Implementing DDD

By | June 28, 2013

A while ago a took the “Implementing DDD” course with no less then Vaughn Vernon (@VaughnVernon) and Patrik Fredriksson (@weakreference) at Citerus. Vernon has written the book with the same name as the course.

Here is my notes from that course.


Disclaimer: This is my notes and my interpretation of the information. I can really recommend going the course.

Day 1

Part 1: Introduction

The expectations was high and after a short round robin introduction of the participants we were ready to go.

Vernon presented what will be in the course by taken a short introduction to Aggregates, Repositories, Services, Domain events, Entities and Value objects.

We were going to hear about how we can integrate the different context with each-other without increasing the complexity. How to use model naming strategies when modelling it by the ubiquitous language.

For those who was unfamiliar with domain events, since it’s not explicit mentioned in [Evans] book, here is a short introduction.

Domain events are created by the aggregate and published to the event publisher that delivers it to the subscribers. This can be seen as a publish-subscriber pattern or observer.

Benefits with domain events:

  • Domain events can be used to keep a record of what have happen in the domain.
  • Domain events can also ease the integration between different (sub-) domains.

Part 2: Bounded Context and the Ubiquitous language

This is DDD. The bounded context and the Ubiquitous language is the most important part of DDD. The thing to take with you from this day is the Bounded Context and the Ubiquitous language. It is the foundation of DDD.

Observe that expert thinks of the domain and usage while developers tend to thinks of code and technical stuff. So have a feedback loop between the developer and the expert.

wpid-Feedback-loop_01.jpg

Remember to always involve the Experts!

So what can be inside a bounded context?

  • Domain model
  • Service interfaces: RPC (SOAP), Rest, Messaging
  • User interface components
  • Application services/command handler
  • Database schemas

The word domain is somewhat overloaded (which domain are we talking about). The Domain in the whole business that is helping the business forward. The parts that builds up the domain are sub-domains.

To map the domain you must start with defining the problem space and solution space. The problem space is the context, and the solution space is the domain.

Start with defining what your core domain is. The Core domain is the sweet-spot of our system. The core is often supported by sub-domains. But your core domain can be another teams sub-domain. So there can be different perspective in the view of the domain between different teams.

Remember that multiple sub-domains can belong to the same bounded context. But try to only have one bounded context per (sub-) domain.

Try to keep your core domain as clean as possible using the single responsibility principle. Try to identify possible sub-domains that can be moved out of the core domain. This can be done using linguistics to identify sub-domains (terms that do not fit in the current core domain).

Always remember that context is King! You need to know your context to know the meaning if the model.

To handle legacy system aka BBoM (Big Ball of Mud). Try to map sub-domains to the BBoM (Big Ball of Mud) to visualize what’s there. This is a great way to visual the vision of how we want the end result to be (even if it’s not possible to reach in polynomial time).

Part 3: Context mapping

Use context mapping to describe the relation between different contexts. Especially defining what are upstream and downstream in the relation. Upstream serve the downstream, think of it as a river metaphor, making the downstream dependent of what the upstream produces and offers.

Partnership

  • Upstream and downstream dependencies are equal
  • No one can create value on there own
  • If one fail all fails

Shard kernel

  • A shard (sub-) domain between different teams
  • Needed by more the one team
  • Hard to maintain

Customer-supplier

  • Upstream can create value of there own
  • Upstream supplies the downstream
  • Downstream must request changes from the upstream team
  • Downstream must conform to upstream changes => conformist or different ways

Conformist

  • Downstream must conform to upstream changes and upstream leaves the downstream helpless

Anti-corruption layer

  • Translate other system model to match your needs
  • Isolate your domain to prevent leaking of other domains

Open-Host service

  • A protocol published to let you talk to other services

Published language

  • A common translation between two (or more) bounded contexts
  • Often combined with an Open-Host service

Separate ways

  • Create your own model and leave the other context/sub-domain

Big Ball of Mud

  • The name says it, stay away from it if possible

Part 4: Architecture

  • Classic architectural styles
  • Enduring architecture

Layers
Using the dependency inversion principle to manage the call hierarchy and loosen the coupling to other parts such as storage. This can be done by defining the persistence storage access as interface in the domain and placing the actual implementation on top of everything by using DI.

Hexagonal (Ports and adapters)
Define input and output ports to communicate on. Use one port per client type and let the application layer handle the conversion and calls to the domain services.

