Chapter 5 - Designing business logic in a microservice architecture

0.0(0)
Studied by 0 people
call kaiCall Kai
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
GameKnowt Play
Card Sorting

1/29

flashcard set

Earn XP

Description and Tags

This chapter covers, Applying the business logic organization patterns: Transaction script pattern and Domain model pattern  Designing business logic with the Domain-driven design (DDD) aggregate pattern  Applying the Domain event pattern in a microservice architecturew

30 Terms

1
New cards

Developing complex business logic in Microservices

Developing complex business logic is even more challenging in a microservice architecture where the business logic is spread over multiple services. You need to address two key challenges.

  • First, a typical domain model is a tangled web of interconnected classes. Although this isn’t a problem in a monolithic application, in a microservice architecture, where classes are scattered around different services, you need to eliminate object references that would otherwise span service boundaries.

  • The second challenge is designing business logic that works within the transaction management constraints of a microservice architecture. Your business logic can use ACID transactions within services, but as described in chapter 4, it must use the Saga pattern to maintain data consistency across services.


2
New cards

What is The Aggregate pattern from DDD?

Fortunately, we can address these issues (In flashcard 1) by using the Aggregate pattern from DDD.

The Aggregate pattern structures a service’s business logic as a collection of aggregates.

An aggregate is a cluster of objects that can be treated as a unit.

3
New cards

What are the two reasons why aggregates are useful when developing business logic in a microservice architecture?

There are two reasons why aggregates are useful when developing business logic in a microservice architecture:

  • Aggregates avoid any possibility of object references spanning service boundaries, because an inter-aggregate reference is a primary key value rather than an object reference.

  • Because a transaction can only create or update a single aggregate, aggregates fit the constraints of the microservices transaction model.

As a result, an ACID transaction is guaranteed to be within a single service.

4
New cards

What is inbound and outbound in a business logic?

Surrounding the business logic are the inbound and outbound adapters.

  • An inbound adapter handles requests from clients and invokes the business logic.

  • An outbound adapter, which is invoked by the business logic, invokes other services and applications.


<p>Surrounding the business logic are the inbound and outbound adapters.</p><ul><li><p>An inbound adapter handles requests from clients and invokes the business logic.</p></li><li><p>An outbound adapter, which is invoked by the business logic, invokes other services and applications.</p></li></ul><p></p>
5
New cards

What are the key decision you must make when developing business logic?

the key decision you must make when developing business logic is whether to use an object-oriented approach or a procedural approach. There are two main patterns for organizing business logic:

  • the procedural Transaction script pattern

  • the object-oriented Domain model pattern.


6
New cards

Designing business logic using the Transaction script pattern

the object-oriented approach, there are some situations where it is overkill, such as when you are developing simple business logic.

In such a situation, a better approach is to write procedural code and use the Transaction script pattern.

Rather than doing any object-oriented design, you write a method called a transaction script to handle each request from the presentation tier. As figure 5.2 shows, an important characteristic of this approach is that the classes that implement behavior are separate from those that store state.

<p>the object-oriented approach, there are some situations where it is overkill, such as when you are developing simple business logic.</p><p><strong>In such a situation, a better approach is to write procedural code and use the Transaction script pattern.</strong></p><p>Rather than doing any object-oriented design, you write a method called a<em> transaction script</em> to handle each request from the presentation tier. As figure 5.2 shows, an important characteristic of this approach is that the classes that implement behavior are separate from those that store state.</p>
7
New cards

Designing business logic using the Domain model pattern

In traditional object-oriented design, a domain model is a collection of classes and relationships between classes. The classes are usually organized into packages.

Pattern: Domain model Organize the business logic as an object model consisting of classes that have state and behavior.

<p>In traditional object-oriented design, <strong>a domain model is a collection of classes and relationships between classes. The classes are usually organized into packages.</strong></p><p><strong>Pattern:</strong> Domain model Organize the business logic as an object model consisting of classes that have state and behavior.</p>
8
New cards

What are the tactical patterns that are the building blocks for domain models

Each pattern is a role that a class plays in a domain model and defines the characteristics of the class.

  • Entity—An object that has a persistent identity. Two entities whose attributes have the same values are still different objects. In a Java EE application, classes that are persisted using JPA @Entity are usually DDD entities.

  • Value object—An object that is a collection of values. Two value objects whose attributes have the same values can be used interchangeably. An example of a value object is a Money class, which consists of a currency and an amount.

  • Factory—An object or method that implements object creation logic that’s too complex to be done directly by a constructor. It can also hide the concrete classes that are instantiated. A factory might be implemented as a static method of a class.

  • Repository—An object that provides access to persistent entities and encapsulates the mechanism for accessing the database.

  • Service—An object that implements business logic that doesn’t belong in an entity or a value object.

