Skip to content

cer/modular-monolith-examples-customers-and-orders

Repository files navigation

Modular monolith example: customers and orders

This application is an example of a modular monolith architectural style.

The application consists of three domain modules

It consists of three domain modules:

  • customers - manages customers

  • orders - manages orders

  • notifications - sends notifications

customers and orders modular monolith

A domain module has a hexagonal architecture

A domain module has a hexagonal architecture:

  • domain - the business logic

  • web - an inbound adapter that implements a REST API

  • persistence - an outbound adapter that implements database access

Domain module collaboration mechanisms

Domains collaborate in two different ways. The first is by one domain invoking another. For example:

  @Transactional
  public Order createOrder(long customerId, Money orderTotal) {
      ...
      creditManagement.reserveCredit(customerId, order.getId(), orderTotal);

The second collaboration mechanism is the Observer pattern - one domain subscribes to events emitted by another domain. For example:

@Service
public class NotificationServiceImpl implements CustomerDomainObserver {

  @PostConstruct
  public void registerCustomerDomainObserver() {
    customerDomainObservers.registerObserver(this);
  }

  @Override
  public void noteCustomerCreated(CustomerInfo customerInfo) {...}

Minimizing build-time coupling is a key design goal

X is build-time coupled to Y if a change to Y requires X to be recompiled and, more importantly, retested. Since fast builds are essential, it’s important to minimize build-time coupling.

This example minimizes build-time coupling in a few different ways:

  • Domain module = multiple Gradle projects

  • Domain modules have a Domain API Gradle sub-project

  • Uses the Interface Segregation Principle (ISP) to define narrower APIs.

Domain module = multiple Gradle projects

To reduce build-time coupling within a domain module, each domain module consists of multiple Gradle sub-projects. Typically, the sub-projects correspond the elements of the hexagonal architecture - domain or adapter. For example, the Customers domain consists of multiple Gradle sub-projects including customers-domain, customers-web, and customers-persistence. An important benefit of this design is that it reduces build-time coupling. A change, for example, to the web adapter doesn’t require the domain or persistence adapter to be recompiled/retested.

Domain modules have a Domain API Gradle sub-project

The Customers and Notifications domain modules - specifically their domain logic - are used by the Orders domain module. In order to minimize build-time coupling, each of those domain modules has a Domain API Gradle sub-project, which defines that module’s API. For example, the Customers domain has a customers-api Gradle sub-project, which contains its API classes.

A domain module’s clients only depend on its Domain API Gradle sub-project. Moreover, its clients are tested using mocks of the API. For example, the Orders domain is tested using a mock of the Customers domain’s API. As a result, a domain module’s implementation can be changed without having to recompile/retest its clients.

Uses the Interface Segregation Principle (ISP) to define narrower APIs.

To further reduce build-time coupling, the Customers domain module uses the Interface Segregation Principle (ISP) to define narrower APIs. It has three Domain Modules API Gradle sub-projects:

  • customers-api - defines CRUD operations

  • customers-api-credit-management - defines operations for managing credit

  • customers-api-observer - for registering observers of the Customers domain

As a result, each client only build-time coupled to those APIs that it’s actually using.

Code Tours

This repository includes a series of Code Tours that explain the design of the application. You can use the code tours in either Visual Studio Code or Github Codespaces.

In Visual Studio Code

  1. Install the Code Tour extension from the Visual Studio Code Marketplace

  2. Use the CodeTour: Start Tour command from the command palette to start the tour

In a Github Codespace

  1. Create the codespace

  2. If necessary, install the Code Tour extension from the Visual Studio Code Marketplace.

  3. Use the CodeTour: Start Tour command from the command palette to start the tour.