CQRS
Separate query and command (view and action). Making every command doing exactly one thing. Retrieve the new view to see the changes making the model having separated write and read. The command should never change the state directly of the part that is retread when reading.

Pipes and filters
Look at it as pipes in *nix systems. Where every command is a filter that changing the data and every pipe forwards the result between the commands. In the same way we can implement a system where every filter do computations on the data and the pipes sends it to the next filter.

Actor model
Messaging between aggregates (See Akka (JVM), Scala (JVM) or ActorFX (MS)).
Think of it the internet where every computer is an actor. Every actor can communicate with every actor. The actor state can be recreated form all events that it has received and the events are persisted when the event is received. This makes the model robust when the actor can be recreated at any time to receive a new event.

wpid-Actor-model_01.jpg

Quote of the day

In short, code what you mean.
Tell, don’t ask objects what to do.
Use roll-based access to the system.

Further reading

Responsibility-Driven Design by Rebecca J. Wirfs-Brock
Dependency inversion principle by Martin Fowler

Actor Frameworks:
Akka and Scala for the JVM and ActorFX for the MS platform.

Day 2

Part 5: Entities

  • Using DDD tactical design
  • Avoid Entity-think and entity overuse
  • Unique identity and construction
  • Designing intrinsic qualities and characteristics

Use entities when:

  • An identified instance may change over time

Entity-think = bad
Don’t think of every thing as an entity

Unique identity

  • User provides an identity (must ensure its uniqueness)
  • Application generates the unique identity
  • Persistence store generates an unique identity
  • Another bounded context provides the unique identity

Order can matter when the entity gets the unique identity.

Early
The identity is provided by the user or application. It can be managed with a surrogate identity to prevent inconsistency in the persistent storage.

Late
The identity is given to the entity when it is stored in the persistence storage.

Validation

  • Validate properties in setters.
  • Validate whole object can be done using a special validator eg. ProductValidator.
  • Validate deferred may involve other objects eg. single object is fine but the whole model fails due to some constraint.

Part 6: Value Objects

  • DDD Tactical design prefers value objects over entities
  • The common characteristics of value objects
  • Integrate with minimalism and design standard types
  • Persistence considerations

Value-think = Good
Choosing between a Value object or entity depends of the context but favour Value Object over Entities.

Immutable and Replaceable
Private setters for validation, public “getter” but ignore the get part and express the getter with the ubiquitous language.

Use methods for modifications but return a new object instead such as the Javas String substring method.

Part 7: Services

  • Domain services are not SOA or Application services
  • When to model a Domain service
  • Sample Domain services

Domain services may

  • Dispatch to the model
  • Be double-dispatched by and from the model

Domain services in the architecture

wpid-Domain-services-in-the-architecture_01.jpg

Domain services is

  • Lightweight
  • Stateless operation
  • Not transactional

Needed if

  • No natural operation home
  • Force-fit on entity
  • Wants to be static

Part 8: Domain events

  • Collecting the facts about your domain by use of events
  • Publish events in your application and beyond
  • Modelling events and event-driven modelling

When and way
Listen for:

  • When
  • If it happens
  • Notify me

The end of Batch? It can reduce the batch window when we gets notifications of when things happens in the system.

PubSub
Acronym for Publish Subscribe

Facts forever (event sourcing).
wpid-Event-sourcing_01.jpg

From the events that are handled you can create a glossary over the events.

Bounded Context Event Name Origin Description
Authorization Login Authentication Dispatched when a user log-in into the system.

Further reading

Checks pattern language by Ward Cunningham

Day 3

Part 9: Modules

  • Modules do’s and don’t – Practical guidelines
  • High level modules and modules in the model
  • Other areas of the application

Simplest form Java packages and C# namespaces

Do

  • Design modules to fit modelling concepts
  • Typically a model for one or a few aggregates that are cohesive, if only by reference
  • Name modules per the ubiquitous language
  • Design loosely coupled modules
  • Strive for acyclic dependencies between modules
  • Relax the rules a bit between child and parent modules

Don’t

  • Create modules mechanically according to a general component type of pattern
  • Make modules a static concept of the model, but allow the to moiled with the objects

The name of the module should be something useful but not to long

eg.

com.sassovation.identityaccess.domain.model
com.sassovation.agilepm.domain.team

<< service >>
com.sassovation.agilepm.domain.team.MemberService

<< aggregate root >>
com.sassovation.agilepm.domain.team.ProductoOwner
com.sassovation.agilepm.domain.team.Team
com.sassovation.agilepm.domain.team.TeamMemeber

