Recognising Software Monoliths: 7 key types


A monolith in software architecture a term used to describe some service that is large, complex and shared across different business functionalities. Changing any aspect of this can be daunting not just from an engineering standpoint but from a testing, delivery and release standpoint as well

As teams look to decompose monolithic software into domain oriented, nimble, maintainable, changeable units – a key tool is to recognise the type of monolith they are dealing with. In this post, we explore 7 different types of monolithic software. These are based on my personal experience as an integration and services engineer and architect building distributed systems

It is a bit of a read, so grab some coffee!

Monolithic Service Types

The 7 types of monoliths observed are:

  1. Endpoint: Single shared endpoint
  2. Repository: Single shared repository
  3. Component: Single shared component
  4. Runtime: Single runtime
  5. Database: Single shared database (schema) for different service implementations for multiple contexts leading different teams and services depending on the same model
  6. Core System: Single core system with services for multiple contexts leading different teams consuming different or same services from a common system
  7. Distributed: Single library with logic for different contexts depended on by different services

Let us explore each in detail below

Endpoint Monolith

The endpoint monolith is when single endpoint handles multiple contexts. For example, a CRUD-style service with a SOAP endpoint or an anaemic REST API with HTTP methods (GET, PUT, POST, DELETE) acting on a single endpoint (e.g. /api/orders)

The key thing to notice here is that the endpoint is used for different business contexts and provides a large canonical schema with a super-set of attributes for all contexts. While a mashup of attributes presents its own problems with a bulky model, the key aspect of what makes this hard to change is the complexity in testing and collaboration

How: The endpoint monolith happens either due to an architectural style (SOA-style architecture) or gradually over time where a an endpoint for a specific context is expanded (attributes added) to show service reuse

Remediation: While the first team building the endpoint may follow a model-driven architecture with context specific resources, it is up to the future maintainers to ensure that the endpoint remains specific to its domain. Applying DDD practices vs pure integration reuse is recommended

Single endpoint servicing different contexts

Repository Monolith

A repository monolith as the name suggests is a single code repository with many different service implementations. These implementation can span multiple business contexts and teams

The key challenge with a repository monolith is how engineering teams collaborate and manage change especially when working in parallel streams of work

How: The repository monolith can be a conscious engineering decision or a result of a common source code that over time has modules or sections specific to different business contexts ( models, interfaces, services)

Remediation: Evaluating the benefits of extending vs creating a new repository is key. While we look to avoid duplication and maximize reuse, we need to ask if there are models, logic or functionality in the repository we are extending that is not a part of our domain

Single repository with different contexts

Component Monolith

A monolithic component contains implementation for different business contexts within the same service component. This is similar to the repository monolith where different features from different business contexts are part of a common source code. The key difference is that the source code is compiled into a single component (the repository monolith could bake different deployable components)

This type of architecture is an improvement over the common endpoint by providing a common root for the service with sub-contexts for specific implementations. For example, instead of a single /api/orders endpoint we handle different types with /api/orders/books, /api/orders/beverage, /api/orders/electronics

The key challenge with building a single component emerges when different teams need to change the different endpoints and in the runtime coupling it introduces when the component is deployed

How: We see the component monolith emerge when teams expand an existing domain service component for context it was not originally intended for. This may be due to speed up delivery through reuse of the component shell or underlying technical adapters/classes or even to avoid having to create a new deployment pipeline etc

The component monolith can also emerge in technologies where the deployment unit creates additional cost to operate. For example in platforms where vendors charge licensing costs per core and when cores are tied to components this can drive a trend to maximise what goes into the component

Remediation: Thinking about the components as domain services with specific business-aligned objectives is key. Avoiding this pattern is hard when the considerations are short-term and focus on local constraints such as operational costs

Thinking about long-term constrains such as maintenance, impact of runtime coupling etc are key. For example, consider the scenario when one implementation (e.g. /api/books) becomes resource intensive and causes the entire component to fail (shutdown or return 504s) would that be acceptable to the other business teams?

Single component with different contextual services

Runtime Monolith

A runtime monolith is a process with one or more deployable units within it. We see this with service-bus vendor technologies, especially on-premise ones where a single runtime process EAR or WAR would have multiple projects deployed to it (as zip, jar etc)

As the name suggests, this introduces coupling in independent components through the act of deploying to a common runtimes process. All process resources are shared, resulting in a lower operational cost but higher operational impact when one or more resources become constrained

How: A runtime monolith emerges either due to the constraints of the underlying platform (e.g. a single service-bus EAR) or due to deliberate choice to operate all services in a common runtime to reduce licensing costs

Remediation: A common runtime might suit a small team and budget to kick-off a services team but is not recommended as the number of services, contexts and demands grow due to the unpredictable use of resources and impact. Most teams work to scale horizontally with the same set of components still deployed to the same runtime, however if there is an opportunity to operate them independently as individually deployable units then that is the recommended approach

Single common runtime with different components

Database Monolith

A monolithic database is a single shared model across various independent components. This type of monolith hides the coupling on the surface unlike the previous examples, i.e. we see independent teams able to make changes to their services easily. However the key challenge with this pattern emerges when an existing shared database schema needs to change

How: A database monolith emerges when teams have direct access to a database and implement commands/queries on a particular schema without realising if this is shared across with other teams and contexts. Often openly available datasource connectors or even services exposing SQL-like construct (OData) can introduce accidental coupling across different domains and contexts

Remediation: Encapsulating a database with an API and events for change data capture can help decouple. If multiple teams are already tied to a single database then there are database monolith decomposition techniques which can help

Core System Monolith

A monolithic core system is a legacy system that is used in various contexts and is depended-on by various services for different business contexts. While key to the business operation of the enterprise, the core system becomes the a monolith in its own right with a slow pace of chance and hindering the release of new features as different teams depend on it to deliver new interfaces or changes. As the core systems become costly to customise and change over time due to use in multiple contexts and specialisation, the impact is felt outwards

How: A core system monolith evolves over time as a COTs product is used in multiple contexts. For example, core insurance system used in Home, Life, Motor etc. As various other systems are integrated to the core system, the reuse creates complexity regardless of the architectural style (point-to-point, service oriented, domain oriented etc) as the model in the back-end system services different contexts

Remediation: Working around a core system requires domain centric vision at an enterprise level especially within the architecture team. The tradeoff between a standard COTs product vs flexibility comes to the fore

Core System monolith

Distributed Monolith

A distributed monolith, unlike the earlier patterns, is spread across the components through a common library or shared logic. Essentially all the worse things about monolithic architecture and distributed architecture are at play as there are multiple component to observe and track while there is a hidden underlying monolith

How: A common library shared across components starts to contain context specific logic and is embedded within components. For example, a library to read from a database with a handling logic is reused across components and as teams add their context specific logic to it – the library expands

Remediation: Avoiding business logic in common libraries and keeping them context free

Summary

Monolithic software can couple contexts making software delivery slower, maintenance and operation harder. We saw 7 types of monolithic service patterns and how they are accidentally introduced through common software delivery processes that focus on systems and tactical optimisation vs business contexts and strategic value

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s