There is one more building block that has been generally ignored (myself included!) except by DDD purists: aggregates. As it turns out, aggregates are an extremely useful concept when developing microservices.


9
New cards

Designing a domain model using the DDD aggregate pattern

This example has several classes corresponding to business objects: Consumer, Order, Restaurant, and Courier. But interestingly, the explicit boundaries of each business object are missing from this kind of traditional domain model. It doesn’t specify.

for example, which classes are part of the Order business object. This lack of boundaries can sometimes cause problems, especially in microservice architecture.

<p>This example has several classes corresponding to business objects: Consumer, Order, Restaurant, and Courier. But interestingly, the explicit boundaries of each business object are missing from this kind of traditional domain model. It doesn’t specify.</p><p>for example, which classes are part of the Order business object. This lack of boundaries can sometimes cause problems, especially in microservice architecture.</p>
10
New cards

What’s the problem with fuzzy boundaries (Race condition)

Besides a conceptual fuzziness, the lack of explicit boundaries causes problems when updating a business object. A typical business object has invariants, business rules that must be enforced at all times.

An Order has a minimum order amount, for example. The FTGO application must ensure that any attempt to update an order doesn’t violate an invariant such as the minimum order amount. The challenge is that in order to enforce invariants, you must design your business logic carefully.

11
New cards

example of DDD Aggregates

The Solution: DDD Aggregates


the DDD aggregates uses Optimistic Locking to solve this issue (please review)


The text concludes by mentioning "DDD Aggregates." This is the fix.In Domain-Driven Design (DDD), an Aggregate draws a hard boundary around the Order and its Items. It says: "The Order and all its Items are ONE unit."

If Sam tries to edit an item inside this Aggregate:

  1. The entire Order (Aggregate) is locked or version-checked.

  2. Mary cannot make a change until Sam is finished.

  3. When Mary finally gets to make her change, she sees the new total ($52), realizes her change would drop it to $47 (illegal), and the system stops her.


<p>The Solution: DDD Aggregates</p><p></p><p>the DDD aggregates uses <strong>Optimistic Locking</strong> to solve this issue (please review)</p><p></p><p>The text concludes by mentioning "DDD Aggregates." This is the fix.In Domain-Driven Design (DDD), an <strong>Aggregate</strong> draws a hard boundary around the Order and its Items. It says: <em>"The Order and all its Items are ONE unit."</em></p><p>If Sam tries to edit an item inside this Aggregate:</p><ol><li><p>The <strong>entire</strong> Order (Aggregate) is locked or version-checked.</p></li><li><p>Mary cannot make a change until Sam is finished.</p></li><li><p>When Mary finally gets to make her change, she sees the <em>new</em> total ($52), realizes her change would drop it to $47 (illegal), and the system stops her.</p></li></ol><p></p>
12
New cards

What’s an aggregate and its explicit boundaries?

An aggregate is a cluster of domain objects within a boundary that can be treated as a unit. It consists of a root entity and possibly one or more other entities and value objects. Many business objects are modeled as aggregates.

For example, in chapter 2 we created a rough domain model by analyzing the nouns used in the requirements and by domain experts. Many of these nouns, such as Order, Consumer, and Restaurant, are aggregates.

<p>An aggregate is a cluster of domain objects within a boundary that can be treated as a unit. It consists of a root entity and possibly one or more other entities and value objects. Many business objects are modeled as aggregates. </p><p>For example, in chapter 2 we created a rough domain model by analyzing the nouns used in the requirements and by domain experts. Many of these nouns, such as Order, Consumer, and Restaurant, are aggregates.</p>
13
New cards
<p>Aggregates are consistency boundaries</p>

Aggregates are consistency boundaries

Updating an entire aggregate rather than its parts solves the consistency issues, (check img) Update operations are invoked on the aggregate root, which enforces invariants. Also, concurrency is handled by locking the aggregate root using, for example, a version number or a database-level lock.

For example, instead of updating line items’ quantities directly, a client must invoke a method on the root of the Order aggregate, which enforces invariants such as the minimum order amount. Note, though, that this approach doesn’t require the entire aggregate to be updated in the database. An application might, for example, only update the rows corresponding to the Order object and the updated OrderLineItem.

