Domain-driven design is a collaborative process involving both domain experts and software practitioners that attempts to address issues of complexity in software. This process is described in the book Domain-Driven Design (Addison-Wesley 2004) written by Eric Evans. Domain-driven design starts with the assertion that (for almost all software) complexity is in the domain, not in the technology. Accordingly, we must let technology play a supporting role. Domain-driven design attempts to focus on and distill the core domain for a given project.
Philosopher and scientist Alfred Korzybski said, "The map is not the territory." As such, a person practicing domain-driven design does not attempt to model reality. Instead, domain experts and software practitioners use a mental model as a tool for solving problems within a given domain. The domain experts and software practitioners collaborate to explore and develop this model. No software of any reasonable scope has just one model. We will look at the concept of a bounded context within which each model can be isolated and explored. Within a bounded context, collaborators must speak a ubiquitous language in order to reason about and discuss the model.
We will also talk about domain-driven design's building block patterns including entities, value objects, aggregates, repositories, services, and domain events. We will look at domain-driven design practices including supple design, strategic design, and distillation of the core. We will see how test-driven development can be used as a means of exploring the model. Examples in PHP will be provided of the building block patterns as well as other techniques including closure of operations, intention revealing interfaces, side-effect free functions, and assertions.
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Domain-Driven Design at ZendCon 2012
1. Domain-Driven Design
A Collaboration Between
Domain Experts and Software Practitioners
2. do·main
dōˈmān n.
a sphere of knowledge,
influence, or activity
"domain." Merriam-Webster.com. 2011. http://www.merriam-webster.com/dictionary/domain (17 October 2011).
3. The Book
http://domaindrivendesign.org/books/evans_2003
7. The Model
A model is an abstract set of tools that is used to
solve problems within a domain
While represented in code, do not think of the
model as just code
Don’t try to model reality
8. from “The Story of Science: Power, Proof and Passion”, a 2010 BBC documentary
9. Ames Room
Used in The Lord Of The
Rings: The Fellowship of
the Ring to make the
hobbits appear the
correct size in relation
to Gandalf
We are always using
mental models to
understand the world
around us—we do not
perceive an objective
reality
By Alex Valavanis (own work) [public domain], via Wikimedia Commons
10. "Why I prefer Fahrenheit to Celsius [Fixed]." reddit. 2012.
http://www.reddit.com/r/funny/comments/wigk1/why_i_prefer_fahrenheit_to_celsius_fixed/ (16 September 2012).
11. “The map is not the territory.”
—Alfred Korzybski
12. This is not a pipe.
Magritte, René. The Treachery of Images (La trahision des images). 1929. Oil on canvas. Los Angeles County Museum of Art, Los Angeles, California.
17. Software Practioner:
Edwin Catmull
Studied physics and computer science
Made many notable computer graphics discoveries
Eventually moved from two-dimensional to
three-dimensional animation
Hired by Lucasfilm to bring his expertise to the
entertainment field
18. Domain Expert:
John Lasseter
Studied animation and taught by veteran animators from Disney
Realized early-on the potential for computer generated imagery
Worked at, but eventually fired from, Disney
Hired by Edwin Catmull at Lucasfilm as an “Interface Designer”
because Catmull’s job didn’t include hiring animators[1]
[2]
1. Buckley, A. M. "Chapter 3: Art Meets Science." Pixar: The Company and Its Founders. Edina, MN: ABDO, 2011. 27. Print.
2. BSD Daemon Copyright 1988 by Marshall Kirk McKusick. All Rights Reserved. Drawn by John Lasseter.
19. “Throughout the process, Lasseter
worked side-by-side with the computer
scientists. Lasseter’s requests pushed
them to develop new tools, and their
feedback helped him learn the digital
animation process.”[1]
1. Buckley, A. M. "Chapter 3: Art Meets Science." Pixar: The Company and Its Founders. Edina, MN: ABDO, 2011. 30. Print.
23. Types of Domains
A model may represent:
• your core domain
• a supporting domain
• a generic subdomain
Focus your modeling efforts on the core domain
Consider outsourcing work on supporting domains
Consider off-the-shelf software for generic subdomains
24. Identifying the Core Domain
Ask organizational leaders and domain experts:
• What keeps you awake at night?
• What makes your system worth writing?
• Why not buy it off the shelf?
• Why not outsource it?
26. Bounded Context
Delineates the applicability of a particular model
Bounded contexts allow each model to be explored in isolation
Clearly define:
• Who is responsible for each bounded context
• To which parts of the application is the bounded
context applicable
• What manifestations the bounded context will take
(code, database schemas, etc.)
27. Ubiquitous Language
Speak a ubiquitous language within a bounded context
Terms must be clearly defined, unambiguous, and consistent
Critically important when communicating between
domain experts and software practitioners
The ubiquitous language will (and must) evolve as a progressively
richer understanding of the domain and the model are achieved
If the ubiquitous language cannot be used to clearly express
complex ideas, then you have more work to do!
29. Context Map
Draw a context map of the current bounded contexts
Map what actually exists—not what you wish existed!
Identify relationships between contexts
30. Relationship Patterns
customer/ anticorruption
partnership supplier layer
shared kernel big ball of separate ways
mud
open host conformist published
service language
32. Entity
Defined by a thread of continuity and identity
Only responsibilities should be around identity and life cycle
May be composed of other entities and/or value objects
33. Value Object
Defined by its encapsulated attributes
Treat value objects as immutable
Delegate business logic to value objects
34. Aggregate
A group of related entities and value objects
Useful when defining transaction, distribution,
and concurrency boundaries
A bounded context will have multiple aggregates
35. Aggregate Root
Designate one entity as the aggregate root
Allow external references to only the aggregate root
Persist the aggregate root, along with its object graph
36. Repository
Delegate persistence of an aggregate to a repository
A repository should behave as if it were an in-memory data store
Use an in-memory strategy for tests
If using an object-relational mapper (ORM):
Database -> ORM -> Repository
37. Service
A place for operations that aren’t naturally part of
any domain object
Like value objects, services should be treated as immutable
Operations on services are stateless
41. Election Event
A set of Districts voting on a set of Ballot Items during the same
general period of time. Examples of Election Events include
primaries, general elections, and town meeting days.
43. Election
A formal decision-making process by which a population chooses
one or more Candidates to hold public office for a given District.
Election results may be tabulated based on Polling Place, Ward,
Municipality, or District. The winner or winners of an Election may
be determined by Plurality and/or a Winning Threshold.
44. District
A distinct territorial subdivision for holding separate Elections or
Referendums. A District may be a Municipality or a Ward, but this
is not always true. Districts are periodically redistricted, but are
immutable during a given Election Event. Districts can contain
sub-Districts (i.e. Polling Places, Wards, Municipalities, or other
Districts). A District’s sub-Districts may be different for different
Ballot Items.
46. Ward
An electoral District. Some Municipalities are comprised of
multiple Wards, some are not. In Vermont, only Burlington is
broken down by Ward. Note that for legislative Districts, only
parts of some Wards vote at a Polling Place. For example, the
Municipality of Burlington’s Ward 2 is broken into two or three
legislative house Districts.
48. Winning Threshold
A method of determining the winner of an Election, or the passing
of a Referendum, based on a minimum percentage (sometimes
plus one) of the total number of votes. This would sometimes be
combined with Plurality. For example, if an Election has a Winning
Threshold of 40% and two Candidates manage to both exceed
40%, then Plurality may be used to decide the winner. Some
examples of where Winning Threshold is used include:
• Burlington Mayor: 40%
• Revenue Bonds: 50%+1
• GO Bonds: 66%
50. Election for Burlington
City Councilor
The Town Meeting Day 2011 Election Event is under way. Ward 3
in the Municipality of Burlington is holding an Election for City
Councilor. This Election has three Candidates. It is 8:30pm and
Ward 3 has indicated the following results:
• Vince Brennan (P) has 354 votes (60.2%)
• Lynn Mesick (D) has 171 votes (29.1%)
• Ron Ruloff (I) has 63 votes (10.7%)
This Election has a Winning Threshold of 40%, so Candidate Vince
Brennan (P) appears to be the winner.
54. Election Entity
(Aggregate Root)
class Election implements BallotItem
{
public function __construct($id) { }
public function setElectionEvent(ElectionEvent $event) { }
public function setDistrict(District $district) { }
public function addCandidate(Candidate $candidate) { }
/**
* @return Candidate[]
*/
public function getCandidates() { }
}
55. Candidate Entity
class Candidate
{
public function __construct($id, Election $election) { }
public function setVotes($count) { }
public function getFractionOfVotes()
{
$totalVotes = 0;
/* @var $candidate Candidate */
foreach ($this->election->getCandidates() as $candidate) {
$totalVotes += $candidate->votes;
}
return round($this->votes / $totalVotes, 3);
}
56. Winning Policy Value Object
interface WinningPolicy
{
/**
* @return Candidate[]
*/
public function determineWinners();
}
57. Winning Threshold
Value Object
class WinningThreshold implements WinningPolicy
{
public function __construct($minimumPercentage, Election $election) { }
/**
* @return Candidate[]
*/
public function determineWinners()
{
$winners = array();
/* @var $candidate Candidate */
foreach ($this->election->getCandidates() as $candidate) {
if ($candidate->getFractionOfVotes() > $this->minimumPercentage) {
$winners[] = $candidate;
}
}
return $winners;
}
60. Election Scenario
as Test
// The Town Meeting Day 2011 Election Event is under way.
$townMeetingDay2011 = new ElectionEvent('Town Meeting Day 2011');
// Ward 3 in the Municipality of Burlington…
$ward3 = new Ward('Ward 3');
$burlington = new Municipality('Burlington');
$ward3->setParentDistrict($burlington);
// …is holding an Election for City Councilor.
$cityCouncilor = new Election('City Councilor');
$cityCouncilor->setElectionEvent($townMeetingDay2011);
$cityCouncilor->setDistrict($ward3);
61. Election Scenario
as Test (cont’d)
// This Election has three Candidates.
$vinceBrennan = new Candidate(
'Vince Brennan (P)',
$cityCouncilor
);
$lynnMesick = new Candidate(
'Lynn Mesick (D)',
$cityCouncilor
);
$ronRuloff = new Candidate(
'Ron Ruloff (I)',
$cityCouncilor
);
62. Election Scenario
as Test (cont’d)
// It is 8:30pm and Ward 3 has indicated the following results:
$vinceBrennan->setVotes(354);
$lynnMesick->setVotes(171);
$ronRuloff->setVotes(63);
$this->assertEquals(.602, $vinceBrennan->getFractionOfVotes());
$this->assertEquals(.291, $lynnMesick->getFractionOfVotes());
$this->assertEquals(.107, $ronRuloff->getFractionOfVotes());
// This Election has a Winning Threshold of 40%…
$winningPolicy = new WinningThreshold(.40, $cityCouncilor);
// …so Candidate Vince Brennan (P) appears to be the winner.
$winners = $winningPolicy->determineWinners();
$this->assertContains($vinceBrennan, $winners);
$this->assertNotContains($lynnMesick, $winners);
$this->assertNotContains($ronRuloff, $winners);
64. Challenge Model
With More Scenarios
Questions to ask a domain expert:
• What if two candidates reach the 40% winning threshold?
• What if a candidate participates in two elections?
• What about a municipality without wards?
• How about an election that is won by plurality?
• What’s different about referendums?
• What changes when it’s a general election?
66. Closure of Operations
Have a method on a value object that returns an instance
of the same type of value object
Any method arguments should also be the same type as
the value object
Example: 2 + 3 = 5
• “2” is a value object of type integer
• integer has an add method
• add method accepts an argument of type integer
• add method returns an integer
• integers are closed under the operation of addition
67. Totaling Ballot Item Results
class BallotItemResult
{
/**
* @param BallotItemResult[] $results
* @return BallotItemResult
*/
public function total(array $results)
{
/* @var $options BallotItemOption[] */
$options = array();
$votes = 0;
/* @var $result BallotItemResult */
foreach ($results as $result) {
$options[] = $result->option;
$votes += $result->votes;
}
$option = new CompositeBallotItemOption($options);
return new BallotItemResult($option, $votes);
}
}
68. Other Techniques
Intention-revealing interfaces
• Is the method’s intention clear based on its interface?
Side-effect free functions
• Does the method return a value and modify state?
• Does the method interact with other objects and methods?
Assertions
• What are the method’s preconditions?
• What are the method’s postconditions?
69. Is the intention clear?
class BallotItemResult
{
/**
* Gets the fraction of votes for this Ballot Item Result
* relative to the total number of votes for all Ballot
* Item Results within the context Ballot Item
*
* @return float
*/
public function getFractionOfVotes() { }
}
70. Side-Effect Free
class WinningThreshold implements WinningPolicy
{
/**
* @return Candidate[]
*/
public function determineWinners()
{
$winners = array();
/* @var $candidate Candidate */
foreach ($this->election->getCandidates() as $candidate) {
if ($candidate->getFractionOfVotes() > $this->minimumPercentage) {
$winners[] = $candidate;
}
}
return $winners;
}
}
71. Assert Preconditions
and Postconditions
public function determineWinners()
{
assert($this->minimumPercentage >= 0);
assert($this->minimumPercentage <= 1);
$winners = array();
/* @var $candidate Candidate */
foreach ($this->election->getCandidates() as $candidate) {
$fraction = $candidate->getFractionOfVotes();
if ($fraction > $this->minimumPercentage) {
$winners[] = $candidate;
}
}
assert(count($winners) <= count($this->election->getCandidates()));
return $winners;
}
74. Domain Event
Something important that happens within the domain
that may lead to a state change in a domain object
Domain events can trigger other domain events (e.g.
three strikes triggers an out)
Domain events are immutable
75. Event Log
Current state can be computed by reading the event log
Current state may be cached, if necessary for performance
Can also serve as an audit log
77. Write Model/Read Model
Define one model for writing data (commands)
Define another model for reading data (queries)
Both models operate on the same aggregate