DEV Community

Axel
Axel

Posted on

Domain-Driven Design - Part 2 - Tactical Design

Introduction

In the first part of the series we talked about the Strategic Design. We saw the subdomain types, ubiquitous language, bounded context and integration patterns.
Now, we need to deep dive into the Tactical Design which is the "technical" part of the DDD concept.

Building blocks

  1. Value objects - Structural equality and Immutable
    The value object is a small object that represents a simple entity whose equality is not based on identity but on value. Value objects are immutable, meaning their state cannot be changed after they are created.

  2. Entities - Identifier equality and mutable
    Entities are objects that have a distinct identity that runs through time and different states.
    Unlike value objects, entities are mutable and their identity (i.e: an identifier in UUID) is more important than their attributes.

  3. Aggregates Root - Type of entity and mutable
    An aggregate is a type of entity (act as a transactional boundary) that has an explicit identifier (i.e: an identifier in UUID) and whose state is expected to change over its lifecycle. The purpose of the aggregate pattern is to ensure the consistency of the data within the aggregate as one atomic transaction.

  4. Domain services - Stateless service
    A domain service is an object devoid of state that encapsulates the business logic. Typically, it orchestrates interactions between different components within the system to execute calculations or analyses.

  5. Domain events - Event occurs in the business domain
    A domain event is an event that describes a change in a business domain.

{
  "eventType": "FlightScheduled",
  "eventPayload": {
    "FlightID": "AA1234",
    "Origin": "JFK",
    "Destination": "LAX",
    "DepartureTime": "2024-06-01T08:00:00Z",
    "ArrivalTime": "2024-06-01T11:00:00Z",
    "Status": "Scheduled"
  },
  "eventTimestamp": "2024-05-21T10:00:00Z"
}

Enter fullscreen mode Exit fullscreen mode

Architectures

There are various ways to implement application architecture.
Below, you will find two types of application architecture that you can use.

First one is the Layered Architecture and the second one the Hexagonal Architecture.

Layered Architecture

Layered Architecture

User Interface / Presentation Layer
It is the interface for interactions with customers (e.g : Web UI, CLI, REST API).

Application / Service Layer
The service layer functions as a bridge between the presentation layer and the business logic layer of the application.

Model / Domain / Business Logic Layer
This layer is responsible for implementing and encapsulating the application's business logic. It is where business decisions are executed.

Infrastructure / Data Access Layer
This layer integrates the Persistence Systems. In modern systems, it can be used for databases (DynamoDB, RDS, etc.), message buses (SQS, SNS, etc.), or object storage (S3, Azure Blob Storage, etc.).

Hexagonal Architecture

Hexagonal Architecture

Business Model / Domain
This is the heart of the application, encompassing all the business rules and logic. It operates independently and does not depend on any external systems.

Application
Ports act as gateways for communication, functioning as either inbound or outbound ports.

  • Inbound ports : Like a service interface, exposes the core logic to the outside world.
  • Outbound ports : Like a repository interface, enables communication from the application to a persistence system.

Infrastructure
Adapters function as implementations of ports, handling user input and converting it into language-specific commands. They contain the logic for interacting with external systems like message queues and databases, facilitating communication between external entities and the core logic.

Adapters come in two types:

  • Primary Adapters or driving adapters: These drive the application using its inbound port (e.g: User interface adapter or REST controllers adapter.
  • Secondary Adapters or driven adapters: These implement outbound ports and are driven by the application (e.g: message queues (SQS adapter), databases (DynamoDB adapter), and external API calls).

Conclusion

Through the tactical lens, we delved into the building blocks of DDD: value objects, entities, aggregates, domain services, and domain events. Each component plays a specific role, from representing immutable values and maintaining entity identity to encapsulating business logic in services and signaling domain changes through events.

Moreover, we explored two principal architectural styles that facilitate the implementation of DDD: the Layered Architecture and Hexagonal Architecture. The Layered Architecture organizes code into distinct layers that separate responsibilities from the user interface down to infrastructure. In contrast, Hexagonal Architecture focuses on decoupling the core logic from external influences, emphasizing portability and adaptability through ports and adapters.

Thank for reading

If you have any questions, feedback, or suggestions, please feel free to leave them in the comments below. I'm eager to hear from you and respond to your thoughts!

Top comments (0)