user

Domain-Driven Design

Introduction

user

Naresh Bhatia

Naresh is a software architect in the Boston area. He started Archfirst after realizing that technologists spend too much time fighting technologies instead of solving real-world problems. Archfirst is a place where we can all learn best practices and techniques to make software development easier.


LATEST POSTS

JoinJS – An Alternative to Complex ORMs 10th August, 2015

MyBatis vs. Other ORMs 01st July, 2015

Domain-Driven Design

Posted on .

The Domain Layer

This layer is the heart of the application. It consists of entities, value objects, domain services and domain events.

Entities

We talked about entities earlier in the Domain Model section. When it is important to distinguish an object from all other objects in the system, it should be designed as an entity. An entity will always have a unique identifier. Bullsfirst contains several entities such as User, Account, Transaction, Order and Lot. Accounts are particularly interesting because there are two types of accounts: BrokerageAccounts and ExternalAccounts. The diagram below shows how these entities are implemented, pulling common state and behavior into BaseAccount.

Account Entity

Note that the Command-Query Separation pattern has been applied to these entities. I use the template shown below as a starting point to code my entities – it helps me think in terms of commands, queries and the supporting code that I need to make my entities work.

public class BrokerageAccount {
    // ----- Constructors -----

    // ----- Commands -----

    // ----- Queries -----

    // ----- Attributes -----

    // ----- Getters and Setters -----
}

Constructors, Commands and Queries are the most important elements of an entity. So I define them at the top. Attributes, getters and setters are really implementation details and hence they are placed at the bottom. Ideally I would like to have no setters in my entities (all changes should be made through commands), but practically, I was not able to do it due to possible limitations in Java Persistence API (JPA) (field-based access was triggering compilation errors). As a compromise, I have made all the setters private.

Value Objects

We talked about value objects earlier in the Domain Model section. An object that represents some descriptive aspect of the domain, but has no conceptual identity is called a Value Object. A good example of a value object is Money.

Money

Domain Services

Some aspects of the domain are not easily mapped to objects. The best practice is to declare these as Domain Services. Domain Services are distinct from Application Services – unlike Application Services, they do contain business logic. The best example of a Domain Service in Bullsfirst is the MatchingEngine (in the Exchange) – it contains business logic to match orders and execute trades. This logic does not naturally belong inside the Order because we need to apply this logic across many orders.

Matching Engine

A good Domain Service has three characteristics:

  1. The operation relates to a domain concept that is not a natural part of an Entity or a Value Object.
  2. The interface is defined in terms of other objects in the domain model
  3. The operation is stateless.

Domain Events

A Domain Event is a simple object that represents an interesting occurrence in the domain. Domain Events help decouple various components of an application. The diagram below shows the Domain Events used in Bullsfirst Exchange.

Domain Events

As an example, the MatchingEngine publishes a MarketPriceChanged event when the price of a security changes as a result of matching orders. This event is caught by MarketPricePublisher, which publishes the price change to external systems. This approach decouples the MatchingEngine from external interfaces.

Aggregates

In any realistic domain, entities are related to one another. In the case of very complex domains, it is easy to end up with an unmanageable tangled web of relationships. Moreover, these complex relationships trigger high degree of database contention, resulting in poor performance or even deadlocks. What we really need is some guidance on organizing complex relationships. Aggregates provide this guidance.

An Aggregate is a group of associated objects acting as a unit for the purpose of data changes. One object within the aggregate is designated as the root – it is usually the “owner” of all the other objects. The root is the only member of the Aggregate that outside objects are allowed to hold references to. Thus outside objects can call methods of the root, giving it commands and querying for information. When the root needs to send information back, it returns Value Objects. I personally prefer a little more flexibility and don’t mind returning internal objects as long as long as they are used for querying.

A good example of an Aggregate within Bullsfirst is the collection of BrokerageAccount, Transaction, Order and Lot.

