Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Domain-Driven Design at ZendCon 2012

Bradley Holt
October 24, 2012

Domain-Driven Design at ZendCon 2012

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.

Bradley Holt

October 24, 2012
Tweet

More Decks by Bradley Holt

Other Decks in Programming

Transcript

  1. Domain-Driven Design
    A Collaboration Between
    Domain Experts and Software Practitioners

    View Slide

  2. do·main
    \dōˈmān\ n.
    a sphere of knowledge,
    in uence, or activity
    "domain." Merriam-Webster.com. 2011. http://www.merriam-webster.com/dictionary/domain (17 October 2011).

    View Slide

  3. The Book
    http://domaindrivendesign.org/books/evans_2003

    View Slide

  4. Training
    http://www.domainlanguage.com/

    View Slide

  5. Complexity is in the domain,
    not the technology

    View Slide

  6. Models are tools used to
    solve domain problems

    View Slide

  7. 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
    The Model

    View Slide

  8. from “The Story of Science: Power, Proof and Passion”, a 2010 BBC documentary

    View Slide

  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

    View Slide

  10. "Why I prefer Fahrenheit to Celsius [Fixed]." reddit. 2012.
    http://www.reddit.com/r/funny/comments/wigk1/why_i_prefer_fahrenheit_to_celsius_ xed/ (16 September 2012).

    View Slide

  11. “The map is not the territory.”
    —Alfred Korzybski

    View Slide

  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.

    View Slide

  13. View Slide

  14. "Everything simple is false. Everything
    which is complex is unusable."
    —Paul Valéry

    View Slide

  15. Collaboratively explore the model
    with both domain experts and
    software practitioners

    View Slide

  16. Case Study:
    Three-Dimensional Animation

    View Slide

  17. Studied physics and computer science
    Made many notable computer graphics discoveries
    Eventually moved from two-dimensional to
    three-dimensional animation
    Hired by Lucas lm to bring his expertise to the
    entertainment eld
    Software Practioner:
    Edwin Catmull

    View Slide

  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 red from, Disney
    Hired by Edwin Catmull at Lucas lm as an “Interface Designer”
    because Catmull’s job didn’t include hiring animators[1]
    2. BSD Daemon Copyright 1988 by Marshall Kirk McKusick. All Rights Reserved. Drawn by John Lasseter.
    1. Buckley, A. M. "Chapter 3: Art Meets Science." Pixar: The Company and Its Founders. Edina, MN: ABDO, 2011. 27. Print.
    [2]

    View Slide

  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.

    View Slide

  20. Identify your core domain

    View Slide

  21. Identify your core domain
    Distill your core domain
    Focus your resources on the core domain
    Core Domain

    View Slide

  22. Distillation

    View Slide

  23. 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
    Types of Domains

    View Slide

  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?

    View Slide

  25. There are always multiple models

    View Slide

  26. Delineates the applicability of a particular model
    Bounded contexts allow each model to be explored in isolation
    Clearly de ne:
    • 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.)
    Bounded Context

    View Slide

  27. Ubiquitous Language
    Speak a ubiquitous language within a bounded context
    Terms must be clearly de ned, 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!

    View Slide

  28. Strategic Design

    View Slide

  29. Draw a context map of the current bounded contexts
    Map what actually exists—not what you wish existed!
    Identify relationships between contexts
    Context Map

    View Slide

  30. customer/
    supplier
    Relationship Patterns
    partnership
    shared kernel
    big ball of
    mud
    conformist
    anticorruption
    layer
    separate ways
    open host
    service
    published
    language

    View Slide

  31. Building Blocks

    View Slide

  32. De ned 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
    Entity

    View Slide

  33. Value Object
    De ned by its encapsulated attributes
    Treat value objects as immutable
    Delegate business logic to value objects

    View Slide

  34. A group of related entities and value objects
    Useful when de ning transaction, distribution,
    and concurrency boundaries
    A bounded context will have multiple aggregates
    Aggregate

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  38. Model Exploration

    View Slide

  39. View Slide

  40. Ubiquitous Language

    View Slide

  41. 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.
    Election Event

    View Slide

  42. Ballot Item
    Either an Election or a Referendum as presented on a ballot.

    View Slide

  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.

    View Slide

  44. 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.
    District

    View Slide

  45. Municipality
    A District that can be a city, town, village, or other local
    government unit.

    View Slide

  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.

    View Slide

  47. Candidate
    A person running for elected office. Write-ins are
    considered Candidates.

    View Slide

  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%

    View Slide

  49. Scenario

    View Slide

  50. 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.
    Election for Burlington
    City Councilor

    View Slide

  51. Proposed Model

    View Slide

  52. Warning: This proposed model is
    intentionally awed in order to
    demonstrate opportunities for
    further re nement.

    View Slide

  53. Election Aggregate
    http://yuml.me/b3094ce6

    View Slide

  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() { }
    }

    View Slide

  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);
    }

    View Slide

  56. Winning Policy Value Object
    interface WinningPolicy
    {
    /**
    * @return Candidate[]
    */
    public function determineWinners();
    }

    View Slide

  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;
    }

    View Slide

  58. Code Probe

    View Slide

  59. Use concrete scenarios in discussions
    with domain experts and in tests

    View Slide

  60. // 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);
    Election Scenario
    as Test

    View Slide

  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
    );

    View Slide

  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);

    View Slide

  63. Challenge the Model

    View Slide

  64. 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?
    Challenge Model
    With More Scenarios

    View Slide

  65. Supple Design

    View Slide

  66. 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
    Closure of Operations

    View Slide

  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);
    }
    }

    View Slide

  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?

    View Slide

  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() { }
    }

    View Slide

  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;
    }
    }

    View Slide

  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;
    }

    View Slide

  72. Advanced Topics

    View Slide

  73. Event Sourcing[1]
    1. http://martinfowler.com/eaaDev/EventSourcing.html

    View Slide

  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

    View Slide

  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

    View Slide

  76. Command-Query Responsibility
    Segregation (CQRS)

    View Slide

  77. Write Model/Read Model
    De ne one model for writing data (commands)
    De ne another model for reading data (queries)
    Both models operate on the same aggregate

    View Slide

  78. http://oreilly.com/catalog/9781449303129/ http://oreilly.com/catalog/9781449303433/

    View Slide

  79. Thank You
    @BradleyHolt
    http://bradley-holt.com
    https://joind.in/7025
    Copyright © 2011-2012 Bradley Holt. All rights reserved.

    View Slide