In this article, we’ll study some key decisions and at what architecture level, micro or macro, they should be taken.
Microservices provide technological isolation. Therefore, it is possible to extend the concept of micro and macro architecture to technical decisions.
For deployment monoliths, these decisions, inevitably, must be implemented globally.
So, only for microservices, technical decisions can be made within the framework of macro or microarchitecture. However, some decisions have to be part of the macro architecture. Otherwise, the integration will be compromised.
Micro and macro architecture decisions
Decisions can be taken in the context of either micro or macro architecture.
Let’s discuss each.
Programming languages, frameworks, and infrastructure
Programming languages, frameworks, and infrastructure can be defined for each microservice individually at the micro architecture.
- Then each microservice can also be done in a different language.
- Technology, such as the application server, that is ideally suited to the particular problems of each microservice, can be used.
Programming languages, frameworks, and infrastructure can be defined uniformly for all microservices in the macro architecture. This is useful if:
- a company’s technology strategy allows only certain technologies
- therefore, only developers with knowledge of certain technologies are hired
At first glance, this decision seems to be comparable to the decision concerning the programming languages, frameworks, and infrastructure but databases are different because:
- They store data.
- The loss of data is usually unacceptable.
- Therefore, there must be a backup strategy and a disaster recovery strategy for a database.
- Setting these up for many different databases requires considerable effort.
Micro: Each microservice can also have its own instance of the database. If databases were defined at the micro architecture.
- A crash of one database will cause only one microservice to fail which makes the entire app more robust.
- However, the higher effort involved, especially concerning operation, is an argument against individual instances.
Macro: To avoid needing many different databases, the database can be defined as part of the macro architecture for all microservices.
- Even if the database is defined in the macro architecture, multiple microservices must not share a database schema. That would contradict the bounded contexts.
- The domain model in the database schema would be used by several microservices. This would couple the microservices too strongly. Even with a unified database, the microservices must have separate schemata in the database.
If microservices have their own user interface (UI), the look and feel of microservices can be a micro or macro architecture decision.
Micro: often the device has various groups of users (for example, back office and customers) with different specifications for the UI, which are sometimes incompatible with a standardized look and feel. The decision on micro architecture for the UI is acceptable in this situation.
- Often there are concerns that a microservice level decision will cause inconsistencies in the look and feel; however, the UI can also diverge in a monolithic system. Hence, defining appropriate style guides and artifacts is the only way to achieve a consistent look and feel for large systems, regardless of the use of microservices.
Macro: Often a system should have a uniform UI; therefore, the look and feel must be a macro architecture decision.
It may be necessary to standardize the documentation.
Micro: The documentation should be part of the micro architecture if the same team will build and maintain the microservice.
- A certain level of documentation makes it easier to later hand the microservice over to another team.
- It may also be necessary to document certain aspects of the microservices in a uniform manner.
- For example, for security reasons, some systems need to keep track of the libraries used in the microservices. In the case of a security vulnerability in a specific library, it is then possible to identify which microservices need to be fixed.
Macro: Of course, the decision about the documentation can also be part of the macro architecture.
- Standardized documentation can provide an overview of the system and the dependencies between microservices.
Typical macro architecture decisions
There are some decisions that must always be taken at the level of macro architecture. Ultimately, all microservices together should result in a coherent system. This requires some standards.
The communication protocol of the microservices is a typical macro architecture decision.
- Only if all microservices provide a uniform interface, for example, a REST interface or a messaging interface, can they communicate with each other coherently.
- Also, the data format must be standardized. It makes a difference whether systems communicate with JSON or XML, for example.
If the communication protocol was a microservice decision, i.e., a different communication channel between each microservice, a coherent system will not exist and will disintegrate into islands that communicate with each other in different ways.
With authentication, a user proves their identity. This can be done with a password and a username, to name a common example.
Since it is unacceptable for the user to re-authenticate with every microservice, the entire microservice system should use a single authentication system. The user then enters a username and password once and can then use any microservice.
Integration testing technology is also a typical macro architecture decision. All microservices must be tested together, so they must run together in an integration test. The macro architecture must define the necessary prerequisites for this.
Typical micro architecture decisions
Certain decisions should be taken for each microservice individually. Therefore, they are typically part of the micro architecture.
The authorization of the user determines what a user is allowed to do. The authorization should be done in the respective microservice.
Which user is allowed to initiate what action, i.e., authorization, is part of the domain logic, and therefore belongs to the microservice like the other domain logic.
If this was decided at the macro architecture, the domain logic would be implemented in a microservice itself, but the decision about which part of the domain logic is available to which user would be made centrally, which is difficult, especially with complex rules.
- For example, if orders up to a certain upper limit can be triggered by certain users, authorization, concrete upper limits, and possible exceptions belong to the microservice order.
Authentication assigns the user roles used in authorization.
- For example, a microservice can define which actions a user with the role of customer can trigger and which actions a user with the role of call center agent can trigger.
The testing can be different for each microservice. Even the tests are ultimately part of the domain logic.
In addition, there may be different non-functional requirements for each microservice.
- For example, one microservice can be particularly performance-critical, whereas another is more safety-critical.
These risks must be covered by an individual focus in the tests.
Since the tests can be different, the continuous delivery pipeline is also different for each microservice. It must include the relevant tests. Of course, the technology for the continuous delivery pipeline can be standardized
- For example, each pipeline can use a tool like Jenkins. What happens in the respective pipelines, however, depends on the respective microservice.
Some more decisions point of micro and macro architecture
The interface in which the microservice obtains its configuration parameters must be defined. For example, a microservice may get these settings from an environment variable or read them from a configuration file. These parameters shall contain both:
- Technical parameters such as thread pool sizes
- Parameters for the domain logic
The decision on how to store and create configuration data is independent of these criteria. For eg, data may be stored in a database. Configuration files or environment variables may be created from the data in the database.
Note that the information on which computer and under which port a microservice can be reached, does not belong to the configuration, but to the service discovery.
Configuring passwords or certificates is also a challenge that can be solved with other tools. To do this, Vault is a good choice because this information must be stored in a particularly secure way and must be visible to as few employees as possible in order to prevent unauthorized access to production data.
For every application, monitoring is very important. So let’s understand what is monitoring?
Monitoring is about the technology that tracks metrics. Metrics provide information about the state of a system. Examples include the number of requests processed per second or business metrics, such as revenue.
The question of which technology is used to track the metrics is independent of which metrics are captured. Every microservice has different metrics because every microservice has different challenges. For example, if a microservice is under a very high load, then performance metrics are useful.
Log analysis defines a tool for managing logs, like Splunk.
Although logs were originally stored in log files, they are now stored on specialized servers. This has a few advantages. For example, it makes it easier to analyze and search the logs, even with large amounts of data and many microservices.
In addition, new instances of a microservice can be started when the load increases and can be deleted again after the load decreases. In this case, the logs of this microservice instance should still be available, even if the microservice was deleted long ago due to a decreasing load. If the logs are stored only on a local device, the logs would be gone after the microservice has been deleted.
Deployment technology determines how the microservices are rolled out. For example, this can be done with Docker images, Kubernetes Pods, a PaaS, or installation scripts.
These decisions define how a microservice behaves from an operational point of view. Typically, these decisions are either all part of the macro architecture or the microarchitecture.
Macro architecture operation with separate operations teams
The organization depends on whether decisions in the field of operation belong to the micro or macro architecture.
For example, a team can develop microservices but is not responsible for their operation. The operating team is responsible for the operation of all microservices. In this scenario, operating decisions must be made at the macro architecture level.
It is generally not appropriate for the Operations Team to learn a separate approach to the activity of each microservice, particularly when the number of microservices is far greater than the number of implementation monoliths for the same project.
Another factor for the decision on the macro architecture for the application of microservices is that there are few advantages to individual solutions in this area. Since the programming language or architecture may be more or less appropriate for a specific challenge, the same applies to technology in the field of service to a much lesser extent.
Standardize only technologies!
As these choices are taken at the macro architecture level, they just standardize technologies.
What configuration criteria, tracking metrics, log messages and implementation functionality of the microservice are the decision at the level of the individual microservice.
Independent implementation must still be maintained as a primary aspect of the microservices. This ensures that it must be possible to alter the configuration parameters for each microservice individually in order to update the configuration as a new implementation takes place.
Testing the operation macro architecture
The adherence to the rules of the macro architecture can be checked with tests. Microservices are being deployed in the environment. The tests shall check whether the uniform deployment rules are complied with. The test then verifies whether the microservice provides metrics and log information in the defined way. Something similar is also possible for configuration purposes.
The test environment for these tests should be very minimal and should not contain any other microservices or databases. In this way, the microservice is tested in an environment in which it is impossible to operate. When such a situation occurs in production, it is particularly important for the microservice to provide logs and metrics for the analysis of potential problems. Similarly, the test also controls the resilience of the microservice.
“You build it, you run it”: operation as micro architecture
There is a form of organization in which the operational aspects must be part of the micro-architecture. If a microservice is to be developed and operated by the same team, they must also be able to choose the technology. This approach could be described as “you build it, you run it.” Each team is responsible for the microservice, its operation and its development. You can only expect this level of responsibility from the team if you allow them to choose their own technology.
Operation as a whole is micro or macro architecture
Decisions for operation can be made either at the level of the micro or macro architecture. Making operational decisions part of the macro architecture is useful if there is a separate operating team, while the “you build it, you run it” organization must make these decisions at the level of the micro architecture. This point is illustrated in the drawing below.
Macro architecture decisions: Best practices and advice
- Specifying just a few points in the macro architecture allows to concentrate. Many teams have struggled to execute a far-reaching unification in a dynamic project or IT landscape. If there are few rules for macro design, the odds are that the rules are eventually applied effectively.
- The rules should be minimal.
- For eg, a macro architecture rule may be used to describe the monitoring technologies. However, it is not appropriate to standardize the calculation of the metrics in the application. It is necessary, after all, just that the metrics are generated. It’s irrelevant if this happens. The macro architecture rule should only specify the protocol for transmitting metrics, but leave the collection of the library to build and pass metrics to the micro architecture. Teams may pick the most suitable technology in this manner.
- Macro architecture principles must also be followed. For example, if the metrics are not produced, the operating team cannot easily put the microservice into production. It’s crucial to get rid of all needless macro architecture components.
- In addition, independence is an essential objective of microservices. Too many macro architecture guidelines run counter to this aim because they impede the freedom of the teams by central management.
- Complying with macro architecture should be in the self-interest of the teams responsible for the microservices. Violations of macro architecture usually mean that microservices cannot go into production because operations cannot support them.
In addition to mandatory macro architecture rules, recommendations and best practices are advisable. However, they do not have to be enforced but are optional for every microservice.
In the end, the goal of macro architecture is to create freedom. Advice and references to best practices are therefore good additions.