Blue octopus tentacle shaped like the DevOps infinity loop, with people on laptops sitting on and around the tentacle.

Continuous Delivery Office Hours Ep.4: Mono, micro, mesco

Steve Fenton
Steve Fenton

After tackling the question of which branching strategy is best, we turn our focus to architecture in this Continuous Delivery Office Hours episode. In particular, we discuss how big your building blocks should be and whether you should opt for a majestic monolith, granular microservices, or something in between.

Traditional monoliths are often described as a big ball of mud or spaghetti code due to the complicated mess of dependencies. When all the code is co-located, it’s common to find a tangled web of paths, with interfaces and facades skipped in favor of direct access to low-level functions and classes. This kind of code is hard to maintain.

Majestic monoliths are well-structured and loosely coupled, with carefully designed dependencies that are sometimes enforced by architectural tools. By making things modular, you get the benefits often associated with microservices, but without the difficulty of finding the code or the runtime complexity of distributed systems.

Microservices go a step further by physically separating parts of the system into independently deployable units. In addition to the architectural benefits, you can get faster build and test run times because you only build and test each service when it changes, which involves much less code. The trade-off is that your codebase becomes more complex, and you have to deal with versioning and issue pinpointing across all the deployed services.

So, how do you choose between these approaches?

Watch the episode

You can watch the episode below, or read on to find some of the key discussion points.

Watch Continuous Delivery Office Hours Ep.4

Architectural decision factors

Many factors influence the decision between monoliths, microservices, and hybrid approaches. One of the most crucial is how your teams are structured and how much autonomy they need. There are different ways to design team structures, like Team Topologies, that make your teams and architecture part of the same conversation.

This is consistent with the inverse Conway maneuver, in which you structure your teams to match your target architecture. This works because Conway’s Law states that organizations design systems that mirror their communication structures. Working at the team level is more effective than creating an architectural diagram, as the structure will naturally yield the design you want.

Having a mismatch between the number of teams and the number of components can add complexity, either because too many teams are working on a single module, or you have created so many modules that there aren’t enough teams to own all the maintenance tasks associated with them. A sensible default is to match the number of teams to the number of components, ensuring sufficient autonomy for each team to work independently without overburdening them with excessive complexity.

The matching of service and team design sits between monolith and microservices, and might be described as “mescoservices” to highlight the balance they strike between the macro level of monoliths and the fine-grained level of microservices.

Another factor that can influence your decision is your deployment model. A managed software-as-a-service offering can use microservices without imposing complexity on its customers. In contrast, a self-hosted software offering may benefit from easier installation, troubleshooting, and upgrades if it uses a monolithic architecture.

Common microservice failure modes

There are several common failure modes to watch out for when moving to a microservice architecture.

Distributed monoliths look like microservices, except they have dependencies that mean you have to deploy services in a specific order. If you can’t deploy independently, you don’t have microservices. Similarly, you often find microservices at the application layer, but all sharing the same database. This prevents independent scaling of high-load services and can cause services to access data directly rather than through the appropriate service.

When you deploy large numbers of microservices, you may need to introduce rules about which services can communicate. Allowing any service to call any other service means managing a complex web of dependencies, and it starts to look a lot like the proverbial big ball of mud. This is often the result of splitting a monolith into microservices, as the old design tends to persist.

Microservices should bring a high level of team independence, allowing teams to make decisions about their own services, persistence, and deployment schedules.

Pulling microservices together

To make microservices successful, you need to establish data ownership and decide what level of data duplication is acceptable to support the business goals. For example, there’s a temptation to store a single address for a customer, but it may be a better idea to store the address immutably against events, like orders. Even if the customer moves house, the address for a past order remains the same.

Domain-driven design provides a method and a language for making decisions across service boundaries. A principal engineer or architect would usually set standards for service boundaries, contracts, and versioning to help keep services loosely coupled and independently deployable.

Fitness test

The best test of your service-based architecture is independent deployability. If each team can deploy its services without cross-team coordination, then your architecture is working. For majestic monoliths, the test is similar; teams should be able to work independently on modules they own. While deployments will be coupled through a single build and deployment pipeline, they should be able to make and commit changes independently.

Happy deployments!

Continuous Delivery Office Hours is a series of conversations about software delivery, with Tony Kelly, Bob Walker, and Steve Fenton.

You can find more episodes on YouTube, Apple Podcasts, and Pocket Casts.

Steve Fenton

Steve Fenton is a Principal DevEx Researcher at Octopus Deploy and a 8-time Microsoft MVP with more than two decades of experience in software delivery.

Related posts