Microservices Ending up as a Distributed Monolith

by Jan Stenberg on Feb 24, 2016 |

At the recent Microservices Practitioner Summit Facebook engineer Ben Christensen talked about an increasingly common anti-pattern of coupling of distributed systems with binary dependencies.

Christensen describes shared libraries are those that are required to run services, in other words those which are collectively referred to as "the platform". Examples of libraries are Spring, Guava and those commonly used for routing and logging, for example. In the end a system can depend on 100s of libraries that all are needed to run the system. If a service cannot interact within a system unless all these libraries are available, then Christensen calls this a distributed monolith. Essentially all you have done is spread a monolith over the network paying all the cost of a distributed system but losing a lot of the benefits of the microservices architecture. Some of the benefits lost include the characteristic of polyglot, meaning that you loose the possibility of services adopting the best technologies to solve the specific problem, and organizational and technical decoupling, allowing for a team to evolve technically without first having to convince a central authority.

The Don’t Repeat Yourself (DRY) acronym is well-known to most, if not all, developers. With business logic in shared code the ability to deploy changes in isolation is reduced since it affects all services using that code. Christensen emphasizes that shared code is perfectly fine within a service boundary but when it leaks outside that’s a potential form of coupling. He refers to Sam Newman and his book Building Microservices where Newman states:

The evils of too much coupling between services are far worse than the problems caused by code duplication

The alternative for Christensen is contracts and protocols, services should hide all their implementation details only exposing data contracts and network protocols. Without any dependency on service implementation a consumer can use any technology and language, and evolve at its own pace noticing that this is how Internet works. He notes though that there are legitimate needs for standardization in areas like logging, distributed tracing, routing, etc., but this should be enabled using independent libraries that a consumer can choose whether to use or not.

Christensen believes the reason for these mistakes occuring so often is ease; we know how to use shared libraries and we too often optimize for the short-term since it feels more productive. He notes though that delaying the cost of decoupling is very high and that we already know the solution, it takes a bit of extra thought and effort to put the tools in place from the beginning but when they are in place they are straightforward to use. He therefore recommends looking beyond the short-term ease, avoiding binary coupling and instead leveraging contracts and protocols to get the benefits of the microservices architecture.

During the Q&A after his talk he emphasized that he thinks it’s OK to use even a large framework as long as it’s used inside a self-contained service, but not if the architecture of the whole system adopts this large framework because that leads to long-term coupling.

Rate this Article


Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Don't diss the shared stuff so quickly... by Roan Bester

I agree with the article to a large degree; however, there are cases where it is indeed OK to use or share libraries.

Team members do not always work in the same team at my company. So, the application stack looks more or less the same across teams to make it easier to share knowledge and be portable (go to another team).

Sometimes, platform libraries have to be shared due to the nature of the platform. For example, unless you're using e.g. Docker (you therefore run on a traditional JEE app server) you cannot for example choose to use whatever Java version you like. Items like logging is also built into the platform, so you would be crazy to go and add your own flavor.

That being said, I suppose microservices lend itself to a whole different world than traditional enterprise applications. Unless you can completely box your services, you may be better off with either well-structured/modularized 'monoliths' or accepting the limitations of the hand you're dealt.

I think the root of the evil is something slightly different by Oliver Gierke

It might be me but the talk sort of gives the impression that using libraries is a bad thing per se (Guava, Spring etc.). However I haven't seen any Microservices deployments where these kinds of libraries were really causing deployment monoliths *if they're not leaked into the APIs the services use to communicate with each other*. I really have a a hard time imagining someone building such an API and exposing a Guava or Spring type with it so that it would require downstream clients to also upgrade to a new version of that library in case the service acting as server moves to a new one.

The most common reason for an accidental deployment monolith I've seen is people dumping some JSON over HTTP, calling this REST (which it is not) and not paying attention to make sure they actually use means and technologies to allow them evolving their APIs without breaking clients to make sure they can deploy a new server first and then — in an independent step — can update the clients to the newly introduced functionality. Doing proper REST (using hypermedia etc.) can be tremendously helpful in avoiding that breakage and thus avoiding deployment dependencies. It also works with messing if done properly but REST has a lot of means baked into the concept to achieve that.

