Sunday, March 23, 2014

Decomposing system into microservices

In my previous post on microservices, I made a point about modelling behaviour vs features.

"Often, developers take an approach, where they endeavour to capture an entire feature in a micro service. That might very well be a mistake. The right approach is to model behaviour and not feature within a micro service."

This is a rather crude and concise way of putting across the point I wanted to make. In this post, we shall expand on and refine the thought behind it. We will look at a generic which assists developers understand what constitutes a microservices.

How are microservices organized?

Microservices are organized around business capabilities.

Togaf describes a capability as
"An ability that an organization, person, or system possesses. Capabilities are typically expressed in general and high-level terms and typically require a combination of organization, people, processes, and technology to achieve. For example, marketing, customer contact, or outbound telemarketing."

We can expect a bunch of microservices to help realize a single business capability.

What constitutes a single micro service? When envisioning a microservice, how does a developer go about it?

Let us dub all the cool things that are required to support a micro service such as plumbing for monitoring, dependency health check, etc as the "infrastructure libraries". Every microservice will have those by default.

What we are bothered with is how to carve out the business logic that goes in a single microservice. To understand this, our narrative must take a small detour.

What are architectural styles?

We must understand what an architectural style is. An architectural style is an abstraction a level above an architecture. In simplistic terms, one can think of an analogy - What patterns are to class design, architectural styles are to architecture.

An architecture is usually defined by combining multiple architectural styles.

The developer would want to mix the microservices architectural style with other architectural styles such as RESTful architectural style, event sourced architectural style, or Pipes and filters architectural style.

Many architectures a system has

In large systems, it is common to have systems decomposed into sub systems, and each sub system can have its own architecture. What is required is that the sub system's architecture comply to the overall constraints imposed at the system level and the sub system interact well with its collaborating systems.

We are concerned with systems where the common theme is the "micro services architectural style"

If we take an example of a large online shopping system. We might have a subsystem that takes care of the shopping cart, and another sub system that takes care of the CRM activities. We can envision a system where the shopping cart sub system is authored as a set of restful microservices where as the CRM system is authored as a set of microservices adhering to the pipes and filters architecture.

The approach

Consider the following approach to the problem of modelling microservices in scientific manner,


  1. First we must settle down on what architectural paradigm we shall follow for the business capability under consideration.
    The architectural style in use will lend the vocabulary that is used to describe what constitutes a single microservice.
    For example, if we are creating "resource oriented micro services" i.e. mixing rest architectural style with microservice architectural style, it makes a lot of sense to think in terms of resources.
  2. If we are dealing with legacy systems, think behaviour-first rather than code-first.
    Developers tend to get attached to the code and attempt to preserve it when breaking it down into micro services. This leads to a though process of  "How much of this code can I carve out into a microservice".
    Remember that one of the benifits of microservices code is that the code can be thrown away and rewritten rather than refactored. What is important is that the service is well behaved.
  3. For each microservices
    1. Write down the single responsibility of the service in one or two lines in plain English (or which ever is your preferred language). If more then a couple of lines are required, then revisit and try to break the responsibility down further.
      Draw on the vocabulary of the chosen architectural style to ensure coherent thought and clear communication.
    2. Write test cases to reflect the behavior.
    3. Start implementing the microservice. If the service becomes too large, then revisit the described responsibility, break it down further and repeat points , b and c until a microservice of desired size is obtained.
  4. Ensure that each microservice is independently deployable. This can be achieved by
    1. Ensuring that our microservices are loosely coupled and well behaved. 
    2. Each microservice manages its own data. Considering the size of microservices, this can become quite challenging. It might often require a paradigm shift in the way data is managed.
      To achieve such data independence, the developer may rely on the following approaches
      1.  Polyglot persistence
      2. Data duplication is acceptable. i.e. Some data might get persisted with multiple services. 
      3. Accept eventual consistency within the system where it makes sense.
Decomposing a system into microservices at times seems like art, while we have endeavoured to present a more scientific approach here. Regardless, the only way to truly understand how to do it, is to actually do it!


No comments:

Post a Comment