Microservices architecture has revolutionised how we build software, offering significant advantages such as:
- Better scalability
- Technology flexibility
- Fault isolation
- Independent deployments
These benefits stem from the clear, physical boundaries between different domains, boosting productivity. However, this approach comes with trade-offs, often sacrificing:
- Simplicity
- Consistency
- Performance
A classic overview of monolith architecture vs microservices
What if you could start a project with the benefits of a monolith and well-defined domain boundaries, then evolve into microservices when the time is right? This is the promise of modular monolith architecture.
What is a modular monolith?
A modular monolith, also known as a modulith, is a software architecture style where the application is developed and deployed as a monolith but is internally divided into distinct, loosely coupled modules.
Each module has well-defined boundaries and responsibilities, allowing for separation of concerns, easier maintenance, and independent development within the monolith.
These modules could later evolve into full-blown microservices.
Overview of modular monolith architecture
Advantages of starting with a modular monolith
Modular monolith architecture provides some key benefits over microservices:
Simplicity in Development Starting with a modular monolith means developing a single codebase that can be tested comprehensively. This simplicity can significantly streamline the initial stages of development.
Well-Defined Yet Flexible Boundaries Modular monoliths, like microservices, emphasize well-defined boundaries between modules. However, the single codebase offers greater flexibility in evolving these boundaries as teams gain deeper insights into their domain.
Enhanced Performance and Consistency In the early stages of a project, business concerns often take precedence over technical concerns like performance optimization or handling eventual consistency. A modular monolith allows you to focus on business needs first, addressing technical challenges as the project matures.
Flexibility in Module Evolution One of the key advantages of a modular monolith is its flexibility. Unlike microservices, where boundaries are rigid, a modular monolith allows for easier refactoring of module boundaries as your understanding of the domain evolves. This flexibility extends to managing dependencies between modules, making it easier to add or remove functionality as needed.
How to build a modular monolith?
- Define Clear Module Boundaries
Start by identifying and defining the core domains and functionalities of your application. Each module should
encapsulate a distinct area of responsibility. Use domain-driven design (DDD) principles to ensure that these
boundaries align with the business logic. - Implement Strong Encapsulation
Ensure that each module has well-defined interfaces and internal implementation details that are hidden from other
modules. This helps maintain separation of concerns and minimizes the risk of unintended interactions between
modules. - Separate Data at the Schema Level
Distribute database tables across modules, with each module having its own schema. This practice strengthens module
boundaries and prepares for an easier transition to microservices by maintaining data isolation. - Maintain a Single Codebase
Keep all modules within a single codebase initially. This simplifies development, testing, and deployment processes. - Treat Each Module as an Independent Application
Organize your source code so that each module is a separate folder representing a domain. Within each module, use the
same architecture you would for an independent application, such as layered architecture or ports and adapters.
Tip: It’s normal to have some shared code between modules. Try to limit shared code to infrastructure logic and avoid
sharing business logic. - Test Between Edges of Modules
Test each module independently and mock interactions with other modules. This simplifies your testing efforts.
When to choose a modular monolith in new projects?
When starting a new project, a modular monolith can be an excellent choice, depending on several factors:
Uncertain Domain Boundaries
If your domain boundaries are not yet fully defined, a modular monolith offers the flexibility to adjust as your understanding grows.
Team Capacity
A smaller or less experienced team may benefit from the simplicity and reduced overhead of managing a single codebase.
Gradual Scaling
If your immediate scaling needs are modest, a modular monolith allows you to focus on delivering business value without the complexity of a microservices architecture.
When it is time to move into microservices?
A modular monolith architecture can evolve into microservices when the time is right. Here are some factors that can lead in that direction.
Reaching Technical Limitations
A modular monolith is, at the end, a monolith, and some factors such as scalability and deployment time can only be optimized up to a certain point. When these limitations start to affect growth, it may be time to consider microservices.
Heterogeneous Requirements
As the application evolves, different parts may require distinct technical foundations, such as different databases optimized for specific tasks or programming languages suited for high-performance operations. Microservices are more suitable for these diverse needs.
Growing Team Size A single codebase can become unmanageable as team size increases. Beyond a certain threshold, the benefits of individual services developed by independent teams outweigh the simplicity of a single codebase.
Conclusion
Choosing the right architecture is critical for the long-term success of any software project. Starting with a modular monolith can provide a balanced approach, leveraging the simplicity and consistency of a monolithic architecture while maintaining the flexibility to transition to microservices when the time is right. This strategy allows for a smoother evolution, accommodating growing complexity, scaling needs, and diverse technical requirements over time. By understanding the principles and advantages of a modular monolith, teams can effectively navigate the initial development stages with confidence and clarity, ensuring robust and maintainable solutions that can evolve with the business.