This document discusses domain-driven design (DDD) as an approach to tackling complexity in software development. DDD focuses on mapping business domain concepts directly into code in order to create software that reflects the business domain rather than frameworks. This is achieved through building a domain model using techniques such as defining entities, value objects, aggregates, repositories, factories and services to encapsulate business logic within the domain layer. Context mapping is also discussed as a way to delineate different bounded contexts and model variations between them.
4. CURRENT ARCHITECTURE
APPLICATION
CONTROLLER
DATA ACCESS /
BUSINESS OBJECT/
PERSISTENCE
BZ
ORM
●
●
●
DATA STORE
DATABASE
BUSINESS LOGIC IN
CONTROLLER AND IN DATA
ACCESS OBJECTS
FRAMEWORK COUPLED TO
CONTROLLER
DIRECT ACCESS TO DATA
OBJECT FROM CONTROLLER
5. PROBLEM
○ DEVELOPERS / ARCHITECTS ARE ONLY THINKING ABOUT THE
FRAMEWORK (DB, ORM, CACHING)
○ MOST OF OUR DEVELOPMENT TIME IS SPENT WRITING PLUMPING
FOR THE FRAMWORK INSTEAD OF REAL BUSINESS LOGIC
○ THE MEANING OF OOP IS LOST
6. DOMAIN DRIVEN DESIGN
WHAT
○ DOMAIN DRIVEN DESIGN IS ABOUT MAPPING BUSINESS DOMAIN
CONCEPT INTO CODE
WHY
○ TO CREATE SOFTWARE THAT REFLECT THE BUSINESS RATHER
THAN THE FRAMEWORK
7. DOMAIN DRIVEN ARCHITECTURE
CONTROLLER
APPLICATION
SERVICE
FRAMEWORK
●
●
●
●
●
●
●
HTTP
SESSION MANAGEMENT
RPC
PERSISTENCE
CACHING
SECURITY
MESSAGING
DOMAIN
DOMAIN
●
●
●
●
DATA ACCESS /
PERSISTENCE
DATA STORE
DAO
DATABASE
●
●
ALL LAYERS SUPPORT POPO BASED DESIGN
CONTROLLERS AND SERVICES ARE
CONSUMERS OF DOMAIN OBJECTS
BUSINESS LOGIC ONLY IN DOMAIN OBJECTS
NO DIRECT ACCESS TO DAO EXCEPT FROM
DOMAIN OBJECT
DOMAIN FIRST, FRAMEWORK SECOND
FRAMEWORK CONCERNS ARE
IMPLEMENTED BY DI
8. ADVANTAGES
○ PROMOTES HIGH COHESION AND LOW COUPLING
○ EASY TO TEST DOMAIN COMPONENTS
○ BUSINESS (DOMAIN) LOGIC IS ISOLATED FROM NON-DOMAIN AND
FRAMEWORK CODE
○ ADDING / CHANGING SERVICES DOES NOT INFLUENCE THE
DOMAIN OR OTHER SERVICES
11. UBIQUITOUS LANGUAGE
○ SHARED TEAM LANGUAGE (DEVELOPERS AND DOMAIN EXPERTS)
○ UBIQUITOUS IS NOT AN ATTEMPT TO DESCRIBE ENTERPRISE-WIDE
DOMAIN LANGUAGE
○ ONE UBIQUITOUS LANGUAGE PER BOUNDED CONTEXT (CODE
BASE)
○ IF YOU TRY TO APPLY A SINGLE UBIQUITOUS LANGUAGE TO AN
ENTIRE ENTERPRISE, YOU WILL FAIL
12. public function chargeCustomer(ChargecodeData $chargecode, Transaction $transaction) {
if($chargecode->getEmail() === $transaction->getCustomerEmail()
&& $transaction->getCustomerCreditCardExpiration > date(‘Y-m’)
&& in_array($transaction->getStatus(), [‘SALE’, ‘REBILL’, ‘AUTHORISE’])
&& $chargecode->isUsed() === false) {
// Do charge
}
throw new ChargeCustomerException();
}
/**
* @Inject
* @var ChargeCodeValidationPolicy
*/
protected $oneClickPolicy;
public function chargeCustomer(ChargecodeData $chargecode, Transaction $transaction) {
if($this->oneClickPolicy->isAllowed($chargecode, $transaction)) {
// Do charge
}
throw new ChargeCustomerException();
}
15. ENTITIES
○ DESIGN A CONCEPT AS AN ENTITY WHEN YOU CARE ABOUT ITS
INDIVIDUALITY, WHEN DISTINGUISHING IT FROM ALL OTHER
OBJECTS IN A SYSTEM IS A MANDATORY CONSTRAINT
(CUSTOMER, MEMBERSHIP)
○ THE ENTITY SHOULD NOT BE BOUND TO ANY FRAMEWORK (ORM),
IT SHOULD BE A PLAIN OLD PHP OBJECT (POPO)
16. /** @Entity */class Membership{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Column(type="string") */
private $status;
/** @ManyToOne(targetEntity="Customer") */
private $customer;
/** @OneToMany(targetEntity="Transaction", mappedBy="membership") */
private $transactions;
public function __construct {
$this->transactions = new ArrayCollection();
}
public function getCustomer() { return $this->customer; }
public function getTransactions() { return $this->transactions;}}
POPO
17. VALUE OBJECT
○ STRIVE TO MODEL USING VALUE OBJECTS INSTEAD OF ENTITIES
WHEREVER POSSIBLE
○ IMMUTABLE, AFTER THE OBJECT HAS BEEN INSTANTIATED, NONE
OF ITS METHODS WILL CAUSE ITS STATE TO CHANGE
○ INSTEAD OF CHANGING THE ATTRIBUTES, WOULD OBJECT
REPLACEMENT WORK INSTEAD?
18. $factory = new ChargeCodeGenerationDataFactory();
$chargeCodeData = $factory->generateFromArray($data);
class ChargeCodeGenerationData{
private $transactionId;
private $emailAddress;
private $accountId;
public function __construct($transactionId, $emailAddress, $accountId) {
$this->transactionId = $transactionId;
$this->emailAddress = $emailAddress;
$this->accountId = $accountId;
}
public function toArray() { return [‘transactionId’ => $this->transactionId,
‘emailAddress’ => $this->emailAddress,
‘accountId’
=> $this->accountId]; }
public function toJSON() { return json_encode($this->toArray());}}
19. VO BASED ON BOUNDED CONTEXT
○ IN A CUSTOMER MANAGEMENT CONTEXT CUSTOMER SHOULD BE
AN ENTITY
○ IN A MEMBERSHIP CONTEXT CUSTOMER SHOULD BE A VALUE
OBJECT
20. SERVICES
○ PROVIDES FUNCTIONALITIES FOR THE DOMAIN
○ STATELESS
○ DOMAIN SERVICES != APPLICATION SERVICES != CONTROLLER
○ DOMAIN SERVICES CAN HOST DOMAIN LOGIC
○
PERFORM A SIGNIFICANT BUSINESS PROCESS
○
TRANSFORM A DOMAIN OBJECT FROM ONE COMPOSITION TO ANOTHER
○
CALCULATE A VALUE REQUIRING INPUT FROM MORE THAN ONE DOMAIN OBJECT
22. AGGREGATES
○ GROUP OF ASSOCIATED ENTITIES AND VALUE OBJECTS TREATED
AS A UNIT FOR THE PURPOSE OF DATA EXCHANGE
○ ENTITY AS ROOT ELEMENT
○ ONLY THE ROOT IS OBTAINED THROUGH QUERIES
○ THE ENTITY IS RESPONSIBLE FOR MAINTAINING THE INVARIANCE
○ DELETE OPERATION MUST REMOVE EVERYTHING WITHIN THE
AGGREGATE BOUNDARY AT ONCE (CASCADE DELETE)
25. class ChargecodeAuthcodeGenerationResponseDataFactory
{
/**
* Factory method to generate chargecode validation data by authcode
*
* @param array $data Data used to generate
* @throws ChargecodeAuthcodeValidationDataException
* @return ChargecodeAuthcodeGenerationResponseData
*/
public function generateFromArray(array $data)
{
$this->_validateParameters($data);
$chargecodeData = $this->_generateDataAccessObject($data);
$data = $this->_unsetUnusedParameters($data);
$chargecodeData->setParams($data);
return $chargecodeData;
}
protected function _sendException()
{
throw new ChargecodeAuthcodeGenerationResponseDataException('Could not Generate a response');
}
protected function _generateDataAccessObject(array $data)
{
return new ChargecodeAuthcodeGenerationResponseData($data['authCode'], $data['account_id_destination'], $data['email_address'],
$data['crypted_string'], null);
}
}
26. REPOSITORIES
○ PATTERN FOR RETRIEVING AND SAVING OBJECTS IN THE DB
○ SHOULD NOT BE TIED TO SPECIFIC FRAMEWORK (ORM)
○ EASY SUBSTITUTION FOR TESTING
28. DEPENDENCY INJECTION
○ OBJECTS SHOULD NOT DEPEND ON CONCRETE CONSTRUCTOR
VARIABLES, INSTEAD TO SHOULD USE INTERFACES
○ OBJECTS SHOULD NOT HAVE TO CONFIGURE ITS INSTANCE
VARIABLES IN THE CONSTRUCTOR OR INIT FUNCTION, INSTEAD
THEY SHOULD RECEIVE THEM ALREADY PRE-CONFIGURED
29. “
"Dependency Injection" is a 25-dollar
term for a 5-cent concept. [...]
Dependency injection means giving
an object its instance variables. [...].
- James Shore
”
34. DOMAIN vs DOMAIN MODEL
○ THE DOMAIN IS THE PROBLEM TO BE ADDRESSED IN SOFTWARE
○ A DOMAIN MODEL IS THE REPRESENTATION OF IN CODE OF THE
SOLUTION FOR THE DOMAIN PROBLEM
○ HAS TO BE CREATED WITH THE COOPERATION OF DEVELOPERS
AND DOMAIN EXPERTS
○ THE GOAL OF DOMAIN DRIVEN DESIGN IS TO CREATE OBJECT IN
CODE THAT REFLECT THE DOMAIN
35. SUB-DOMAIN vs BOUNDED CONTEXT
○ DOMAIN CAN BE DECOMPOSED INTO SUB-DOMAINS (PRODUCTS,
BILLING, MEMBERSHIP)
○ SUB-DOMAIN SPLIT THE DOMAIN INTO DIFFERENT UNIQUE
SECTIONS
○ BOUNDED CONTEXT SPLIT THE CODE INTO DIFFERENT CODE
BASES
○ SUB-DOMAIN CAN BE IMPLEMENTED BY MULTIPLE BOUNDED
CONTEXTS (MEMBERSHIP AND MEMBERSHIP REBILL)
36. “
ORGANIZATIONS WHICH DESIGN
SYSTEMS ARE CONSTRAINED TO
PRODUCE DESIGNS WHICH ARE
COPIES OF THE COMMUNICATION
STRUCTURES OF THESE
ORGANIZATIONS
- Melvin Conway
”
41. CONTEXT MAPPING
○ PARTNERSHIP
○
○
○
○
SUCCEED OR FAIL TOGETHER
COORDINATED PLANNING
JOINT MANAGEMENT OF
INTEGRATION
SCHEDULED COMPLETION
○ SHARED KERNEL
○
○
○
INTIMATE INTERDEPENDENCIES
KEEP IT SMALL
CAN’T BE CHANGED WITHOUT
CONSULTATION
○ CUSTOMER-SUPPLIER
○
○
○
UPSTREAM / DOWNSTREAM
RELATIONSHIP
DOWNSTREAM PRIORITIES FACTOR
INTO UPSTREAM PLANNING
NEGOTIATED SCHEDULE
○ CONFORMIST
○
○
UPSTREAM / DOWNSTREAM
RELATIONSHIP
UPSTREAM HAS NO MOTIVATION TO
PROVIDE FOR DOWNSTREAM
42. CONTEXT MAPPING
○ ANTICORRUPTION LAYER
○
○
TRANSLATION LAYER
LAYER TRANSLATES IN ONE OR BOTH
DIRECTIONS BETWEEN THE TWO
MODELS
○ OPEN HOST SERVICE
○
○
SOA
PROTOCOL TO GIVE ACCESS TO
YOUR SUBSYSTEM
○ PUBLISHED LANGUAGE
○
WELL-DOCUMENTED SHARED
LANGUAGE
○ SEPARATE WAYS
○
○
COMPLETELY CUT LOOSE FROM
EACH OTHER
INTEGRATION IS EXPENSIVE WITH
SMALL BENEFITS
○ BIG BALL OF MUD
○
○
○
○
MIXED MODELS
INCONSISTENT BOUNDARIES
DRAW A BOUNDARY AROUND THE
MESS
DO NOT TRY TO APPLY
SOPHISTICATED MODELING
43. “
Any 3rd party system
that I have to integrate
with, was written by
a drunken monkey
typing with his feet
- Oren Eini
”