As mentioned in our last post, “Microservices: Concepts and Characteristics” microservices is one of the most recent approaches to developing enterprise software applications. Instead of developing an application with a big monolith, is created simple services that, when combined, can offer the functionality needed.
Microservices present particular properties besides unique architecture concepts that allow us to extract the best results of this software development approach.
Microservices Properties
Although there are no exact rules to define microservices, they are typically characterized by some fundamental characteristics:
High Cohesion
The concept of cohesion is closely related to the Single Responsibility Principle introduced by Robert C. Martin in the early 2000s, which states that a class (or in our case, a Microservice) should only have a single responsibility and execute it well. Ignoring this principle results in software that is hard to maintain and reuse.
The degree of cohesion of a software component indicates how closely related are the features it implements and if they are part of the same problem domain. A highly cohesive Microservice means it has a single responsibility and fulfills it completely. It should not overlap responsibilities with other components, delegate its responsibilities to other services or try to execute tasks not related to it.
Low Coupling
A Microservices coupling refers to how connected or related it is to other components. In a way, coupling indicates how a component relies on others in a system. It is desirable that microservices have a low (or weak) relationship of interdependence. This means that microservices are more independent, and therefore more reusable. It will also make them more maintainable because it brings a higher degree of functional isolation which restricts the propagation of changes to its internal behavior.
Autonomy
Microservices should be autonomous, as in they should be completely capable of managing and executing their tasks without depending on other external services. Even when there is an execution flow to be followed with chained services, the autonomous execution model should be followed. Microservices should be capable of orchestrating their communication and execution within the application.
Independence
Ideally, software should be constructed as a set of independent components that function without relying on other resources or external components. This is usually impossible or highly impractical. Nevertheless, this principle should be followed, and external dependencies minimized and thoroughly justified.
Naturally, these concepts are interrelated. For example, low coupling usually implies high cohesion. Similarly, independent microservices need to be cohesive. Autonomy and independence are overlapping concepts.
We can understand coupling as an external property of a component, referring to how it relates to other components. Cohesion, on the other hand, is an internal property of a component, given by how its parts relate to one another.
In this context, we can also consider another Single Responsibility Principle quote from Robert C. Martin: “Group things that change for the same reason. Separate things that change for different reasons”.
Regardless, Microservices are not isolated in an application. At some point, they need to communicate and coordinate to know when to execute. That’s when the Microservices Architecture comes into play. It is the model by which a set of microservices is grouped together in an organized manner to offer the features of a complete application coherently.
Microservices Architecture
The Microservices Architecture defines the model to build each component of a system and its coordination to form a cohesive whole:
- Autonomy – Microservices should be created based on business features to minimize communication between other services or resources. Communication should happen through well-defined contracts that do not expose internal implementation. There must be complete freedom of choice as to what technologies to use to implement a service (like programming language and persistence mechanisms) and it should be possible to deploy each service independently from the rest of the application.
- Resiliency – With the application split in independently deployable microservices, potential failures are isolated, affecting smaller parts of the application and not the system as a whole. Unfortunately, we have now introduced multiple points of failure into our application, therefore it is critical to have the proper monitoring, failure detection, and recovery tools.
- Transparency – In order to have Resiliency, the system must be transparent and observable. Only then it will be possible to identify when a failure occurs so problems can be diagnosed. The main tools used for this purpose are application logs and request tracing.
- Automation – The complexity of a system based on microservices is naturally much higher than a monolithic system. There is the need to automate every step to make the system available (build, automated testing, deploy) and it should be possible and simple to update the system partially (isolated microservices). Eliminating manual tasks reduces errors and guarantees the correct implementation and functionality of the system. DevOps techniques are key to implement a Microservices Architecture.
- Alignment – Microservices must be based on the business needs the application is trying to address. The feature set must be adequately distributed between microservices ensuring high cohesion, low coupling, autonomy and independence as previously stated. Domain-Driven Design is extremely useful for this purpose. Ideally, development and operation teams should be organized around Microservices with each team responsible for one or more components independently.
What is the size of a Microservice?
The prefix “micro” seems to indicate a Microservice should be small, an idea reinforced by the Single Responsibility Principle and high cohesion that should characterize it. A Microservice should do one thing and do it well. In his excellent book “Building Microservices: Designing Fine-Grained Systems”, author Sam Newman states that “a Microservice should be small enough, and no smaller than that”.
There is no final definition of what is a Microservice, so we resort to its properties and characteristics to understand its concept. Likewise, there is no golden rule to define the size of a Microservice, nor the size of the team responsible for its construction, evolution, and maintenance. The size of a microservice is certainly not the most important factor of a system. It is much more important to ensure the properties of High Cohesion, Low Coupling, Autonomy, and Independence.
In the next posts on this series, we will dive deeper into understanding the limitations and main concerns that go into the project of a Microservice.