Coming back to the topic of Ben's talk, I can sort of relate to the situation where teams were inclined to reuse the Java classes they used to model their REST resources on a client "to not have to duplicate those". This kind of reuse has often lead to deployment dependencies. But again this usually only arises for types that end up in the API, not for fundamental infrastructure libraries that just help build the service. And yes, that needs to be avoided, just he outlines pretty well in the talk.

Re: I think the root of the evil is something slightly different by Oliver Gierke

Adding on that, I'd argue that Swagger is a pretty good example of the wrong incentives. It's URI focussed and makes it easy to generate clients tied to the URIs of a particular service version. If you use that to generate clients, you've been basically trapped by the things the talk outlines not to do: baking key API elements into clients. You're gonna find yourself unable to update the server as some Swagger generated client will break because of that.

Re: I think the root of the evil is something slightly different by Richard Clayton

This ^^^ is the real reason why distributed monolith's exist, not because a team has decided to standardize on a set of tools for building their microservices. If the contracts between the components are platform agnostic, it shouldn't matte what libraries, languages, or platforms where used to build the service. As Oliver said, if you are used platform specific libraries (e.g. Joda Time or an Erlang Date tuple) as the official "date format" in your model, you've made a terrible choice because you have allowed implementation details to leak through your platform agnostic contracts.

However, to extend Oliver's point, most teams are smart enough to not do something as silly as expose platform-specific constructs in their APIs. The real challenge is creating a distributed business model that does not create monoliths. While no one wants to model a "User" entity in each microservice, you may need to because each service will probably have their own requirements of that entity. This is described extensively in Domain Driven Design as a bounded context (

Re: I think the root of the evil is something slightly different by Oliver Gierke

I'd still argue that the usage of JodaTime or the like doesn't create that coupling if you resort to ISO date representation in whatever representation format you're exposing to your clients. If that's the case all services can upgrade their library versions whenever they actually like to.

Good point about Bounded Contexts. However most teams I see these days have pretty much realized that these are required to build Microservices successfully. I guess what needs more emphasis is that sharing code implementing those contexts violates the principle in general. :)

Re: I think the root of the evil is something slightly different by Richard Clayton

Sorry, to clarify, I mean the library representation of a Date in a contract. Obviously using Joda, Moment.js, etc. to return an ISO 8601 representation is totally fine. What I meant was not serializing the platform-specific Date object (somthing goofy like an Erlang timestamp: { {2016, 02, 29 }, { 09, 58, 21}} to JSON for instance: [[2016, 02, 29],[09,58,21]]). Obviously that example is weak. Maybe a better one would be something like a Guava Optional, or forcing all microservices in your architecture to use something like Protobuf.

Re: I think the root of the evil is something slightly different by David Dawson

There's a huge difference between sharing/ re-using a technical library and sharing business logic/ domain objects.

I'd say that protobuf doesn't matter, it's your communication medium, and a good one. The other side of this argument is that, if not protobuf, then what? Http? Congratulations, you've just adopted the semantics of http as your core programming model. Http is a fine protocol, but it's both too flexible, and too restricted in what it can do to form everything your system will need to do. So, it's not generating no coupling, it's making an active choice to couple on certain things, knowing the costs and benefits of doing so. A point that Ben seems to make.

Sharing domains objects will force all of your services to share the same representation of that data internally, and this is where the coupling is really generated, and where problems will occur. Outside of a bounded context, you MUST be able to vary the representation as needed without reference to the original, or you're system will get pretty fragile quickly.

I had an extended rant on this topic a while ago ->

Very cathartic.

Re: I think the root of the evil is something slightly different by Richard Clayton

I mentioned Protobuf to indicate a library/protocol not universally supported by many languages, not necessarily to mean the only way you communicate. And I think I made the same point about bounded contexts.

Re: I think the root of the evil is something slightly different by Adrian Ivan

Client SDK, Yes or No?
The main point is to be able to evolve service API safely, as Oliver pointed out.
There seems to be two schools right now:
- Client SDK, advocated by Adrian Cockroft, Matt Ranney
- Consumer Driven Contracts, Pact, etc

Is there any obvious advantage of one vs the other?

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

9 Discuss
General Feedback
Marketing and all content copyright © 2006-2016 C4Media Inc. hosted at Contegix, the best ISP we've ever worked with.
Privacy policy