I’m a software dev and founder of Hotels.ng and HNG Internship. I also dabble in embedded systems and hardware projects.

Micro-monolith design pattern for software

Abstract Art

Micro-services may be good for scaling, but they introduce a lot of complexity to software. The vast majority of software produced will never need to scale, so all the effort invested in building it as a set of micro-services will be wasted.

The complexity of micro-services comes from having different repositories, with separate deployment (that need to be separated using something like Docker), and having these services having to talk to each other over external interfaces.

The first two points are chore-like complexity, and do not contribute to better software practise, but the last point, even if it introduces some complexity, does force better code.

Forcing coders to separate concerns and design interfaces between them leads to a cleaner code-base and makes bugs and issues easier to find. Separating the user interface from backend services via a json interface also cleans up the code, and makes it more flexible (e.g when used with mobile).

To achieve this, rather than using pure micro-services, an alternative approach I have explored is to have everything in one monolith service, but with each concern separated out into a different file and interface.

So for example, a microservice setup could look like this:

  • {Search Service}
  • {Product Service}
  • {Booking Service}
  • {Admin Service}

All of these are independent and offer Json interfaces which are consumed and served by a central router.

     /- {Search}

[Router] – {Product} _ {Booking} _ {Admin}

A micro-monolith would then be designed differently as a single repo with a single project, that offers a json API:

{ A single Project with

  • Search Endpoints (search.py)
  • Product Endpoints (products.py)
  • Booking Endpoints (booking.py)
  • Admin Endpoints (admin.py)

}

Each of these files has its own external endpoints. They can either directly access components from another file, or they can access them over the external endpoint.

[Router] — [API]

What this does is that the concerns are separated in the code, but the entire codebase can be deployed as a single project. When there is need to scale, the entire codebase is deployed to a new server, but only the parts that are needed are called on that server. For example:

[Router] — [API] __ [API but only Search.py is being used]

In the above case, search has been spun out of the api, and is running on a different server.

Search is communicating with the rest of the API over http, while the other services like booking may be talking directly to products without using the external interface.




Last Modified: May 15, 2022