The technologies we employ to build our applications evolve, rapidly. Meanwhile, the business for which the software is built also evolves. However, the pace of change and the impact it has is significantly different for these two aspects. Business owners typically require swift response and a short time-to-market when business requirements change. Technical changes are typically in response to new technologies being available, which allow developers to address their challenges in a way that better suits their non-functional requirements.

The technologies we employ to build our applications evolve, rapidly. Meanwhile, the business for which the software is built also evolves. However, the pace of change and the impact it has is significantly different for these two aspects. Business owners typically require swift response and a short time-to-market when business requirements change. Technical changes are typically in response to new technologies being available, which allow developers to address their challenges in a way that better suits their non-functional requirements.

One of the most important aspects of Axon is the abstractions it provides. This differentiates Axon from many other frameworks and helps in ensuring that applications based on Axon can withstand the test of time. Axon’s use of explicit messages between components provides clear boundaries between then, allowing systems to be built and adapted using an Evolutionary Architecture, without suffering from the many challenges of Distributed Systems from day 1.

Separating business from infrastructure

Ever since its inception in 2009, Axon Framework has been designed to separate the business logic from infrastructural concerns. This separation has proven to be key in improving the long-term maintainability of code, ensuring systems can be modified to maintain their relevance in changing domains.

“The man who moves a mountain begins by carrying away small stones.” – Confucius. However, for that to work the mountain must be made up of small stones. Unfortunately, this is not true for many of the monolithic software systems out there. Many systems suffer from the absence or decay of architectural elements, and have evolved into a “Big Ball of Mud”.

Separation of concerns is a very important concept in software architecture. This is especially true when separating the “what” from the “how”. Business logic is about “what” needs to happen. The choices made on “how” these things need to happen, are often specific to the types of systems you need to interact with, which we refer to as infrastructure logic.

In Axon, business logic is implemented in classes that interact with the different Message Buses. Axon Framework provides a number of building blocks to assist developers in implementing this logic, such as Aggregates, Command Handlers, Event Handlers, View Models, Sagas, etc.

Infrastructure logic is typically a matter of configuration. This configuration defines which implementations of Message Buses should be used, how technical errors should be dealt with and how messages should be transformed to communicate across remote components in a system. In places where simple configuration does not suffice, it is possible to implement small, custom, components to change the behavior of Axon-provided infrastructural components. This approach significantly reduces the need for so-called “boilerplate code”, while still having a high degree of customizability.

Business components communicate through messages

Axon heavily stimulates the separation of logic into smaller components, which communicate with each other through messages. This significantly reduces the mental burden on developers working with specific components. While developers need to worry about the logic being executed for a specific incoming message, such as an event, they do not need to worry under what conditions that event was emitted.

At a system level, instead of components directly interacting with each other, which creates a stronger coupling, components interact without explicitly knowing they do so, which provide for a looser coupling. This approach can be very powerful, allowing change in behavior of the system, even when none of the individual components in that system have changed. Axon provides the monitoring endpoints required to test, monitor and manage such system.

In Axon, components communicate through explicit messages. These are messages for which there is an actual definition of the data it carries, and that can be transported regardless of the distance between the components in a system.

There are three categories of messages that a component has a reason to send:

  • Commands represent an intent to perform an operation in the system, which typically changes its state. Commands provide a reply to indicate whether the change was successful or not.
  • Events are a notification that something relevant has happened in the system. For example, a change as a result of a processed Command. Events are one-way; the sending component will not wait for any confirmations or replies.
  • Queries express the desire for information, generally a specific representation of the state of the system.

Having explicit messaging in place, we now need to decide “when and what” messages are sent and “how” we get these messages published between components. These are fundamentally different aspects that need to be addressed in different parts of the codebase.

The “when and what” are typically business logic related — when a user applies for a loan and we don’t have a credit score for that user, then we request a credit score. In Axon terms, this means that when a message comes in representing the loan application, we send a Query to request the credit score for that user.

The “how” is more technical in nature. Which protocols do we need to get the message to the credit system? Which format of messages do they require? How do we handle communication errors with the external system? While these aspects need to be addressed, they do not directly influence the decision-making process of whether the credit score is needed, or not.

Location transparency

The abstraction Axon provides by using explicit messages comes with another benefit: a component that communicates with another component does not need to know where that other component is located. In fact, the component sending a message doesn’t even need to know which other component it communicates with. This makes an Axon-based system significantly more flexible than a system based on a more traditional service-based discovery mechanisms, where components are explicitly aware of the recipient of a message.

This so-called Location Transparency enables systems to gradually evolve from a structured monolith, where all components are deployed as part of the same unit, to a full microservices system, where each component is deployed individually. The ability to gradually do so, allows for systems to evolve at a pace that is much more aligned with the pace at which the teams and business evolves. Components will only need to be split across deployable units if the non-functional requirements, such as team size, release cycle, availability requirements, performance, etc., require so. Until then, deploying components as part of the same unit, reduces technical complexity of running them.

Summary

Evolutionary architectures provide the flexibility required for systems to maintain their business value throughout time. However, managing the boundaries of components to ensure their loose coupling can be challenging. Axon provides the APIs and abstractions developers need to build components with clearly defined APIs. At runtime, it ensures these components can interact, regardless of how each one is deployed.

Subscribe

and find out useful news on Axon releases, invitations to AxonIQ events and other news