02 DDD

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 107

Domain-

Driven Design
Maurício Aniche
Software Architecture
March/2019
Delft University of Technology
Cool! Let’s start with a cool No-
SQL database, and Redis for
caching, and Kafka for streaming,
and Play! Framework, and REST
APIs, and …
Manufacturing

Billing / Payments

E-learning
”Yet the most significant
complexity of many
applications is not technical. It
is in the domain itself, [...]”

Eric Evans
Tackling complexity in the
heart
of the software
What is a model
?
Both are good
models…
They just model
different things.
You were just

hired
as Software Architect by
AwesomeStuff, B.V.!
AS

Let’s model the


shopping process
of our software!
st o m e r
e n to ry C u
In v
Deliver O rd er
y
y m e n t
P a
Custom
Satisfa e r
ction
Personal note: source in https://www.lucidchart.com/documents/edit/5813d622-920c-4a43-8325-3497a3527066/0
We only store the
current inventory
The same order can
be delivered
in different dates
Satisfaction is about
Orders, and not
about Products.
Is it Item or Product?
How do you deal with
complex entities?
User and its
Aggregates
Infrastructure and
domain model
Modelling can be quite

challenging .
Let’s talk about four things:
1) We should better understand
the business.
2) Different concepts require
different modelling.
3) We have “multiple domains in
one”.
4) The importance of a common
language between devs and
business experts.
It’s hard to model the “now”.
We don’t see the
action/reaction!

generates
Order Payment
What if we think about
business events?
Order Payment
placed completed
Item
removed
from
Past tense!
inventory
Order Perform
placed Payment

Reactions!

Payment Payment
refused completed
“This happens whenever that happens!”

Reaction! Event!
Order Perform
placed Payment

Payment
External systems!
Gateway
Submit Commands!
order

Order Perform
placed Payment

Payment
Gateway
Event Storming

Figure: https://blog.redelastic.com/corporate-arts-crafts-modelling-reactive-systems-with-event-storming-73c6236f5dd7
“Things happen. Not all of them are
interesting, some may be worth
recording but don’t provoke a
reaction. The most interesting ones
cause a reaction. Many systems
need to react to interesting events.
Often you need to know why a
system reacts in the way it did.”

https://martinfowler.com/eaaDev/DomainEvent.html
“Things happen. Not all of them are
interesting, some may be worth
recording but don’t provoke a
reaction. The most interesting ones
cause a reaction. Many systems
need to react to interesting events.
Often you need to know why a
system reacts in the way it did.”

Search for event-driven


architectures!
https://martinfowler.com/eaaDev/DomainEvent.html
Modelling can be fun!
If the payment fails, we should
send an e-mail to the user, so
that she can try again.
Ok. We create a batch job that
will perform a SQL query. We
then do a loop and send an e-
mail for each customer in this
situation.
Batch job? SQL? Whatever.
Also make sure that, if it fails
more than two times, we don’t
send e-mails anymore.
Ok, we can have like a Boolean
column on the table schema to
store such information.
Boolean? Schema? Freak…
What is
wrong
with this
conversation?
Ubiquitous
Language
• The model is also a language. Used to
communicate among all members of the
team.
• We need people speaking the same
language.
• Should exist in code, diagrams, and
communication.
• Can't be good from the start.
• Be persistent. Weaknesses will appear.
• Rename your code to match the UL.
If the payment fails, we should
send an e-mail to the user, so
that she can try again.
Ok. We create a FAILED
PAYMENTS NOTIFICATION
SERVICE that will do it every 10
minutes.
Nice! Also make sure that, if it
fails more than two times, we
don’t send e-mails anymore.
Ok, we can store this as part of
our ORDER entity, as I suppose
this happens for each order,
right?
Precisely! We do speak the
same language!
If sophisticated domain
experts do not understand
the model, there’s
something wrong with the
model.
Bind the model and
the implementation!
We have a lot of
terminology here!!
(some awful language behind the scenes)
Something could be better…
There’s probably a

