III Implementing Microservices
Part III demonstrates how microservices can be implemented. After studying the chapters in this part the reader should be able to not only design microservice-based architectures but also implement them and evaluate effects the microservices approach may have on his or her organization.
Chapter 7, “Architecture of Microservice-Based Systems,” describes the architecture of microservice-based systems. It focuses on the interplay between individual microservices.
The domain architecture deals with domain-driven design as the basis of microservice-based architectures and shows metrics that allow you to measure the quality of the architecture. Architecture management is a challenge: It can be difficult to keep the overview of the numerous microservices. However, often it is sufficient to understand how a certain use case is implemented and which microservices interact in a specific scenario.
Practically all IT systems are subject to more or less profound change. Therefore, the architecture of a microservice system has to evolve, and the system has to undergo continuous development. To achieve this, several challenges have to be addressed, which do not arise in this form in the case of deployment monoliths—for instance, the overall distribution into microservices is difficult to change. However, changes to individual microservices are simple.
In addition, microservice systems need to integrate legacy systems. This is quite simple as microservices can treat legacy systems as a black box. A replacement of a deployment monolith by microservices can progressively transfer more functionalities into microservices without having to adjust the inner structure of the legacy system or having to understand the code in detail.
The technical architecture comprises typical challenges for the implementation of microservices. In most cases there is a central configuration and coordination for all microservices. Furthermore, a load balancer distributes the load between the individual instances of the microservices. The security architecture has to leave each microservice the freedom to implement its own authorizations in the system but also ensure that a user needs to log in only once. Finally, microservices should return information concerning themselves as documentation and as metadata.
Chapter 8, “Integration and Communication,” shows the different possibilities for the integration and communication between microservices. There are three possible levels for integration:
- • Microservices can integrate at the web level. In that case each microservice delivers a part of the web UI.
- • At the logic level microservices can communicate via REST or messaging.
- • Data replication is also possible.
Via these technologies the microservices have internal interfaces for other microservices. The complete system can have one interface to the outside. Changes to the different interfaces create different challenges. Accordingly, this chapter also deals with versioning of interfaces and the effects thereof.
Chapter 9, “Architecture of Individual Microservices,” describes possibilities for the architecture of an individual microservice. There are different approaches for an individual microservice:
- • CQRS divides read and write access into two separate services. This allows for smaller services and an independent scaling of both parts.
- • Event Sourcing administrates the state of a microservice via a stream of events from which the current state can be deduced.
- • In a hexagonal architecture the microservice possesses a core, which can be accessed via different adaptors and which communicates also via such adaptors with other microservices or the infrastructure.
Each Microservice can follow an independent architecture.
In the end all microservices have to handle technical challenges like resilience and stability—these issues have to be solved by their technical architecture.
Testing is the focus of Chapter 10, “Testing Microservices and Microservice- Based Systems.” Also tests have to take the special challenges associated with microservices into consideration.
The chapter starts off by explaining why tests are necessary at all and how a system can be tested in principle.
Microservices are small deployment units. This decreases the risk associated with deployments. Accordingly, besides tests, optimization of deployment can also help to decrease the risk.
Testing the entire system represents a special problem in case of microservices since only one microservice at a time can pass through this phase. If the tests last one hour, only eight deployments will be feasible per working day. In the case of 50 microservices that is by far too few. Therefore, it is necessary to limit these tests as much as possible.
Often microservices replace legacy systems. The microservices and the legacy system both have to be tested—along with their interplay. Tests for the individual microservices differ in some respects greatly from tests for other software systems.
Consumer-driven contract tests are an essential component of microservice tests—They test the expectations of a microservice in regard to an interface. Thereby the correct interplay of microservices can be ensured without having to test the microservices together in an integration test. Instead a microservice defines its requirements for the interface in a test that the used microservice can execute.
Microservices have to adhere to certain standards in regard to monitoring or logging. The adherence to these standards can also be checked by tests.
Operation and continuous delivery are the focus of Chapter 11, “Operation and Continuous Delivery of Microservices.” The infrastructure is especially an essential challenge when introducing microservices. Logging and monitoring have to be uniformly implemented across all microservices; otherwise, the associated expenditure gets too large. In addition, there should be a uniform deployment. Finally, starting and stopping of microservices should be possible in a uniform manner—in other words, via a simple control. For these areas the chapter introduces concrete technologies and approaches. Additionally, the chapter presents infrastructures that especially facilitate the operation of a microservices environment.
Finally, Chapter 12, “Organizational Effects of a Microservice-Based Architecture,” discusses how microservices influence the organization. Microservices enable a simpler distribution of tasks to independent teams and thus for parallel work on different features. To that end the tasks have to be distributed to the teams, which subsequently introduce the appropriate changes into their microservices. However, new features can also comprise several microservices. In that case one team has to put requirements to another team—this requires a lot of coordination and delays the implementation of new features. Therefore, it can be better that teams also change microservices of other teams.
Microservices divide the architecture into micro and macro architecture: In regards to micro architecture the teams can make their own decisions while the macro architecture has to be defined for and coordinated across all microservices. In areas like operation, architecture, and testing individual aspects can be assigned to micro or macro architecture.
DevOps as organizational form fits well with microservices since close cooperation between operation and development is very useful, especially for the infrastructure-intensive microservices.
The independent teams each need their own independent requirements, which in the end have to be derived from the domain. Consequently, microservices also have effects in these areas.
Code recycling is likewise an organizational problem: How do the teams coordinate the different requirements for shared components? A model that is inspired by open-source projects can help.
However, there is of course the question whether microservices are possible at all without organizational changes—after all, the independent teams constitute one of the essential reasons for introducing microservices.