<p>Updating an entire aggregate rather than its parts solves the consistency issues, (check img) Update operations are invoked on the aggregate root, which enforces invariants. Also, concurrency is handled by locking the aggregate root using, for example, a version number or a database-level lock. </p><p>For example, instead of updating line items’ quantities directly, a client must invoke a method on the root of the Order aggregate, which enforces invariants such as the minimum order amount. Note, though, that this approach doesn’t require the entire aggregate to be updated in the database. An application might, for example, only update the rows corresponding to the Order object and the updated OrderLineItem.</p>
14
New cards

Identifying aggregates is key and Aggregate rules

In DDD, a key part of designing a domain model is identifying aggregates, their boundaries, and their roots. The details of the aggregates’ internal structure is secondary. The benefit of aggregates, however, goes far beyond modularizing a domain model. That’s because aggregates must obey certain rules.

DDD requires aggregates to obey a set of rules. These rules ensure that an aggregate is a self-contained unit that can enforce its invariants. Let’s look at each of the rules.

15
New cards

Aggregate rules - RULE #1: REFERENCE ONLY THE AGGREGATE ROOT

The previous example illustrated the perils of updating OrderLineItems directly. The goal of the first aggregate rule is to eliminate this problem.

It requires that the root entity be the only part of an aggregate that can be referenced by classes outside of the aggregate.

A client can only update an aggregate by invoking a method on the aggregate root.A service, for example, uses a repository to load an aggregate from the database and obtain a reference to the aggregate root. It updates an aggregate by invoking a method on the aggregate root. This rule ensures that the aggregate can enforce its invariant.

16
New cards

Aggregate rules - RULE #2: INTER-AGGREGATE REFERENCES MUST USE PRIMARY KEYS

Another rule is that aggregates reference each other by identity (for example, primary key) instead of object references. For example, as figure 5.6 shows, an Order references its Consumer using a consumerId rather than a reference to the Consumer object.

Similarly, an Order references a Restaurant using a restaurantId.

<p>Another rule is that aggregates reference each other by identity (for example, primary key) instead of object references. For example, as figure 5.6 shows, an Order references its <em>Consumer </em>using a <em>consumerId</em> rather than a reference to the <em>Consumer </em>object.</p><p>Similarly, an <em>Order </em>references a <em>Restaurant </em>using a restaurantId.</p>
17
New cards

Aggregate rules - RULE #3: ONE TRANSACTION CREATES OR UPDATES ONE AGGREGATE

Another rule that aggregates must obey is that a transaction can only create or update a single aggregate.

this constraint is perfect for the microservice architecture. It ensures that a transaction is contained within a service. This constraint also matches the limited transaction model of most NoSQL databases.

This rule makes it more complicated to implement operations that need to create or update multiple aggregates. But this is exactly the problem that sagas (described in chapter 4) are designed to solve. Each step of the saga creates or updates exactly one aggregate. Figure 5.7 shows how this works.

<p>Another rule that aggregates must obey is that a transaction can only create or update a single aggregate.</p><p>this constraint is perfect for the microservice architecture. It ensures that a transaction is contained within a service. This constraint also matches the limited transaction model of most NoSQL databases.</p><p>This rule makes it more complicated to implement operations that need to create or update multiple aggregates. But this is exactly the problem that sagas (described in chapter 4) are designed to solve. Each step of the saga creates or updates exactly one aggregate. Figure 5.7 shows how this works.</p>
18
New cards

Aggregate granularity - How large to make each aggregate?

When developing a domain model, a key decision you must make is how large to make each aggregate.

  • On one hand, aggregates should ideally be small. Because updates to each aggregate are serialized, more fine-grained aggregates will increase the number of simultaneous requests that the application can handle, improving scalability.

  • On the other hand, because an aggregate is the scope of transaction, you may need to define a larger aggregate in order to make a particular update atomic.


<p>When developing a domain model, a key decision you must make is how large to make each aggregate.</p><ul><li><p>On one hand, aggregates should ideally be small. Because updates to each aggregate are serialized, more fine-grained aggregates will increase the number of simultaneous requests that the application can handle, improving scalability.</p></li><li><p>On the other hand, because an aggregate is the scope of transaction, you may need to define a larger aggregate in order to make a particular update atomic.</p></li></ul><p></p>
19
New cards

Designing business logic with aggregates

In a typical (micro)service, the bulk of the business logic consists of aggregates.

The rest of the business logic resides in the domain services and the sagas. The sagas orchestrate sequences of local transactions in order to enforce data consistency.

