Friday, August 19, 2016

Start with Microservice (in mind) - I think Martin Fowler is wrong

Martin Fowler says: “Don't even consider Microservice unless you have a system that's too complex to manage as a monolith.” The reason for his caution is that Microservice is not a free lunch (nothing in life that is worthy is free): there is a great overhead in implementing Microservice. 

He shows the overhead in this diagram:


So where does the overhead lie? I like this diagram from, which shows that the Miroservice architecture involves much more than just application design: 


Underneath the application layer, there are the application infrastructure layer and the infrastructure layer. In today’s technology, the application infrastructure layer usually involves some highly robust message broker, logging gathering and analysis tools etc; while the infrastructure layer usually involves some service registry and discovery, docker orchestrating tools etc; on the application layer, you have to consider how all the services can behave nicely together, you have to consider API compatibility, failure handling, eventual consistency etc. 

So not only Microservice is not a free lunch, it is quite expensive!

Martin Fowler is right to caution you about Microservice, but I think he is wrong in saying that you should start with monolith. There are great benefits in starting with Microservice in mind – even if you are building a monolithic application. 

I got this awakening when I tried to dissect one of the systems I have worked on. I first listed its features, and picked one to practice. I thought it wouldn’t be too hard because it has a very clear functionary boundary, but pretty soon I found out it has a lot hidden dependencies with other functions of the system. 

In an aging system, hidden dependencies and relationships are hard to find. We thought we were building a clearly layered beautiful system:


We thought we have walls along each layer and around each component. But in reality, because everything is in the same code base and in the same DB, it is so easy to break the walls and even tunnel underneath the walls. Sometimes you do this without even a second thought especially when you saw there were already holes in the wall. You ended up with this:


This is very bad: business logic is scattered in the code and in the database models. 

I wanted to break out moduleA as a Microservice, and discovered its hidden dependencies through discussing with my colleagues and digging into the database models. In the process, often times, discussions like the following sprung up:  

“Why did we design this model like this?”

“Probably to provide the maximum flexibility.”

“Do we have any customers using this function in this way?”

“Probably not many, but maybe a few…”

“So we went to so much trouble just for maybe a few…”

If we had started with Microservice in mind, we would have setup walls around the bounded context. We might be building a monolith, but comparing with a monolith without having Microservice in mind, the walls will be guarded more carefully because we have the idea or hope that one day we might break things apart into Microservices.  


The conversation, in this situation, might be like this:

“We need this feature.”

“This feature requires communicating across walls, it is expensive. Do you really need it?”

“I didn’t know it was so expensive. We need to think about this carefully.” 

Having visible walls will force us to be economic, it will force us to weigh benefits and costs. It doesn’t mean that we can’t open holes or create tunnels underneath to work around the walls – even in a Microservice architecture, we can still make a mess, at the end of the day, it is our skills that count. But having Microservice in mind force us to do deliberate thinking and make decisions explicit. 

The moduleA in my system has the following data models:

It has this structure because in many of its tables, either “flexibility” is reserved for some unknown future usage or because other functions tried to piggyback on those tables (e.g. adding some fields into the tables, the new fields belong to different domain models than the tables). Applying DDD, moduleA’s core can be structured as:


Of course, I am benefited by 100% hindsight. But I believe if there is one single bullet, it is: start with simple, evolve it into complexity after it is proven.  


  1. Thanks for writing this. I believe Fowler's point was not that we should ignore dependencies and just write tightly coupled code to start with, but rather that we should start with a single code base and discover through constant refactoring what/where the natural bounded contexts are before breaking up the solution into microservices. This does require experienced developers, or at least an experienced architect to review the code, because its easy to end up with a tightly coupled monster. However this is true whatever you do.

    In your "microservices-first" approach, there's a danger that the service boundaries that you select upfront may not end up being the most logical bounded contexts once you've gained the learning that comes from operation in the real world, and the experience of dealing with iterative business-driven changes.

    Refactoring the microservice ecosystem is always going to be harder than refactoring within a single code base, therefore Fowler suggests we start with a monolithic code base in order to discover the natural boundaries before we lock those in to less fluid architectural components via microservcies.

    1. Thanks for your comment. I agree that it requires experienced developers/architects to do a good design -- and that is true whatever you do.

      My idea is to have "microservice-first in mind". What I have found out is that to have walls around models can act as design crutches, the walls remind people to not come across boundaries. With one code base, one database, it is so easy to trespass -- that is the example I mentioned in my blog, which has ended up as being database-drive, with a single table containing different business models. If there were these mental walls, maybe things wouldn't have deteriorate so much so quickly.

      I also think it is easy to combine things together than to break things up. Looking at my system, I doubt refactor will be easy or even possible.