DEV Community 👩‍💻👨‍💻

Ahmet Küçükoğlu
Ahmet Küçükoğlu

Posted on • Originally published at ahmetkucukoglu.com

What is Modular Monolith?

This article was originally published at: https://www.ahmetkucukoglu.com/en/what-is-modular-monolith

Traditional Monolith

Firstly, let's talk about Traditional Monolith approach. This approach focuses on layers. It includes three layers, UI, Business and Data. All features in a project are vertically separated into these layers. Among those three layers, the business layer is the one that contains business logics of all features. Each feature knows business logic of other features, which is a fact we call tightly coupled.

Traditional Monolith

Modular Monolith

The main focus of Modular Monolith is to separate modules. Each module has its own layers ( Domain, Infrastructure and API etc.). Thus, they can use different database solutions. On the other hand, modules don’t share their own business logics with each other. They can communicate with each other with sync or async approaches. These approaches are called loosely coupled.

Modular Monolith

Modular Monolith has a single binary. Therefore, apps that implement Modular Monolith can’t be scaled horizontally. Also modules are separated logically, not physically. So Modular Monolith doesn’t have a physically distributed structure. If we want to physically separate it, we have to implement the microservice approach.

Physical and Logical Architectures

Traditional Monolith isn’t a bad choice but it is likely to turn into a big ball of mud due to its structure. Its transition to microservice is also very difficult. On the other hand, Modular Monolith can easily migrate to microservice. Microservice is a good choice if your application will be published at internet scale. But Modular Monolith is a better option if your application will be published just within an organization.

Communication in Modular Monolith

Let’s consider an ordering system in an e-commerce app. Basic modules in an ordering system are Inventory, Order and Payment. During a buying process, order is received, stock is checked and payment is made. If a product is out of stock or payment hasn’t been made, that order is cancelled. Then how does such a communication occur in Modular Monolith?

There are two approaches (sync, async) for communication. In the sync approach, each module exposes an interface. These interfaces are defined in the shared layers of modules. The inventory module exposes IInventoryService which has the methods of ReserveStock, ReleaseStock. Likewise, the payment module exposes IPaymentService which has the MakePayment method. The order module communicates with other modules by using these interfaces.

Sync Communication

In the async approach, each module raises events. These events are defined in the shared layers of modules. The order module raises the OrderReceived event. The inventory module raises the events of ReserveStock, OutOfStock and ReleaseStock. Likewise, the payment module raises the events of MakePayment, PaymentMade and PaymentFailed. Each module subscribes to related events. So the communication occurs through the message broker.

Async Communication

There are two approaches (choreography, orchestration) in async communication. It doesn’t matter which one is preferred. I preferred the orchestration approach because it is more efficient than the choreography approach for this scenario.

Orchestration

How is the project structure?

Bootstrapper is the entry point of the project. So it is a WebApp.

Each module has its own layers which aren’t standard. You can apply Onion or Hexagonal Architecture.

Shared.Abstractions : It is used by Modules.Core and Modules.Infrastructure. It contains interfaces, abstractions such as DDD, CQRS etc.
Shared : It is used for cross-cutting concern. It also includes implementations of the abstractions.

Ecommerce.Inventory : It is a class library. It contains the controllers of the inventory module. If you intend to use async method for communication, you can add the consumers (ReserveStockConsumer, ReleaseStockConsumer etc.) in Ecommerce.Inventory.
Ecommerce.Inventory.Core : It contains the domain or business logic of the inventory module. If you wish, you can separate Ecommerce.Inventory.Core into two parts, Application and Domain.
Ecommerce.Inventory.Infrastructure : It is where the modules are connected to external services or components such as database, message queue etc.
Ecommerce.Inventory.Shared : It is used to expose some classes (OutOfStock, StockReserved etc.) and allow the other layers to use those classes.

Project Structure

Summary

Using Modular Monolith is a better choice if you don’t want your project become a big ball of mud, and your project doesn’t require internet scale, or if you are likely to convert your project to a microservice architecture later.

You can access the sample projects from my Github address.

GitHub logo ahmetkucukoglu / modular-monolith-async

Ecommerce Modular Monolith App with Async

modular-monolith-async

Ecommerce Modular Monolith App with Async

Run the following command to start the project.

docker-compose up -d

Postman Collection

Run in Postman




GitHub logo ahmetkucukoglu / modular-monolith-sync

Ecommerce Modular Monolith App with Sync

modular-monolith-sync

Ecommerce Modular Monolith App with Sync

Run the following command to start the project.

docker-compose up -d

Postman Collection

Run in Postman




Good luck.

Top comments (0)

🌚 Life is too short to browse without dark mode