Rethinking Microservices Architecture through Dynamic Consistency Boundaries

When creating microservices-based architectures, developers may encounter the concept of an “aggregate” while modeling their systems. In the simplest of terms, an aggregate is a collection of various objects in your system that can be treated as a single unit. It's important to note that an aggregate includes an aggregate root, entities, and value objects bound together by consistency rules.

Most notably, aggregates serve to enforce consistency and integrity within your domain model. They define boundaries for where business rules apply and ensure that changes to the data are both valid and coherent. At the end of the day, aggregates are crucial for managing domain logic, however, their traditional implementation can sometimes hinder scalability and flexibility, especially in distributed systems.

Microservices architectures have revolutionized the way developers build and manage complex systems. But as they evolve, we encounter conceptual bottlenecks that can stifle performance and scalability. One critical area that can be improved is the handling of consistency within a microservice's bounded context. This is where "Dynamic Consistency Boundaries" (DCB) come into play.

Have you ever wondered if the traditional implementation of aggregates is always the best approach, especially when considering transactional operations that span multiple objects? So, let’s dig a little deeper into this new, exciting concept.

Understanding the Pitfalls of Aggregates in Dynamic Systems

Traditionally, aggregates aim to encapsulate and enforce the business rules that maintain the integrity of data. However, they can become a significant bottleneck. Have you come across a situation where an operation spans across multiple aggregates? The resulting complexity can lead to larger transactional scopes than necessary and reduced system performance. Why is that the case? 

Consider a bank's transaction system. If a transfer operation touches upon two different aggregates, a long transaction becomes essential to maintain consistency, leading to reduced system performance. Is there a better way to maintain data integrity without sacrificing concurrency and performance? Yes, and that's where Dynamic Consistency Boundaries step in.

“Bounded contexts” are essential to scalable microservices-based architectures, but what exactly are they? A bounded context is when you define and apply explicit boundaries within a particular model. This can be illustrated in the following scenario.

How Bounded Contexts Can Be Applied Within a Bank or Financial Institution

Within a bank, financial transactions are multifaceted, involving several subdomains such as accounts management, fraud detection, and regulatory compliance (to name a few). 

Bounded contexts in a bank with dynamic consistency boundary

Let's consider a simple example where bounded contexts exist while performing a basic use case: transferring money from one account to another:

  1. Accounts Management: This subdomain is concerned with maintaining account balances and transaction history and handling day-to-day operations like deposits, withdrawals, and transfers.

  2. Fraud Detection: Here, the focus is to identify and prevent unauthorized transactions, which involves analyzing patterns, flagging suspicious activity, and blocking potential fraud.

  3. Regulatory Compliance: This area involves ensuring all transactions comply with the regulations and statutory requirements and generating reports for both internal audits and regulatory bodies.

Therefore, in order to manage these concerns without cluttering each subdomain with the intricacies of the others, bounded contexts are employed. As a result, each department treats the same transaction in its own unique way:

  1. The Accounts Management context. Here, the focus is on adjusting account balances after the transfer. The subdomain has a model of accounts where balance changes are integral, and it's responsible for recording the transaction and updating the customer's balance within a short timeframe.

  2. The Fraud Detection context. Here, the same transaction is handled differently. It's treated as a data point that feeds into an algorithm designed to detect unusual patterns. The model operates with less concern for account balances and more for behavioral analysis—frequency of transactions, size of transfers, etc.

  3. The Regulatory Compliance context. Here, the transaction is a piece of a larger puzzle that ensures the bank meets reporting standards and maintains proper documentation for audits and legal purposes.

As you can see, using bounded contexts allows each subdomain to operate within its own well-defined boundaries with its dedicated data models and rules, ensuring that changes in one context do not adversely affect or complicate another. Each bounded context is like a tailored workspace that provides the right tools and information for a specific job, avoiding unnecessary overlap and potential conflicts.

Different bounded contexts can coexist within a system, each with its own domain model. Therefore, defining clear boundaries within which a particular model is essential. They help to logically separate different parts of the system, reducing complexity and avoiding ambiguity. 

By delineating clear boundaries, bounded contexts facilitate a more modular and understandable system. They allow different parts of a system to evolve independently, promoting flexibility and maintainability.Now that we’ve clearly illustrated the need and use of bounded contexts, let’s talk about why Dynamic Consistency Boundaries can help improve the overall performance of your distributed application.

Emergence of Dynamic Consistency Boundaries

A Dynamic Consistency Boundary (DCB) is a flexible architectural pattern that promises more adaptable transactional consistency within a single bounded context. But what exactly does this imply for the design and operation of a microservice?

When using a DCB, you can define the scope of transactional consistency independently for each operation based upon specific business rules and constraints. This adjustment does not translate across different bounded contexts; it's confined within a single context

So, how does this look in a practical scenario such as a bank?

Application of DCB in Real-world Scenarios

Let's take a bank's Accounts Management context where transfers between accounts are daily operations. Traditionally, checking that balances are correct across accounts during a transfer would require encompassing multiple aggregates, culminating in a larger-than-necessary transaction scope. What if there was a way to limit this transactional scope dynamically?

Imagine a situation in a banking application where you need to transfer money from a checking account (also called a “current account”) to a savings account without surpassing specific thresholds. With a DCB, you're able to create a temporary boundary that encapsulates only the necessary data elements for the transfer. The dynamic nature of this boundary allows for validating rules across the accounts involved in a single operation, which cannot typically be done across multiple aggregates in real-time.

The DCB, in essence, forms a 'temporary bubble' of consistency, confining the transactional validity to precisely when and where it's needed. Wouldn't this impact performance in a negative way?

The Technical Intricacies and Impact of DCB

Dynamic Consistency Boundaries redefine how we perceive and implement transactional consistency. Instead of burdensome and oversized aggregates imposing rigid consistency across a system, we pinpoint the precise moment and context where rules need to be enforced, allowing for optimization. 

But how does this pan out technically? Take Axon Server as an example, where the infrastructure can support eventual consistency for reading while ensuring that no inconsistent data is written. The key lies in embracing the optimistic lock pattern, maintaining high performance and concurrency without compromising consistency within the boundary.

Easing the Developer's Journey

With DCB, the approach to system design shifts towards a more adaptable and behavior-driven methodology. Rather than exhaustive upfront design, developers can dynamically introduce or adjust consistency rules and boundaries as the system evolves and new requirements emerge.

In what kind of system does this technology prove to be particularly beneficial? Truly, any domain where there is a combination of heavy transactionality and the need for high flexibility stands to gain from the implementation of DCB.

Conclusion, Challenges, and Considerations

While Dynamic Consistency Boundaries offer flexibility, they also introduce complexity in terms of system design and operation. It requires careful planning and implementation to ensure that the system remains reliable and performant.

The concept of Dynamic Consistency Boundaries suggests a future where domain-driven design is more adaptable and capable of addressing the challenges of modern distributed systems.

Aggregates, bounded contexts, and Dynamic Consistency Boundaries are foundational concepts in scalable microservices architectures that are evolving to meet the needs of modern software development. By rethinking these concepts, developers can create more flexible, scalable, and resilient systems. 

Bruce Hopkins
Bruce Hopkins is a Technical Writer and Oracle Java Champion. He works for the Developer Relations team at AxonIQ.
Bruce Hopkins

Share: