The Single Key Principle to Determining a Microservice Boundary

Ron Norman emphasizes a single key principle for defining microservice boundaries: ensuring that a microservice's dependencies are contained within its API's request-response cycle. This design philosophy promotes autonomy and reduces co-dependency by advocating for internal management of functionalities and using asynchronous events for external dependencies.

Ron Norman

2/19/20242 min read

So your team has decided to go the microservices route. There are many principles for a microservice architecture, but what is the number one key principle that you must get right to avoid a painful existence later on?

We know that a microservice design must strive to be autonomous, but what does that mean? When it's time to implement, what detailed design guidance should you be following that keeps you and your team on the right track without slipping into the hell of co-dependency?

It's so easy and tempting to start spawning off a new microservice for whatever comes up thinking that you're doing a microservice architecture only to find out at the end that you've just built a more glorified monolith entangled system but a higher level of complication: distributed entanglement vs local entanglement.

The number one question or acid test to ask yourself when deciding whether to include a dependency within the boundary or exclude it into its own separate microservice is this:

Does that dependency fall within the request-response cycle of the call to the API?

If the answer is yes, then you must include that dependency within the boundary of your microservice, and not create it as its own new separate microservice.

If you tell me that it doesn't fit within your bounded-context design then I would question your design of this boundary and suggest that you go back to the drawing board of designing the boundaries along the lines of this acid test. Make sure that the boundary you design would own its single functionality end-to-end.

First and foremost, a microservice must own its full cycle. Anything that is needed to complete its core single responsibility must be owned and controlled by it and its single development team. If you get this right, then you will reap the true benefits of the microservice architecture.

It follows then anything that is outside this request-response cycle that still needs to be communicate with should be done through events. This asynchronous message-based communication will keep the coupling between systems at its minimum and as a side effect of the main microservice API fulfilling its single responsibility.

One might ask that in many complex scenarios, it is impossible to fulfill a whole use case without calling multiple microservices, each having a single responsibility. The answer to that is to implement an orchestrator or process manager on top instead of chaining calls between microservices.

Without getting into the design-time and deployment benefits of the microservice architecture, remember that the main motivation behind it is to minimize the number of communication paths of dependency so a system can do its main job quickly and efficiently without having to wait and depend on another system.