business term
for that!
Code is more

domain-driven .
User Interface Layer
Application Layer
Domain Layer
Infrastructure Layer
Can you see
advantages (or
disadvantages)
Of a Layered
Architecture?
An isolated domain layer enables us to:
• Better test the model
• Reuse the model
• Reduce problems with external
infrastructure
• Easy to find ”where to code”
• Less expensive to maintain because
they tend to evolve at different paces
and respond to different needs
(Fowler, 1996)
Separate infrastructure from
the domain is the challenge!
(Your framework should help you, and not
distract you from developing a good
model.)
DDD patterns understand that
systems rely on (external)
infrastructure!
Not every element in our
model is the same. Different
elements require different
treatment.
Order has an
identity and should
be the same
throughout the
business life cycle.
Order is an

Entity!
Entities have
actions.

Actions change
the state of the
Entity.
It needs an Identity
• Avoid pointer
comparison
• Is there a true key?
• ISBN for books
• If not, create one.
• When distributing,
make sure the ID is
unique among systems.
You should avoid
anemic models
(behavior and state in different places)
The challenge is to
find the right entity
that the behavior belongs to
Is this an
Entity?
• ”Tracking the identity of ENTITIES is
essential, but attaching identity to other
objects can hurt system performance,
add analytical work, and muddle the
model by making all objects look the
same.”
• ”Software design is a constant battle
with complexity. We must make
distinctions so that special handling is
applied only where necessary.”
This is a
Value Object!
Is Address always a Value
Object?
It depends… ;)
No bi-directional relationship
with VOs and Entities!

1
User Address

Class User { Class Address {


private String name; private String street;
private Address address; private Address city;
private List<User> users;
// …
// …
}
}
Quick quiz:
Where would you place the Satisfaction behavior?
(the user gives a star rating to the entire order)

User#satisfaction(Order, int) Order#satisfaction(int)


Quick quiz:
Where would you place the Perform Payment
behavior? (talking to a payment gateway, …)

Payment#perform(Order) Order#pay()
”When a significant process or
transformation in the domain is
not a natural responsibility of
an ENTITY or VALUE OBJECT,
add an operation to the model
as a standalone interface
declared as a SERVICE. […],
make sure the operation name
is part of the UBIQUITOUS
LANGUAGE.”
• The operation relates to a domain
concept that is not natural part of
an Entity.
• The interface is defined in terms of
other elements of the domain
model.
• The operation is stateless.
This is a PerformPayment

Service! makes use of consumes

Payment Order AdyenWebService

class PerformPayment {

public PerformPayment(AdyenWebService) { /* … */ }

public void pay(Order order) {


// connect to Adyen It does
// manipulate entities not fit any
// generate PaymentLog
} Entity!
}
Again: You should avoid
anemic models
(aka If you only have SERVICES,
maybe your model is anemic)
Order
- totalAmount
- amountLimit
Has many Has many

Item Discount
- product - apply()
- quantity
- price

… In complex domains,
Entities have
complex associations
Order
- totalAmount
- amountLimit
Has many Has many

Item Discount
- product - apply()
- quantity
- price
Who makes sure that

… the amountLimit is
respected?
<< aggregate root>>
Its root!
Order
- totalAmount
Any party - amountLimit
Has many Has many

Item Discount
- product - apply()
- quantity
- price

This is an
Aggregate!
• The root has global identity.
Boundaries have local identity.
• Root is ultimately responsible for
checking invariants.
• Nothing outside the Aggregate
boundary can hold a reference to
anything, except to the root.
• Objects within the Aggregate can
hold references to other Aggregate
Roots.
• A delete operation must remove
everything within the Aggregate
boundary at once.
• When a change to any object
within the Aggregate boundary is
committed, all invariants of the
whole Aggregate must be satisfied.
• Avoid bi-directional associations.
• Maurício: They are messy in ORMs
• Impose a traversal direction.
• Remove non-essential associations.
• Remember: the model should not
match reality.
• Constrain relationships as much as
possible.
• Be simple.
We will
eventually need
to persist our
data
Our
database
Order
Repository consumes
Our
- Add(Order) database
- List<Order>
allOrders(Customer)

