domain-driven design at zendcon 2012

79
Domain-Driven Design A Collaboration Between Domain Experts and Software Practitioners

Upload: bradley-holt

Post on 09-May-2015

883 views

Category:

Technology


0 download

DESCRIPTION

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.

TRANSCRIPT

Domain-Driven DesignA Collaboration Between

Domain Experts and Software Practitioners

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

Complexity is in the domain, not the technology

Models are tools used to solve domain problems

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

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

Ames RoomUsed 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

"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).

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

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.

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

Collaboratively explore the model with both domain experts and software practitioners

Case Study: Three-Dimensional Animation

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

Domain Expert: John LasseterStudied 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]

“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.

Identify your core domain

Identify your core domain

Distill your core domain

Focus your resources on the core domain

Core Domain

Distillation

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

Identifying the Core DomainAsk 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?

There are always multiple models

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

Ubiquitous LanguageSpeak 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!

Strategic Design

Draw a context map of the current bounded contexts

Map what actually exists—not what you wish existed!

Identify relationships between contexts

Context Map

customer/supplier

Relationship Patterns

partnership

shared kernelbig ball of

mud

conformist

anticorruption layer

separate ways

open host service

published language

Building Blocks

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

Value ObjectDe$ned by its encapsulated attributes

Treat value objects as immutable

Delegate business logic to value objects

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

Aggregate RootDesignate one entity as the aggregate root

Allow external references to only the aggregate root

Persist the aggregate root, along with its object graph

RepositoryDelegate 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

ServiceA 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

Model Exploration

Ubiquitous Language

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

Ballot ItemEither an Election or a Referendum as presented on a ballot.

ElectionA 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.

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

MunicipalityA District that can be a city, town, village, or other local government unit.

WardAn 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.

CandidateA person running for elected office. Write-ins are considered Candidates.

Winning ThresholdA 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%

Scenario

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

Proposed Model

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

Election Aggregate

http://yuml.me/b3094ce6

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

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

Winning Policy Value Objectinterface WinningPolicy{ /** * @return Candidate[] */ public function determineWinners();}

Winning Threshold Value Objectclass 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; }

Code Probe

Use concrete scenarios in discussions with domain experts and in tests

// 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

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

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

Challenge the Model

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

Supple Design

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

Totaling Ballot Item Resultsclass 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); }}

Other TechniquesIntention-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?

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

Side-Effect Freeclass 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; }}

Assert Preconditions and Postconditionspublic 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;}

Advanced Topics

Event Sourcing[1]

1. http://martinfowler.com/eaaDev/EventSourcing.html

Domain EventSomething 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

Event LogCurrent 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

Command-Query Responsibility Segregation (CQRS)

Write Model/Read ModelDe$ne one model for writing data (commands)

De$ne another model for reading data (queries)

Both models operate on the same aggregate

Thank You@BradleyHolt

http://bradley-holt.comhttps://joind.in/7025

Copyright © 2011-2012 Bradley Holt. All rights reserved.