Modular monolithic architecture - Part 1

In the former lessons, we learned about monolithic architecture, microservices, the use cases that fit these architectures, the big ball of mud and layered architecture. 

In this one, I'll discuss the modular monolithic architecture, which lies somewhere in the middle of the monolith and the microservices architecture. 

We understand that no technology is perfect; all have their pros and cons. Microservices architecture makes our architecture loosely coupled but, at the same time, adds additional maintenance and management overhead of a distributed infrastructure. 

Now, if our primary goal in switching to a microservice architecture is to avoid the big ball of mud, you might want to consider the modular monolith architecture that has modules split based on the business features as opposed to them being coded together in a single module tightly coupled with each other. 

Let's understand what is modular monolithic architecture.

What is modular monolithic architecture?

A modular monolithic architecture is a monolith designed in a modular fashion having business features coded in loosely coupled modules with their own layers (controller, service, DAO, etc.) interacting synchronously or asynchronously.

Illustration 1.41: Modular monolithic architecture

These loosely coupled modules can also connect to different databases as opposed to having just one database, typically in a monolithic architecture.

These modules are designed based on business functionalities, as you can see in the diagram above. The inventory is implemented in a separate module, orders and payments have their own modules and so on. 

Why split the code and design modules based on business features? Why not code all the features in a single module with layered architecture keeping things simple?

Why use modular monolithic architecture?

Often different business features coded in a single module in a monolithic architecture result in a big ball of mud that is hard to manage and extend. To tackle the issue, devs largely transition to a microservice architecture where every feature has one or more dedicated microservices powering it. 

The modular monolithic architecture makes working with code easier, helping us write loosely coupled modules in monolithic architecture without having to bear the overhead of managing microservice architecture. 

A modular monolithic architecture facilitates code reusability, ease of maintenance and extendability, better code comprehension, observability, low code complexity and ease of testing, similar to what the microservices architecture offers.

However, we have to bear in mind that even though the modules are separated like the microservices architecture, they cannot be deployed independently since they are separated logically, not physically. If we require physical separation, we must move to microservices architecture.

Understanding modularity and domain-driven design

Modular monolith architecture is an implementation of the domain-driven software design methodology that encourages having a code structure aligned with the business domain, similar to our app above, where the modules are split based on the app features such as inventory, order, payment, user membership, etc. 

This methodology facilitates better isolation and encapsulation based on the domain features. 

Following domain-driven design, in enterprise projects, domain experts and the technical folks (architects, developers) work in conjunction to model their system, mapping the domain to code.

They try to define bounded contexts and then convert those contexts into modules. Bounded contexts are logical boundaries in a domain with similar rules. For instance, in a food delivery app, inventory management will be a bounded context, user management will be another bounded context and so on. The bounded contexts will have things consistent with a certain domain feature.

Once the modules are coded, they have dependencies on each other. For instance, the inventory module would need to communicate with the order module and the order module would need to communicate with the payment module, etc. to complete a user purchase flow. How do they do that?

Let's understand this in the lesson up next.

Complete and Continue