Repositories provide an illusion


of an in-memory collection of all
objects of that type.
• Decouple the domain from the
persistence technology.
• Provide Repositories only for Aggregate
roots.
• The interface should only deal with
domain objects. Methods should
return domain objects only.
• Leave transaction control to the client.
• Repositories should be reflected in the
UL.
The domain should not know
your infrastructure. But you
should!
Database or OOP? Sacrifice in
both ways:
• Sacrifice richness of OOP to
keep close to relational model
• Sacrifice some formal
relational standards to simplify
the object mapping.
Is the Customer, the same entity
to the entire model?
(let’s say, to financial and to marketing?)

Customer Customer

Customer
Customer
Multiple models are in play on any large
project. Yet when code based on distinct
models is combined, software becomes
buggy, unreliable, and difficult to
understand. Communication among team
members becomes confused. It is often
unclear in what context a model should
not be applied.
We may have different bounded contexts!

Figure: https://martinfowler.com/bliki/BoundedContext.html
• Explicitly define the context within which a
model applies.
• Explicitly set boundaries in terms of team
organization, usage within specific parts of
the application, and physical
manifestations such as code bases and
database schemas.
• Keep the model strictly consistent within
these bounds, don't be distracted or
confused by issues outside.
How can I integrate
with a (legacy) When a new system is
system that has a being built that must have a
large interface with
bad design model? another, the difficulty of
relating the two models can
eventually overwhelm the
intent of the new model
altogether.
Thanks,
Anti corruption layer!

Legacy New system

Your legacy
shall not pass!
Give a decent interface to
your anticorruption layer
so that in the future it can
be simply removed from
the system.
• The book is full of other
patterns, both technical
(Factories, Specifications,
…) and strategical.
• Event-driven architectures
and CQRS are getting
popular.
The “how” is tricky!!


Aniche, Maurício. What do we (not) know about DDD? https://codeburst.io/what-do-we-not-know-about-ddd-93727bc5908c, 2017.
Tackling complexity in the
heart
of the software
Further reading
• Alberto Brandolini (inventor of Event Storming):
https://www.youtube.com/watch?v=1i6QYvYhlYQ.
• Microservices or Modules?: https://www.oreilly.com/ideas/modules-vs-
microservices
• Anemic Domain Models:
https://martinfowler.com/bliki/AnemicDomainModel.html.
• Context Mapping: https://www.infoq.com/articles/ddd-contextmapping
• Eric Evans about Microservices:
https://www.youtube.com/watch?v=yPvef9R3k-M.
• Emergent Boundaries, from Mathias Verraes:
https://www.youtube.com/watch?v=ECM1rPYxvD4.
• Towards Modelling Processes, from Mathias Verraes:
http://verraes.net/2015/05/towards-modelling-processes/.
• Modelling reactive systems with event storming:
https://blog.redelastic.com/corporate-arts-crafts-modelling-reactive-
systems-with-event-storming-73c6236f5dd7.
License
• You can use and share any of my material (lecture
slides, website).
• You always have to give credits to the original
author.
• You agree not to sell it or make profit in any way
with this.

• Material that I refer has its own license. Please


check it out.
References
• Aniche, Maurício. What do we (not) know about DDD?
https://codeburst.io/what-do-we-not-know-about-ddd-
93727bc5908c.
• Evans, Eric. Domain-driven design: tackling complexity
in the heart of software. Addison-Wesley Professional,
2004.
• Marinescu, Floyd, and Abel Avram. Domain-driven
design Quickly. Lulu. com, 2007.
• Curtis, Bill. "Fifteen years of psychology in software
engineering: Individual differences and cognitive
science." Proceedings of the 7th international
conference on Software engineering. IEEE Press, 1984.

You might also like