com.sassovation.agilepm.domain.product
<< aggregate root >>
com.sassovation.agilepm.domain.product.Product

com.sassovation.agilepm.domain.product.backlogitem
<< aggregate root >>
com.sassovation.agilepm.domain.product.backlogitem.BacklogItem

com.sassovation.agilepm.domain.product.release
<< aggregate root >>
com.sassovation.agilepm.domain.product.release.Release

Other areas of the application

com.sassovation.agilepm.resources // Rest
com.sassovation.agilepm.resources.view // UI

com.sassovation.agilepm.application.product // Application services and commands
com.sassovation.agilepm.application.team
com.sassovation.agilepm.application.tenent

Modules before creating a new bounded context

Part 10: Aggregates

  • Part 1: Common pitfalls of aggregate design
  • Part 2: Follow the rules of aggregate domain (mostly) design
  • Part 3: Reimplementing the BacklogItem design

Every aggregate have a root entity. The root entity must have global unique identifier.
By design every aggregate must be transactional.

Part 1 – Common pitfalls

  • Focus on object graphs and navigational convenience
  • Imagine incorrect invariants (consistency constraints)
  • Tune persistence to support previous two pitfalls

wpid-large-aggregate_01.jpg
Large cluster aggregate object graph.

Positive: Navigational convenience for model client
Negative: Transactional failures
Negative: Size and performance

Incorrect invariants

Invariants say: When this object changes that object must also change.

wpid-Incorrect-invariants_01.jpg

Imagine false business constraints
Aggregate design are influenced by wrong assumptions often lead to large-cluster aggregate problems.

Tune persistence
wpid-Tune-Persistnce_01.jpg

Force persistence mapping to fit large-cluster aggregates. Enabling large-cluster aggregates leads to some issues still leads to performance and scalability issues.

Aggregate boundaries are for transactional reasons. So persisting a aggregate is a atomic action.

Rule: Model true invariants in consistency boundaries.

Aggregate boundaries for invariants

Rule: Design small aggregates

wpid-not-small-aggregate_01.jpg
This is not small a small aggregate.

Don’t trust every use-case.
wpid-Dont-trust-every-usecase_01.jpg

Use Eventual consistency to manage a situation where an aggregate might affect another aggregate.

Part II
How many aggregates are there in this picure?

wpid-How-many_01.jpg
Ans: 2 aggregates

Rule: Reference by identity

Should aggregates use repositories?
Rule of thumb: No.

Rule: Use eventual consistency outside the boundary [Evans, p128]

Ask who’s job it is
Transactional or eventual consistency?
Is it the job of the user – Transactional
Is it the job of another user or system – Eventual consistency

Reason to break the rules

  1. User interface convenience
  2. Lack of technical mechanisms
  3. Global transactions
  4. Query performance

Adhere to the rules and only break them with a good reason.

Part III
Model the BacklogItem in the sassovation agilepm application. See the book.

Part 11: Factories

Motivations for using factories in the model. See the book.

Part 12: Repositories

  • Collection oriented repositories
  • Persistence oriented repositories
  • Look at sample repositories

Collection oriented eg. java collection (Set). Can be used with a document based database eg. MongoDB.

Use one repository per aggregate. And try to not call repositories from aggregate, use a domain service instead.

Part 13: Integrate the bounded context

If all context provides an open host service through eg. REST it is easy to integrate other context with that one using a small anti-corruption layer.

See the book and look at the example code for more information.

Part 14: Application

Designing the application with regards to

  • Application without architecture
  • User Interface
  • Application services

wpid-Application_01.jpg

Common things to think about.

  • Render DTO from aggregate instance
  • Use a mediator to publish aggregate internal state
  • Render aggregate instance from domain payload object
  • State representation of aggregate instance
  • Presentation model
  • Use-case and optimal query (CQRS)
  • Using commands

Workshop: Walk-through of parts of the example code

Futher Reading

Programming Pearls, second ed. by Jon Bentley
Life Beyond Distributed transactions by Pat Helland
Example code by Vaughn Vernon

Idempotent = Side effect free (wikipedia).

Question

To implement a Event Sourcing model (to be extended as an actor model). How must I store the events to let them recreate the state of the aggregates?

Answer

You have to store each event together with the id for the root entity for the aggregate. Use this id as a key to retrieve all the events that has affected the aggregate.

Leave a Reply

Your email address will not be published.