Tips on Designing a Good Framework, Library, or Plugin — Part 2 — Architecture

Posted in engineering

After explaining why a bad documentation could ruin a good framework on my previous post. I will explain about how to architect your framework properly that people can use your framework easily.

Architecture

Write Usage Code First

Before I am writing a framework, I would write an example code on how to use the framework first. Example, when I was designing ParticleDB, a fluent database library for PHP, I didn’t write any of my library code until I covers all example.

By writing the example code first, you can focus on usability of your framework first instead of the functionalities. User would not want to use your framework no matter how functional it is, if they can not use it easily.

Your code doesn’t have to be fluent as above, but most people enjoy using fluent API because it is more intuitive to them. But make sure that it is clear what methods that they can chain. ParticleDB returns a concrete implementation of a class on each methods, so all of the methods and parameters 100% covered by autocomplete.

I abandoned ParticleDB in favor of using Laravel’s Eloquent directly, it is no longer available for use.

Example you wanted to write a library for manipulating images in a non-fluent way, just write the example code first.

Now you know how you will structure your code to make this example possible. Writing example code is like prototyping your framework design, it is fast and easy to do and give you the broad overview. Think of it as mockup for framework design.

Follow the Standard

Again, standard is there to make us learn once, and can apply our knowledge to everything under that standard. When you are writing code in Java example, you are expected to write methods with camelCase, and when you are writing class you have to write with WordCase. These standards make it easy for people to use your framework.

Example in NodeJS, the internal library is usually defined in lowercase. While some external library used lowercase, or word case, and some class expect you to use new for initialization, some can just use the class name (correct me if I am wrong, I did not use NodeJS extensively, but as per my personal experience, this is what I encountered). Everything is in chaos, but Bran said chaos is a ladder :).

Make it Extensible

Laravel is one of the most extensible framework I ever used. I was encountered with this case where I have to use another encryption for the user authentication. So I extended the Laravel auth provider and managed to create my own authentication, and can be used widely in the Laravel ecosystem.

Be cautious though, when you want to make your framework extensible, make sure that the defaults already work seamlessly and covers wide usage. Options and customization is like a fire, too many options and customization could burn the user minds as they are faced with overwhelming options and make it hard for them to decide. See why having too many choices is bad here.

By making it extensible, your code usually will support dependency injection. This mean that users will be able to plug and replace any components as long they followed your framework architecture (overriding methods, implementing interfaces, etc.).

Use Proper Namespace

It is reasonable to put HTTP related code into something like myframework.network.http. Just because some codes depends on each other, it does not mean that you have to put it on the same package.

Example your HTTP related code utilize an SSL related code, then you put your SSL code inside myframework.network.http, it will make it very hard for the user of your framework that does not want to use HTTP, but want to use SSL. Instead, you can put the SSL into myframework.network.security namespace as it is more intuitive for your user.

Your framework user could still read the documentation to find your SSL related code, but by properly structuring your namespace, it helps your user save times from reading documentation by using intuitive namespace structure.

Implementing this is really hard though in practice, when you first designed your framework and structured the namespace as best as possible, but then you noticed that some of your user still unable to find the correct namespace and they filed some issue, you solved this issue and told them they can find the namespace at myframework.network.http.websocket. But then another issue asked the same question, you answered it again, but another issue raised, say, 100 issues asking the same questions. Then you know that something is wrong with your namespacing. You are left with two options now, put the namespace in a FAQs or the main documentation, or move and restructure your namespace, the latter would break existing users code as their code can not use the old namespace anymore.

This is not very important nowadays, because IDE is smart and can help the user to find the correct namespace.

Manage Visibility Properly

If your platform or programming languages supports managing members visibility (private, protected, public), use it properly. Some people did actually make everything public, and it really confuses the user when their IDE autocomplete give them bunches of members that only used internally.

Most object oriented language supports this feature, and some IDE did helps you as the framework designer as they usually tells that some members could be defined as private or protected.

Conclusion

Writing frameworks require practice, don’t worry about it too much. You will learn how to improve your framework everyday. Architecture is one of the critical criteria of a framework that affects the opinion of your user.

Again, this is my personal opinions and based on my experience writing and using frameworks. Feel free to give me feedback!

By Aditya Purwa on October 7, 2017.