3. Procedural thinking where Objects are just Plain
data structures devoid of any behaviour, and
behaviour is concentrated in “service” and
“controller” classes.
3
5. “The fundamental assumption of
DDD is that human beings are
incapable of building enterprise
applications, but are capable of
understanding small, well-
bounded problems (a "domain").”
https://visualstudiomagazine.com/articles/2015/07/01/domain-
driven-design.aspx
5
9. Problema:
qual é o princípio geral para a atribuição de
responsabilidades aos objetos?
Solução:
Atribuir a responsabilidade ao information expert
- a classe que contém a informação necessária
para desempenhar essa responsabilidade
9
GRASP
10. class Employee {
private int number;
private double salary;
private List skil = new ArrayList();
...
public int getNumber() { … }
public void setNumber(int n) { … }
public double getSalary() { … }
public setSalary(double s) { … }
public List getSkills() { … }
public void setSkills(List s) { … }
}
10
11. Segregation of the design decisions that are most
likely to change, thus protecting other parts from
extensive modification if the design decision is
changed.
11
12. An object cannot be constructed neither modified
in a way that it does not hold its internal
consistency.
12
13. class Employee {
public Employee()
...
public void setNumber(int n) { … }
public setSalary(double s) { … }
public void setSkills(List s) { … }
}
VS
class Employee {
public Employee(int number, double salary) { ... }
...
private void setNumber(int n) { … }
private void setSalary(double s) { … }
public void addSkill(Skill s) { … }
public void removeSkill(Skill s) { … }
}
13
20. Objects wich rich behaviour in the real world
which we would like to track its identity
Example:
Student identified by Student Number, NIF,
email
Product identified by Product Reference
Sale identified by Invoice Number
20
DDD
21. Class Product{
private ProductID id;
// other attributes of product, e.g., designation,
description, etc.
public Product(String sku, Money price) {…}
public ProductID getProductID() { … }
private void setProductID(string sku) { … }
public boolean equals(Object other) {
if (other==this) return true;
if (!(other instanceof Product)) return false;
return (this.getProductID() ==
(Product)other.getProductID());
}
}
21
Always
constructed in a
valid state
It’s ok to return
one’s identity
No one can change
one’s identity
Object instances refers to
the same real world entity, if
they have the same identity
22. @Entity
Class Product{
// database ID
@ID
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private void setID(Long id) { … }
private Long getID() { … }
// domain ID
private ProductID ref;
public ProductID getProductID() { … }
private void setProductID(ProductID ref) { … }
…
}
22
23. Problem
Some objects matter for the value of its
attributes, e.g., Color
Serve to describe, quantify or classify na Entity
Solution
Create immutable objects which are identified by
the equality of its attributes and do not need an
identity
24
DDD
24. class Color {
private final float red;
private final float green;
private final float blue;
public Color(int r, int g, int b) {…}
public float redPercentage() {…}
public float greenPercentage() {…}
public float bluePercentage() {…}
public boolean isPrimaryColor() {…}
// imutable; creates a new object
public Color combinedWith(Color other) {…}
// equality by value
public boolean equals(Object other) {…}
}
25
26. 27
@Entity
class Color {
// database ID not to be exposed to domain
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
// domain values
private int red;
private int green;
private int blue;
…
// avoid instantiation
private Color() {...}
//factory method
public static Color fromRGB(int r, int g, int b) { … }
}
@Entity
Class Car {
…
@OneToOne
private Color color;
…
}
Factory method hides
the lookup/write to the
DB if necessary.
27. The Domain, SRP and Value Objects
Primitive types are not the best option to represent
domain concepts!
Favour imutability of your objects.
28
Person
«value»
Name
«value»
Address
«value»
NIF
«value»
PhoneNumber
1..*1
1 *
«value»
Email
*
28. Requirement 321:
Passwords must be at least 6 characters longs and
have at least one digit
29
29. @Test
public void ensurePasswordHasAtLeastOneDigitAnd6CharactersLong() {
new Password("abcdefgh1");
}
@Test(expected = IllegalArgumentException.class)
public void ensurePasswordsSmallerThan6CharactersAreNotAllowed() {
new Password("ab1c");
}
@Test(expected = IllegalArgumentException.class)
public void ensurePasswordsWithoutDigitsAreNotAllowed() {
new Password("abcdefgh");
}
30
You are actually
doing design
30. @Test
public void ensurePasswordHasAtLeastOneDigitAnd6CharactersLong() {
Password p = Password.valueOf("abcdefgh1");
}
@Test(expected = IllegalArgumentException.class)
public void ensurePasswordsSmallerThan6CharactersAreNotAllowed() {
Password p = Password.valueOf("ab1c");
}
@Test(expected = IllegalArgumentException.class)
public void ensurePasswordsWithoutDigitsAreNotAllowed() {
Password p = Password.valueOf("abcdefgh");
}
31
Taking decisions on
how the code will
work
31. public class Password {
…
public Password(String password) {
if (!meetsMinimumRequirements(password)) {
throw new IllegalStateException();
}
thePassword = password;
}
private boolean meetsMinimumRequirements(String password) {
if (Strings.isNullOrEmpty(password)
|| password.length() < 6)
|| !Strings.containsDigit(password))
{
return false;
}
return true;
}
32
32. All methods of a domain object should handle
domain entities and value objects only; no primitive
types.
void setName(String name)
vs.
void setName(Name aName)
Provide a convenience valueOf() method to convert
from primitives read from the outside (e.g., UI, DB)
Class Name {
public static Name valueOf(String name) {…}
}
33
33. Problem:
Some business operations are not naturally
placed in a certain domain object
Solution:
Create a service object that handles only that
operation and coordinates the necessary domain
objects.
34
DDD
34. Money transfer between two accounts:
Account.transferTo( Account other,
Money amount
)
vs.
TransferService.transfer( Money amount,
Account from,
Account to
)
35
DDD
36. 1. An object is created
2. The object is used
3. It must be persisted for later use
4. Later, the object is reconstructed from
persistence
5. It is used (provably changed)
6. It is stored back again for later use
7. …
37
37. When creation of an entire, internally consistent
aggregate, or a large value object, becomes
complicated or reveals too much of the internal
structure, factories provide encapsulation.
38
DDD
38. Problem:
How to hide the details of persisting and
reconstructing an object while keeping the
domain language?
Solution:
Query access to aggregates expressed in the
ubiquitous language
Abstract the persistence of an object in a
Repository class that behaves as a list
39
DDD
41. 42
• Remove
unnecessary
associations
• Force traversal
direction of
bidirectional
associations
• Reduce cardinality
by qualification of
the association
we are still left
with a tangle of
interconnected
objects...
42. Some objects are closely related together
and we need to control the scope of data
changes so that invariants are enforced
Therefore
Keep related objects with frequent changes
bundled in an aggregate
control access to the “inner” objects thru one
single “root” object
43
DDD
44. Efficient aggregate design is hard
Imagine the relationship between an account
and its movements
Are movements part of the Account
aggregate?
45
47. 48
Entities,Value objects and Aggregates are
about things
Services are about operations
But, what happens in the system is also
important.
48. Some things that happen in the domain are
worth noting.
Therefore
Model activity in the domain as a series of
discrete events represented as a domain object.
49
DDD
49. A domain event might be of interest to some
object.
Therefore
Make the interested object an observer of the
event’s issuing party.
50
GoF
60. Design Principles and Design Patterns.
Robert Martin.
http://www.objectmentor.com/resources/arti
cles/Principles_and_Patterns.pdf
Applying UML and Patterns; Craig Larman;
(2nd ed.); 2002.
Design Patterns-Elements of Reusable
Object-oriented Software, Gamma et al.
(Gang of Four)
62
Editor's Notes
The hollyhood principle: don’t call us, we’ll call you
After all it is called OBJECT-oriented and not CLASS-oriented
Source: implementing DDD, Vernon Vaugh
Breaks encapsulation
Breaks information hiding
Variation points are not protected, e.g., employee “number” might be a string, or we may want to use LinkedList instead of ArrayList but we can’t without extensive change to the codebase.
Se um objeto é o information expert de um dado tópico (informação), não tem nada que dar essa informação a outras para que esses outros façam “as contas”
The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change).
Information expert
Getters and setters are evil
Construct objects only in avalid state
Beware of empty constructors and atomic setters when things need to change in clusters
Intention Revealing Interface
Os objetos são preguiçosos: fazem o mínimo possível e delegam o máximo possível
https://www.websequencediagrams.com
title calculating the total for an order (procedural)
App -> Order : getPrice()
loop for each item
Order->OrderItem: getQuantity()
Order->OrderItem: getProduct()
Order->Product:getPrice()
Order->Order: sum()
end
https://www.websequencediagrams.com
title calculating the total for an order (Object Orientation)
App -> Order : getPrice()
loop for each item
Order->OrderItem: getPrice()
OrderItem->Product:getPrice(quantity)
Order->Order: sum()
end
Método equals para verificação de igualdade (e não identidade)
Existência de vários concstrutores
Vários métodos de “query” mas nenhum de “comand” (mutators)
Operações não alteram o conteudo deste objecto mas sim retornnam novos objectos
-- ver método combinedWith
-- reparar no nome do método: “combined” e não “combine”
Método equals para verificação de igualdade (e não identidade)
Existência de vários construtores
Vários métodos de “query” mas nenhum de “command” (mutators)
Operações não alteram o conteúdo deste objeto mas sim retornam novos objetos
-- ver método combinedWith
-- reparar no nome do método: “combined” e não “combine”
Still need to hold to all value objects characteristics: imutability, …
Factory methods might be in the Repository class
Extrato faltam aqui alguns métodos. Devem ver o código fonte completo
After reducing and simplifying associations we are still left with a tangle of interconnected objects.
Other objects are not allowed to have references to “inner” objects of an agregate, only to its root
The model must be practical
they can serve as a trace to what have happed, why an entity is in a specific state, or other objects might be interested to perform some other action.
Events should have meaningfull names based o the domain
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically
“Global” event listener
note left of O: subscribe to future events
O -> +Dispatcher: subscribe(eventType)
Dispatcher --> -O:
note over Ctrl, P: during program execution
Ctrl -> +P : func()
P -> P : ...
P -> *e Event: create
P -> Dispatcher:publish(e)
P --> -Ctrl:
note left of Dispatcher: asynchronously notify subscribers
Dispatcher -> O: handle(e)