Monolith -> Services: Theory & Practice

How can we get from a monolith to micro-services quickly?

Can’t answer that question. First, “quickly” is right out the window. You didn’t make this mess in a month; you’re not going to fix it in a month. Second, you want some benefit you aren’t currently getting that you expect from micro-services. What is that benefit? Micro-services aren’t the point.

Having rejected the question, I will go ahead and answer it. Before I can explain why a quick change to micro-services is impossible and, if forced, dangerous, here are the basic forces acting on software design. These were elucidated in the mid-70s by Yourdon & Constantine in Structured Design and haven’t changed.

Structured Design, Yourdon & Constantine

Their argument goes like this:

(This skips loads of interesting stuff, but I’m just trying to set up the argument for why rapid decomposition of a monolith into micro-services is counter-productive.)

Managing Coupling

Note I don’t say, “Eliminating coupling.” Decoupling comes with its own costs, both the cost of the decoupling itself and the future costs of unanticipated changes. The more perfectly a design is adapted to one set of changes, the more likely it is to be blind-sided by novel changes. And so we have the classic tradeoff curve:

You manage coupling one of two ways:

  • Eliminate coupling. A client and server with hard-coded read() and write() functions are coupled with respect to protocol changes. Change a write() and you’ll have to change the read(). Introduce an interface definition language, though, and you can add to the protocol in one place and have the change propagate automatically to read() and write().
  • Reduce coupling’s scope. If changing one element implies changing ten others, then it’s better if those elements are together than if they are scattered all over the system —less to navigate, less to examine, less to test. The number of elements to change is the same, but the cost per change is smaller. (This is also known as the “manure in one pile” principle, or less-aromatically “cohesion”.)

Not Quickly

Two factors prevent de-coupling quickly:

  • Skill
  • Knowledge

I see useful folklore around software design — keep your models separate from your views & controllers, for example — but little explicit acknowledging or managing coupling. Once you put on Coupling Glasses you won’t be able to unsee coupling, but the transition takes a while. Identify coupling, look for Emmenthal changes (changes with lots of holes between the cheese), increase cohesion, decrease cohesion in one direction then increase it in another, play with design.

Once you can design in the abstract, apply those skills to your system. Where should your system’s internal boundaries be? It will take a while & some experiments to discover them. Best to sketch the boundaries lightly, then draw them more firmly, before cutting parts out. Sketching mistakes are reversible. Service extraction is not exactly forever, but it’s expensive to reverse when you discover two services are coupled.

Good News

How can you quickly decompose a monolith into micro-services? You can’t because you need to learn how and you need to learn what. The good news is that you don’t have to quickly decompose a monolith into micro-services to quickly get some of the benefits you seek.

Change clusters. If you tidy the streets you walk, and you mostly walk the same streets, then a little tidying will have you mostly walking tidy streets. Increase cohesion a little before you make changes. Eliminate coupling a little before you make changes. Pretty soon change will accelerate.

Kent is a long-time programmer who also sings, plays guitar, plays poker, and makes cheese. He works at Gusto, the small business people platform.