Microservices: what they are, how they work and best practices of use

Sebastian Sanchez

April 5, 2021

By now many will be familiar with the concept of microservices, others have simply heard of them, but what are they? Microservices are software components at the lowest possible level of functionality. They are components that can have isolated functionality and that manage to have a great deal of decoupling. This is in contrast to traditional monolithic software that compiles all components into a single piece.

Microservices are independent, that is, they only need to be hosted in containers with minimum requirements for their execution and they can interact with other microservices according to the need of use.

Why or when to use microservices?

Microservices allow you to run separate functions, and if for some reason one service fails, the rest will continue to run without being affected by the microservice that is having problems. 

In the case of monolithic applications, if we have a problem with a component, we must stop the execution, correct and make a new deploy of the new version with the fix made. It would mean that we have to stop the whole system, affecting other components that were working properly and that have no relation with the component that failed!

© Kranio 2021
© Kranio 2021
Now that you know what microservices are, you may wonder how they will work and how they will talk to each other.

Well, to implement microservices there are reference models that we can follow. These models guide you to achieve that when separating a set of functions in microservices these are perfectly decoupled and there is no dependency between them.

Reference models

To implement a microservices architecture you must take into account the following aspects:

  • Perform a preliminary analysis and define why a microservices architecture is necessary.
  • Define which reference model is the right one to solve the need (reference architectures).
  • An implementation model with which you can specify the implementation of the components of the reference model. For example, if you use Java and Spring, you must have all the necessary components of this framework that support this architecture.
  • A deployment model that allows you to define how the components of the architecture will be deployed. For example, if you use containers, Docker and what you need to use the applications in these containers.

Given the above, to have a good microservices architecture model, you should at least consider the following necessary components and concepts:

  • Central configuration server (centralized source repository, versioning and software lifecycle).
  • Registration/discovery service (microservices registration, endpoint disposition).
  • Load balancing (service orchestrator).
  • Fault tolerance (work on solving faults in isolation without affecting the rest of the calls).
  • Services exhibition (Gateway).
  • Authorization component (implementation of a security layer).
  • Monitoring (tools to monitor pod health, workload, failures).

Now that you have considered these components, it's time to think about how to structure each microservice. To start you must have a previous analysis related to the business domain to model the microservices. Knowing and managing the business domain, objectives and requirements is one of the biggest challenges, since there is no mechanical process that guides us to a perfect design. But what you can do, is to follow architectures that separate by layers and isolate the domain in a way that the other components communicate with each other, without being affected or mixed.

Hexagonal Architecture

The Hexagonal architecture is a software design pattern, which seeks to decouple the application by components. These components form a series of layers that will be easily connected to each other through ports and adapters. A port is the definition of a public interface and an adapter is a specialization of a port for a particular context. Thus components can become interchangeable at any level or layer. We can also isolate automated tests without the need to go through several layers to test a specific functionality.

This Architecture is represented by a Hexagonal shape, where the sides represent the ports, which allow to go to an inner or outer layer of the application. Each component will be able to connect to another component through these ports. The communication between the ports will always follow a specific protocol (for example an API) that will depend on the objective or function it has. 

Hexagonal Architecture - © Kranio 2021

Hexagonal Architecture

Infrastructure Layer

This layer contains components that are related to the integration of other components of the microservice, for example, an external service component such as a user authentication, or a messaging service (sending mail), which is not a core component of the domain.

Application Layer

This layer contains, for example, a component like Spring in Java and contains the different use cases.

Domain Layer

This layer contains all the business domain of the application, i.e. entities, repositories, model, events, services.

DDD (Domain Driven Design) Architecture

It is a software architecture design where the business logic is the determining factor in the construction of the software. It allows mapping the business in the software artifacts and organize them in such a way that it manages to solve business problems. 

Modeling is based on business use cases. There is a context, which is created from the need to solve a problem. We have to establish limits for the resolution of this problem, limiting the requirements so that they are not redundant or do more than necessary for the solution. With this we get an idea of the ideal size that the microservice should have. This point is important because not setting limits, leads to have a microservice too large and generate unnecessary couplings. Cohesion is a key concept in the delimitation of each component.

Levels or layers of DDD

