Modularization in Ruby on Rails (Rails) is a software design approach that breaks down a large application into smaller, self-contained units called modules. These modules have well-defined functionalities and interact with each other in a controlled way.
Here’s why modularization is important for Rails applications:
- Maintainability: As Rails applications grow, a monolithic codebase (everything in one place) becomes difficult to understand and modify. Modularization makes the code easier to navigate and work with, allowing developers to focus on specific parts without needing to understand the entire system.
- Reusability: Well-designed modules can be reused across different parts of the application or even in other Rails projects. This saves development time and reduces code duplication.
- Testability: Smaller, focused modules are easier to test in isolation, leading to more reliable and robust applications.
There are different ways to achieve modularity in Rails:
- Ruby Modules: Built-in Ruby modules allow you to group methods, constants, and other functionalities. These modules can be included in classes to share common behavior.
- Rails Engines: Rails engines are self-contained units that provide specific functionalities like authentication or e-commerce. They can be mounted within a Rails application and act as modular components.
- Gradual Modularization: This approach emphasizes a step-by-step process of breaking down a codebase into smaller modules. It allows for a more flexible approach to modularization, adapting it to the specific needs of the project.
Component-based Challenges
“Components come at a cost. It is the cost of maintaining the additional structure that allows us to reason about how parts of the system are connected. This includes the gemspec, the gemfile, the gem entry point file, the spec helper, and in the case of gems that are also engines so much more. When I started with CBRA I believed (and I still do) that these costs are worth it.”
from the book Gradual Modularization for Ruby and Rails
Architecture Design
Modularization principles are key to building well-structured and scalable Rails applications. Here’s how you can approach it:
Imagine a Rails application for an online store. You can break it down into modules like:
- Products Module: Handles product data management, including CRUD operations, searching, and filtering.
- Orders Module: Responsible for order processing, payment handling, and fulfillment.
- User Management Module: Deals with user registration, authentication, and authorization.
These modules would have their own controllers, models, and views, promoting cleaner code organization and easier maintenance.
By adopting modular architecture principles and using appropriate tools, you can build robust, scalable, and maintainable Ruby on Rails applications.
Another example is building a project with a single api. For simple use cases the module would be sufficient but to be able to really scale and use the api module that supports everything we need, serving in addition to the frontend all the external services that we may have “Although the Ruby on Rails application had a single repository, by its true nature, the application consisted of many different services. It was a real challenge to develop new features because of the way the code of all these services was mixed together.
After the brainstorming phase, the development team decided to use Modular Monolith design for Ruby on Rails API. The benefit of this choice was that all services were decoupled into separate Rails engines (Admin Portal, CMS, Common API, etc.). It was then easy to navigate the project and implement new features, and the design had a clear and easy to implement set of guidelines.”

What Gems we use to build these applications
1 Packwerk
Packwerk is an open-source Ruby gem specifically designed to enforce boundaries and promote modularity in Rails applications. It helps developers structure code into well-defined packages and manage dependencies between them.
Here are some resources to learn more about Packwerk:
- The official Packwerk repository on GitHub: https://github.com/Shopify/packwerk
- An article on Packwerk from Shopify Engineering: Enforcing Modularity in Rails Apps with Packwerk
- A retrospective on Packwerk’s development and lessons learned: A Packwerk Retrospective
- pen_spark
2 Rails Engines
Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a “supercharged” engine, with the Rails::Application class inheriting a lot of its behavior from Rails::Engine.
Rails engines provide a way to isolate code within a Rails application. This isolation helps with modularity, reusability, and avoiding naming conflicts. Here’s how engines achieve isolation:
isolate_namespacemethod: This method, included in theRails::Engineclass, namespaces models, controllers, routes, and other components within the engine's module. This prevents conflicts with similarly named components in the main application.- Namespaced directories: Engine code resides in namespaced directories within the
appdirectory. For example, a blog engine might have its models inapp/models/blog, controllers inapp/controllers/blog, and so on. - API definition: While engines promote isolation, they also need to interact with the main application. For controlled interaction, engines can define an API within an
apidirectory. This API specifies methods or modules accessible from the main application.
Here are some resources for further understanding:
- Rails Guide on Engines: https://guides.rubyonrails.org/
How to build a Modular Rails Application
Here are some good resources
Gradual Modularization for Ruby and RailsBetter Rails apps with packages! Manage the complexities of your domain by elevating your ability to discuss boundaries…leanpub.comNOTES : Based on the book https://leanpub.com/package-based-rails-applications