Let’s start by defining the concept.
You might not know what modularity means, or what a modular architecture is. You might have a vague idea of what it represents, but no concrete example in mind. That’s okay, this is what this chapter is for.
This chapter will take you from knowing nothing about modularity to having a clear idea of what it is and how it can be of use to you.
We believe that in order to understand something, you need to understand its origin. The word ‘module’ originates from the Latin word modulus, which means ‘small measure’. By extension, ‘modular’ means ‘composed of interchangeable units’. The antonym of ‘modular’ is ‘monolithic’, which originates from the Greek word monolithos and means ‘made of a single large stone’. Both these terms will be used throughout the book, so it is a good idea to keep them in mind.
As you have probably worked out, something modular is built from a set of smaller, interchangeable pieces. On the other hand, something monolithic is built from one piece. For example, a computer is a modular object. It is composed of various pieces, such as the CPU, GPU, RAM and so on, that together make up the computer. Most components in a computer can be changed, one at a time, without impacting its normal function. When choosing parts for a computer, the main thing to pay attention to is that the parts work together. They need to be able to talk to each other through common interfaces. This is just one example of modularity in the real world.
Now that we’ve established that modularity is all around us, let’s see how it fits in the programming world.
Let’s focus on programming now, since this is why you’re here.
What is modularity in programming?
Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.
Conceptually, modules represent a separation of concerns, and improve maintainability by enforcing logical boundaries between components. Therefore, modularity is all about isolating the functionalities of your application into independent and interchangeable components.
But what does this mean, exactly? The best way to understand this is with an example, and what better example than the Ruby on Rails framework itself! Ruby on Rails used to be monolithic, but all that changed with Rails 3, after it merged with Merb. It was then that Rails became truly modular!
Rails is now composed of a set of modules:
You will normally use all of the Rails modules in a standard Ruby on Rails application, but you could also build a Ruby program with just
Active Record, which would allow you to talk with all kinds of databases. As you can guess from the names, each module in the Rails framework encapsulates a specific feature. For example,
Active Record contains everything you need to map Ruby classes to database tables.
Rails modules are, obviously, highly reusable since they lay the groundwork for any web application you might want to build. What we will learn in this book is a way to build Ruby on Rails applications on top of these modules by using the same principles: Re-usability and Functionality Encapsulation.
As we have already mentioned, modularity comes with 2 major advantages: the reusability of components, and the encapsulation of features into independent chunks of code, called modules. There are, in fact, more advantages!
The fact that each module can be independent (even though one module can be built on top of another), makes the coordination and cooperation of different teams much easier. If two teams are building 2 completely different features on top of a shared core module, even without communication, there won’t be a lot of code conflicts. This is because they are effectively working on 2 distinct projects.
Let us assume that you are working for a company that develops complex web applications. This company’s applications will always require users, authentication, and authorization. Why not build these once and re-use them in all applications? You could build a Core module which will handle the users’ login and actions in the application. Once it is completed, you can simply reuse the module in every future web application produced by your company, simply by adapting the layout.
Finally, we need to talk about tests. Automated testing is an important part of software creation, whether it is for the web, desktop or mobile. Since features are encapsulated, you can easily write tests that run in isolation. You can also add tests at the top level of your application to ensure that everything is working well together. It’s just like the way libraries are tested to be sure that what they provide is working. You then test the code where you use those libraries, to be sure you are getting the behavior you want.
Just like everything in life, modularity comes with some drawbacks.
One of the main drawbacks of modular applications is that it can be quite time-consuming. You are not dealing with one application and one repository, but with a set of repositories, each containing the source code for a specific functionality. Depending on the technology used, you will have to update the module, test it, push the source code, then link it to the main application, retest it and then push it again. Now, imagine if you have 3, 4 or more modules to update! That’s a longer process than simply making the change and pushing it live, but the benefits are totally worth the time!
Finally, since we will have a lot of different mini-projects, we need to keep track of their versions; which version is currently used in production, which version is in staging, which versions are ready for testing, etc. A convenient method is a simple shared spreadsheet, that allows you to see which version is where and is easy enough to update.
As you can see, modularity comes with a few difficulties that you will need to deal with if you want to use it in an effective way.
Before delving further into modular web applications built with Ruby on Rails, we would like to talk about a few cases where a modular approach would be beneficial, and when you should simply avoid it.
A good example of when to use the modular approach, is the one we spoke of earlier: if you are a web development company, or a freelancer, and you would like to reuse code between clients. You have probably built a lot of web applications, with a lot of common features. These might include a way for people to create accounts, log in, access some parts of the application, and so on, and so forth. You will also often want an admin panel to administer the application. Then you will probably have some custom code to add for each client, depending on their requirements. By reusing the existing modules you have built, you will have saved a lot of time. Now imagine the time you could save if you do this for 10 or 100 projects!
Another good case for modularity is a startup creating some kind of generic application with a layer of configuration. This might sound a bit abstract, so here is an example of such an application: the Stack Exchange network. If you’re looking to build something similar to Stack Exchange, then modularity is your best friend. You would probably have a set of modules present in every application in your network, and then you’d have some specific modules added on top of those to customize the application to a specific niche. Maybe for one application you want a rating system, for another one you want to have commentable questions and answers. All this can be achieved by building modular applications.
You may have heard about Spree Commerce. Spree is a complete open source e-commerce solution, built with Ruby on Rails. It is completely modular and is composed of 6 modules. Spree was one of Thibault’s main points of reference when starting with modular applications, and would like to commend them for the great work that they did. If you’re looking for an e-commerce solution, take a look at what they offer. It’s really good!
There are some times when a modular approach is not the best way forward. The first situation that comes to mind is when you’re starting off. Modularity is more of an Intermediate to Advanced architectural concept, and if you’re a beginner in Rails (or any framework of your choice, for that matter), then we highly recommend that you start with a monolithic application. This will help you understand the ins-and-outs of Rails while understanding what can be modularised. Of course, we’re not saying that you throw all the modularity principles out the window, but you can implement them slowly; build something functional first, see what can be reused and then make those parts modular as the project starts to grow, or as you see other projects start using the same functionality.
Another situation, where one should stick to a monolithic application, is when you’re building a small project, you know it will remain small, and speed of maintainability is more important. We discussed earlier that modularity is time consuming (even though we believe it’s worth the effort), so for small applications we recommend sticking to a monolithic architecture. That being said, we can’t think of an example where this is the case, because most applications require a user functionality at the very least, and that is one of the most obvious places you can implement modularity.
Finally, a monolithic application is recommended when developing an MVP (Minimum Viable Product) or a prototype. An MVP, or a prototype, is not something that is meant to be kept; it is meant to confirm that the direction you’re taking is feasible, and that your end users (or clients) are happy with what you will develop for them (emphasis on will). In this case, speed is of the essence (and often the functionality is not implemented properly - it’s just enough to show what the application will do) so you develop the application in the quickest possible manner (i.e. not modular).
With this book, you will learn how to build modular web applications with Ruby on Rails. We will help you build a fully modular application, but you don’t have to go to that extent in your application if you don’t want or need to. Hybrid applications are also great. In a hybrid application, the idea is to use a few modules and build a standard Rails application with them. We will talk more about this approach in the next chapter, in the section about modular architectures.