The structure is composed of layers or levels well defined and structured in such a way that its components are not mixed between layers. For example, we ensure that business entities are not in layers that do not belong to the business domain, or that the persistence logic is in the infrastructure layer and not in the presentation one... 

The levels or layers interact with each other through their own interface, keeping their internal logic encapsulated.

Layer dependency - © Kranio 2021

The different layers are defined as follows:

Presentation Layer (UI): This is the layer that interacts with the different clients. This layer is the one that shows and receives data. It can be represented by a graphical interface of a web or a device.

Application Layer: Coordinates the actions to be performed in the domain. It delegates the actions of the business to the domain layer. It has dependency with the Infrastructure and Domain layer.

Domain Layer: Contains the business rules and logic, entities and persistence details. It is the core of the software. It has no dependencies with other layers of the model, but yes, other layers depend on it.

Infrastructure Layer: In this layer there are encapsulated implementations and functionalities that are not from the business domain, for example connections with databases, integrations with other external services, email notification service, etc. It has dependencies with the domain layer.

Cohesion and Coupling

Well-designed monolithic applications tend to have a high cohesion, since all its components are integrated in the same context, so it is easy to understand the relationship of each component that is integrated. For microservices it is a constant task to maintain cohesion since being an isolated and loosely coupled component, there are cases where there is so much separation between them that the cohesion of a service and how it is related between the other microservices that may exist in a given context is lost.

Microservices should be designed around enterprise functionality, they should have loose coupling and also high functional cohesion. This means that microservices should exhibit low coupling, but also maintain high cohesion. 

If a component (microservice) requires a change, and this change does not affect the other microservices that interact with it, i.e. they do not need to be updated because of this change, it means that the microservice has a high cohesion. It is designed with a unique and well-defined purpose that allows encapsulating domain knowledge in such a way that it can be abstracted from the clients that consume it. If this design is not well defined and is decoupled more than necessary, it is possible to lose cohesion between components.

Advantages

Agility: as they are implemented independently, it is easier to manage microservices, in case of a failure, you can update a single service without having to redeploy the entire application.

Small and focused teams: Since the size of the microservices is small, you only need a small team to manage them. This speeds up productivity since having small teams means that communication flows in a better way. Unlike larger teams where communication tends to be slower, resulting in less agility.

Small code base: Monolithic applications over time tend to grow and have new features, which complicates the maintenance of the code, having to modify several layers of the application. Microservice architectures minimize this dependency by allowing new features to be added easily.

Mix of technologies: Microservices architecture allows you flexibility in the language of each microservice, which improves the implementation of a service according to the most appropriate technology for a functionality. It also allows you to have experts in a specific technology and not have a team forced to use a technology that is not used to use and must investigate.

Error isolation: Microservices being independent, if an error occurs, the error does not prevent the operation of other microservices, so it will not be necessary to stop the entire application to correct errors.

Horizontal Scalability: There is no migration of the entire system to a hardware with better performance, since, being independent services, the concept of service replication is used. This scalability allows to add adaptable resources to the workload growth.

Challenges

Complexity in managementWhen having a distributed architecture in several microservices, it becomes more complex to manage the integration of these. Therefore it is necessary to have tools that allow to have an overview of all of them in case of possible failures.

High memory consumptionMicroservices architecture works in a distributed way and each microservice is independent, therefore resources must increase, unlike a monolithic architecture.

Developer ProfileDeveloper with high experience in development and versioning, knowledge in network latency and load balancing is required.

Initial time investmentWhen implementing this architecture, it requires a greater investment of time since it requires more analysis to correctly separate the services and implement the communication between them.

Personal Vision

When you start designing the architecture and its components, you must keep in mind that it is key to maintain cohesion to achieve a well-defined architecture. You must also have a high management and understanding of the business, since the domain is the most important component and the one you should focus on. If you don't have a high knowledge of the business, it will be more complex to implement architectures like these. 

Another important point is to have the right team to implement this architecture. It must have the necessary expertise to address the components and tools required to build an architecture like this, as well as additional tools such as monitoring of all its artifacts.

Need help? Write to us at

Sebastian Sanchez

April 4, 2021

Previous entries