The services are the entry points into the business logic and are invoked by inbound adapters. A service uses a repository to retrieve aggregates from the database or save aggregates to the database.

Each repository is implemented by an outbound adapter that accesses the database. Figure 5.9 shows the aggregate-based design of the business logic for the Order Service.

<p>In a typical (micro)service, the bulk of the business logic consists of aggregates. </p><p>The rest of the business logic resides in the domain services and the sagas. The sagas orchestrate sequences of local transactions in order to enforce data consistency. </p><p>The services are the entry points into the business logic and are invoked by inbound adapters. A service uses a repository to retrieve aggregates from the database or save aggregates to the database. </p><p>Each repository is implemented by an outbound adapter that accesses the database. Figure 5.9 shows the aggregate-based design of the business logic for the Order Service.</p>
20
New cards

Publishing domain events - Pattern

In the context of DDD, a domain event is something that has happened to an aggregate. It’s represented by a class in the domain model. An event usually represents a state change. Consider, for example, an Order aggregate in the FTGO application. Its state-changing events include Order Created, Order Cancelled, Order Shipped, and so forth. An Order aggregate might, if there are interested consumers, publish one of the events each time it undergoes a state transition.

Pattern: Domain event An aggregate publishes a domain event when it’s created or undergoes some other significant change.

<p>In the context of DDD, <strong>a domain event is something that has happened to an aggregate. </strong>It’s represented by a class in the domain model. An event usually represents a state change. Consider, for example, an Order aggregate in the FTGO application. Its state-changing events include Order Created, Order Cancelled, Order Shipped, and so forth. An Order aggregate might, if there are interested consumers, publish one of the events each time it undergoes a state transition.</p><p><strong>Pattern:</strong> Domain event An aggregate publishes a domain event when it’s created or undergoes some other significant change.</p>
21
New cards

What is a domain event?

A domain event is a class with a name formed using a past-participle verb. It has properties that meaningfully convey the event. Each property is either a primitive value or a value object. For example, an OrderCreated event class has an orderId property.

A domain event typically also has metadata, such as the event ID, and a timestamp. It might also have the identity of the user who made the change, because that’s useful for auditing. The metadata can be part of the event object, perhaps defined in a superclass.

<p>A domain event is a class with a name formed using a past-participle verb. It has properties that meaningfully convey the event. Each property is either a primitive value or a value object. For example, an OrderCreated event class has an orderId property.</p><p>A domain event typically also has metadata, such as the event ID, and a timestamp. It might also have the identity of the user who made the change, because that’s useful for auditing. The metadata can be part of the event object, perhaps defined in a superclass.</p>
22
New cards

Event enrichment

You are building an Event Consumer (such as an Order History Service) that needs to process OrderCreated events. To do its job correctly, this consumer needs specific details about the order, such as the items purchased and delivery info.

The "Event Enrichment" Approach

The Order Service (the publisher) "enriches" the event by packing it with all the details the consumer might need upfront.

  • The Data Included: In this scenario, the enriched OrderCreated event includes lineItems, deliveryInformation, paymentInformation, and even the restaurantName.

  • The Benefit: The consumer (Order History Service) is simplified because it no longer has to fetch that data—it's already in the message.


<p>You are building an <strong>Event Consumer</strong> (such as an <strong>Order History Service</strong>) that needs to process <code>OrderCreated</code> events. To do its job correctly, this consumer needs specific details about the order, such as the items purchased and delivery info.</p><p><strong>The "Event Enrichment" Approach</strong></p><p>The <strong>Order Service</strong> (the publisher) "enriches" the event by packing it with all the details the consumer might need upfront.</p><ul><li><p><strong>The Data Included:</strong> In this scenario, the enriched <code>OrderCreated</code> event includes <code>lineItems</code>, <code>deliveryInformation</code>, <code>paymentInformation</code>, and even the <code>restaurantName</code>.</p></li><li><p><strong>The Benefit:</strong> The consumer (Order History Service) is simplified because it no longer has to fetch that data—it's already in the message.</p></li></ul><p></p>
23
New cards

How to Identify domain events

There are a few different strategies for identifying domain events. Often the requirements will describe scenarios where notifications are required. The requirements might include language such as “When X happens do Y.” For example, one requirement in the FTGO application is “When an Order is placed send the consumer an email.” A requirement for a notification suggests the existence of a domain event.

24
New cards

Identifying domain events with Event storming & The 3 steps it consists of

