Implementing Axon Framework’s Microservices Design Patterns

It's often easier to learn from the real-life perspectives of users than from solutions providers. At our 2020 conference, a customer team discussed both the theory and their reality of implementing an application using Axon Framework microservice design patterns. 

During this session, the team explained why they chose to build the application using microservices with Axon Framework after having compared it with three other architectural styles: Microkernel, Service-Oriented Architecture (SOA), and typical microservices.

Architectural characteristics


To make a fair comparison, the team scored and measured the four different approaches based on eleven architectural characteristics grouped into three categories with as little bias as possible. We can see those in Figure 1.

Figure 1: Categorization of architectural characteristics

Microservices Design Patterns

Deciding which architectural characteristics were important was an intense, iterative process for the team. Architectural characteristics influence which trade-offs will be made in the applications’ architecture. If there are too many trade-offs, it becomes confused and fails to perform adequately. 

 

Microkernel architecture

A microkernel architecture has a core system at its center, with plugin components providing additional functionality. It’s quick to write and low-cost since it’s typically a monolithic application. It also provides for the ability to partition domains into the plugin components.

Figure 2: An overview of the Microkernel architectureblogcomparingaxonframeworktootherarchitecturesimage2

However, individual components cannot be scaled, and the core system is prone to bloating. It’s also difficult to build fault tolerance into MicroKernel. Therefore, it’s often considered suitable for only small applications or larger applications where less performance is required.

 

Service-oriented architecture


Service-oriented architecture (SOA) divides a system into multiple coarse-grained services. These are often defined by the domain they represent. For example, for a banking application, there may be a ‘lending service’ and a ‘savings service’.

Since they are coarse-grained and represent a domain, developers can quickly and easily start by creating a shared understanding of the domain. It also encapsulates volatility well, and it has less traffic between services, leading to less latency.

However, the services are easy to get bloated, as are their database since most of the time, the services (or the components of a service) share it.

Overall, it’s a good approach in most cases. You can decompose the services into smaller ones if certain desired characteristics, such as performance, require the services to be scoped differently.

Figure 3: An overview of the Service-oriented Architectureblogcomparingaxonframeworktootherarchitecturesimage3

Microservices (typical approach)

The microservice design patterns approach many companies typically started out with had lots of small services. The microservices could be scaled effectively at crucial points in the architecture. However, without a framework, they become hard to manage. The data isolation is good, and the architecture allows developers to parallelize work. 

Figure 4: An overview of the typical microservices architectureblogcomparingaxonframeworktootherarchitecturesimage4

The challenge of using this approach is that it introduces an API gateway that knows a lot about the individual microservices and their data structure. These additional network calls introduce latency, especially when a microservices must call another to ask for additional information or execute an action.

A platform system is needed to automate discovery, logging, alerting, and other vital concerns to use microservices efficiently. The microservices approach also introduces a ripple effect when building new features. When building a new feature or enhancing a current one, it’s often needed to change multiple services simultaneously. 

Decomposing a service is usually more effective if left until the need arises. Decomposing at the start, as the microservices approach encourages, can cause the services to be scoped incorrectly since the domain is not yet clear. 

 

Microservices with Axon Framework

CQRS and Event-Sourcing are principles most easily applied with the support of a purpose-built framework. Axon Framework removes a lot of friction points within this architecture, and the event-sourcing within the framework is very suitable for a system of record like a bank.

The downside of the approach is that CQRS has a steep learning curve in the beginning and that good aggregate design is complex.

Axon Framework heavily encourages DDD approaches and facilitates volatility encapsulation of projections by providing projections and events. It also provides a lot of the needed boilerplate needed for the architecture, such as message delivery and location transparency.

Figure 5: Overview of the Axon CQRS architecture

blogcomparingaxonframeworktootherarchitecturesimage5

Comparison

Based on the key architecture characteristics, the team compared the four approaches using a scoring system for each of the main architectural categories. Their ratings can be seen in figure 6. Based on this, they found that Axon Framework had the most significant competitive advantage of the four architectural styles and proceeded to implement the application using the microservices architecture based on Axon Framework.

Figure 6: Rating of the different architectural characteristics

blogcomparingaxonframeworktootherarchitecturesimage6

In addition to the comparison, the team also shares their post-implementation experience; it’s a great talk to watch if you are considering Axon Framework for your architecture.
The presentation in full is available to watch on the AxonIQ YouTube channel.