Simple to conceive associations between objects but difficult to implement
There are three patterns of model elements: entities, value objects and services
Associations
"For every traversable association in the model, there is a mechanism in the software with the same properties"
For example, an association between a customer and a sales representative reflects both a conceptual relationship and physical implementation, much like a reference between two objects in code
Implementation of relationships aren't always direct, the design must account how relationships are traversed in the system
Many models of relationships are many-to-many and bi-directional, which are complex, hard to maintain and don't convey much about the actual nature of the relationship
There are strategies to simplify relationships:
Impose a direction: Decide which side of the relationship is primary and make it uni-directional (ex. from country to president, not the reverse)
Add a qualifier: Reduce complexity by constraining the association (ex. only one president per country)
Eliminate unnecessary associations: Remove relationships that don't make sense
Adding constraints such as limiting the number of valid relationships can make associations easier to implement and understand
In some cases, bi-directional associations may be necessary but can often be constrained further to simplify the model
Entities
Many objects are defined by their identity rather than their attributes
For example, a person's identity persists even though their address or name may change
An entity like a user may exist across different systems, potentially with different attributes
The identity must remain consistent to avoid issues like duplication and mismatched data
Not all objects in a model have meaningful identities, if an object's identity is important then the model must prioritise it
The model must have a way to distinguish each entity, regardless of form and history
May involve attaching a unique identifier or symbol
It's important not to designate objects as entities if unnecessary
Modeling entities:
Keep it simple, only focusing on essential characteristics
Unique and immutable ID attached to the entity
Common attributes such as name and address which are common query attributes
Non-intrinsic attributse can be moved to an associated object (could be other entities or value objects)
In some domains, entities may use IDs from external sources such as the government but it may introduce complexity as it's not foolproof
Value objects
It's inefficient to assign an identity to all objects
Increases complexity, burdens system with unnecessary tracking and prevent performance optimisations
Value objects, unlike entities, describe attributes or aspects of the domain
Defined by what they are, not who they are
These objects are purely descriptive, representing information but don't need a unique identifier
Value objects are often transient, created for a specific operation then discarded
For example, a person is an entity but their name is a value object
Value objects are immutable, their state persists after creation which reduces complexity and ensures stability
Related attributes should be bundled together, forming a cohesive whole
Ex. Address value object should contain street, city, state, etc.
Designing value objects:
Should be made immutable
An Name object can be copied or shared between two people but if it's mutable, changing it for one person would affect the other
Trade-offs between sharing and copying value objects
Copying can overload system with too many objects, sharing can create bottlenecks in distributed systems especially. Flyweight patterns can be implemented to help make objects interchangeable and minimise memory usage
When to copy or share?
Copy when immutability is not guaranteed when passing between processes
Share if the object is strictly immutable and when space and overhead is a concern
Mutable objects are allowed if:
They change frequently
Creating or deleting them is resource-intensive
Replacing them could disturb object clustering (ex. in databases)
If an object is mutable, it must not be shared between different parts of the system
Services
Some operations span multiple domain objects and forcing these behaviours on a single object can increase model complexity
A service is used when certain operations don't naturally belong to any entity or value object
Services don't maintain state or represent a domain object, just exist to simply perform operations
Typically named after verbs to represent an action
Characteristics of a good service:
Service relates to the domain but not fit naturally as part of an entity or value object
Interface should be well definde using other domain model elements such as entities or value objects
Should not have its own state and should be reusable across different clients
Don't overuse services, some behaviour and operations still naturally belong within entities or value objects
Modules
Modules allow you to focus on the details within it and see relationships between modules without getting lost in internal details
Should represent meaningful concepts in the domain, not just an arbitrary divisions of code
Low coupling (limited dependencies) and high cohesion (related key elements) between modules
Modules tend to evolve alongside smaller elements within them
Harder to refactor modules than classes but allowing modules to reflect changes keeps the model relevant and adaptable
Module names become part of the ubiquitous language which reinforces the conceptual structure of the model
Modelling paradigms
Entities, value objects, services and modules are fundamental building blocks for an object model in DDD
Model driven design doesn't mean forcing everything in an object model, there are other paradigms such as rules engines though it often introduces complexity
The object-oriented paradigm dominates
Balances simplicity and sophistication
Widespread adoption, mature tools and infrastructure
Has developer support and established frameworks unlike other paradigms