Another approach, which is increasing in popularity, is to use event storming. Event storming is an event-centric workshop format for understanding a complex domain. It involves gathering domain experts in a room, lots of sticky notes, and a very large surface—a whiteboard or paper roll—to stick the notes on. The result of event storming is an event-centric domain model consisting of aggregates and events.


Event storming consist of three main steps:

  1. Brainstorm events—Ask the domain experts to brainstorm the domain events. Domain events are represented by orange sticky notes that are laid out in a rough timeline on the modeling surface.

  2. Identify event triggers—Ask the domain experts to identify the trigger of each event, which is one of the following:

    1. User actions, represented as a command using a blue sticky note

    2. External system, represented by a purple sticky note Another domain event

    3. Passing of time

  3. Identify aggregates—Ask the domain experts to identify the aggregate that consumes each command and emits the corresponding event. Aggregates are represented by yellow sticky notes.


<p>Another approach, which is increasing in popularity, is to use event storming. <strong>Event storming is an event-centric workshop format for understanding a complex domain</strong>. It involves gathering domain experts in a room, lots of sticky notes, and a very large surface—a whiteboard or paper roll—to stick the notes on. The result of event storming is an event-centric domain model consisting of aggregates and events.</p><p></p><p>Event storming consist of three main steps:</p><ol><li><p>Brainstorm events—Ask the domain experts to brainstorm the domain events. Domain events are represented by orange sticky notes that are laid out in a rough timeline on the modeling surface.</p></li><li><p>Identify event triggers—Ask the domain experts to identify the trigger of each event, which is one of the following:</p><ol><li><p>User actions, represented as a command using a blue sticky note</p></li><li><p>External system, represented by a purple sticky note Another domain event</p></li><li><p>Passing of time</p></li></ol></li><li><p>Identify aggregates—Ask the domain experts to identify the aggregate that consumes each command and emits the corresponding event. Aggregates are represented by yellow sticky notes.</p></li></ol><p></p>
25
New cards

Generating and publishing domain events

Communicating using domain events is a form of asynchronous messaging, discussed in chapter 3. But before the business logic can publish them to a message broker, it must first create them. Let’s look at how to do that.

26
New cards

How to generate Domain Events?

Conceptually, domain events are published by aggregates. An aggregate knows when its state changes and hence what event to publish.


A better approach is to split responsibility between the aggregate and the service (or equivalent class) that invokes it. Services can use dependency injection to obtain a reference to the messaging API, easily publishing events. The aggregate generates the events whenever its state changes and returns them to the service. There are a couple of different ways an aggregate can return events back to the service. One option is for the return value of an aggregate method to include a list of events.

knowt flashcard image


<p>Conceptually, domain events are published by aggregates. An aggregate knows when its state changes and hence what event to publish.</p><p></p><p>A better approach is to split responsibility between the aggregate and the service (or equivalent class) that invokes it. Services can use dependency injection to obtain a reference to the messaging API, easily publishing events. The aggregate generates the events whenever its state changes and returns them to the service. There are a couple of different ways an aggregate can return events back to the service. One option is for the return value of an aggregate method to include a list of events.</p><img src="https://assets.knowt.com/user-attachments/8bff347d-5531-4a0b-b99f-75775c2f65f8.png" data-width="100%" data-align="center" alt="knowt flashcard image"><p></p>
27
New cards

How to reliably publish Domain Events?

Chapter 3 talks about how to reliably send messages as part of a local database transaction. Domain events are no different. A service must use transactional messaging to publish events to ensure that they’re published as part of the transaction that updates the aggregate in the database. The Eventuate Tram framework, described in chapter 3, implements such a mechanism. It insert events into an OUTBOX table as part of the ACID transaction that updates the database. After the transaction commits, the events that were inserted into the OUTBOX table are then published to the message broker.

knowt flashcard image


<p>Chapter 3 talks about how to reliably send messages as part of a local database transaction. Domain events are no different. A service must use transactional messaging to publish events to ensure that they’re published as part of the transaction that updates the aggregate in the database. The Eventuate Tram framework, described in chapter 3, implements such a mechanism. It insert events into an OUTBOX table as part of the ACID transaction that updates the database. After the transaction commits, the events that were inserted into the OUTBOX table are then published to the message broker.</p><img src="https://assets.knowt.com/user-attachments/38f09188-cecd-43eb-b107-edc3ecce4532.png" data-width="100%" data-align="center" alt="knowt flashcard image"><p></p>
28
New cards
<p>Consuming domain events</p>

Consuming domain events

29
New cards
30
New cards