Brokerage Account Aggregate

In this example, BrokerageAccount is the aggregate root – it “owns” Transactions, Orders and Lots. Objects outside the aggregate only have access to its root. They can affect the internals only via commands sent to the root.

Pages: 1 2 3 4 5 6 7 8

profile

Naresh Bhatia

Naresh is a software architect in the Boston area. He started Archfirst after realizing that technologists spend too much time fighting technologies instead of solving real-world problems. Archfirst is a place where we can all learn best practices and techniques to make software development easier.

Comments
  • user

    AUTHOR Ilya

    Posted on 6:56 am March 25, 2015.
    Reply

    > BrokerageAccount is the aggregate root – it “owns” Orders or Transactions.

    But the collections of orders/transactions will grow unbounded eventually. What will you do in that case?

  • user

    AUTHOR Naresh Bhatia

    Posted on 7:30 am March 25, 2015.
    Reply

    Good point! To take care of this situation, I would break Orders and Transactions into seperate aggregate roots. This is not to take care of the read situation, but more of the write situation. A write must be transactional and must keep the aggregate consistent. With too many Orders and Transactions in the Account aggregate, we will run into version conflicts. This can be easily avoided by breaking Orders and Transactions into their own aggregate roots. In case of reads, we can always join as many entities we want and limit the results, so that’s not an issue – this follows from the Command Query Separation principle. Hope this clarifies.

  • user

    AUTHOR Matt

    Posted on 4:14 am March 26, 2015.
    Reply

    I am curious how this would fit in with Micro Services?

  • user

    AUTHOR Naresh Bhatia

    Posted on 10:58 pm March 29, 2015.
    Reply

    Good question, Matt. I would say that DDD is very compatible with micro services concepts. The micro services architecture style recommends breaking a large monolithic application into smaller services that communicate via lightweight mechanisms such as RESTful interfaces. This is analogous to the DDD concept of breaking a large domain into smaller sub-domains and drawing explicit boundaries around them, known as “bounded contexts”. Within each bounded context the domain terms have specific meaning. However they could have slightly different meanings across bounded concepts. For example, the term “Customer” may have a different set of attributes in the Order system vs. the Customer Support system. The analog of this in the micro services approach would be to break a large e-Commerce system into smaller micro services, an Order service to manage orders and a Customer Support service to manage support requests.

    For a detailed treatment of bounded contexts, you can refer to “Implementing Domain-Driven Design” by Vaughn Vernon (listed at the end of this post).

  • user

    AUTHOR Sridhar

    Posted on 12:17 pm April 7, 2015.
    Reply

    Great work and love reading through the documentation.
    To understand your domain model better do we have a class diagram that we can refer to? Of course I can download the source code and view it from eclipse but wonder if you have already prepared one.

  • user

    AUTHOR Naresh Bhatia

    Posted on 1:16 am April 8, 2015.
    Reply

    Sridhar, glad to know that you liked the work. I do have the full domain models for the OMS and the Exchange, but didn’t get the time to publish them yet. Will try to do it over the weekend.

  • user

    AUTHOR Nico Nel

    Posted on 2:38 am April 12, 2016.
    Reply

    For someone that have been “aware” of DDD for a very long time and “thought” he know a good bit about it, but only recently really started digging into the various aspect of design (software, ux, etc) this is the best article I’ve read on the topic (and I’ve read a LOT lately while waiting for my blue book)
    Please share this, it’s really easy to follow for all levels of expertise and every stakeholder should gain this kind of understanding of the topic.

  • user

    AUTHOR Vijay Gupta

    Posted on 1:07 pm September 19, 2016.
    Reply

    This is really a great article to understand the DDD. I was struggling to understand the DDD and read few online references but was not satisfied with my learning. This article provide complete picture of DDD in very concise, to the point manner.

    Many Thanks.

  • Leave a Reply

    View Comments (9) ...
    Navigation