what is ddd and how could it help you
TRANSCRIPT
Frameworks PHPSymphony
CakePHP
CodeIgniter
LarvalSilex
Yii
PhalconZend Framework Nette
Kohana
SGBD and others SQLite
Eloquent
NoSQL
Larval
Doctrine
SQL
SybaseMySQLMongoDB
PDO
Interfaces Command Line Web Browser APIs
ORMActive Record
What do they all have in common?
Domain-driven design
BasketWasCreated or BasketWasPickedUp
Concept created by Eric Evans (2003)
It is an approach of software development, designed to work with complex and large scaled software
It proposes an Ubiquitous language between business and software (developers and business experts)
It focuses on domain and business
When should we use it?
When should we not use it?
Complex domain with many business rules
Iterative process with a long lifecycle
Growth forecast of complexity
Simple domains (like CRUDs)
Why do we use it?
Agile, iterative and continuous modelling
Less coupling, more cohesive, flexible and extensible code
Testable Code
Agreement between domain experts and developers
BDD tests close to the code
Software for everyone to understand
EntitiesHave an identity that endures over the time
1 class User { 2 private $username; 3 private $password; 4 5 public function getUsername() : string { 6 return $this->username; 7 } 8 9 public function setUsername(string $username) { 10 $this->username = $username; 11 } 12 13 public function getPassword() : string { 14 return $this->password; 15 } 16 17 public function setPassword(string $password) { 18 $this->password = $password; 19 } 20 }
Don’t forget the PSR-1 :P
EntitiesEntities have behaviour Entities aren't typed arrays (getters e setters)
1 class User { 2 private $banned; 3 private $username; 4 private $passwordHash; 5 6 public function toNickname() : string { 7 return $this->username; 8 } 9 10 public function authenticate(string $pass, callable $checkHash) : bool { 11 return $checkHash($pass, $this->passwordHash) 12 && ! $this->hasActiveBans(); 13 } 14 15 public function changePass(string $pass, callable $hash) { 16 $this->passwordHash = $hash($pass); 17 } 18 }
beberlei/assert - Thin assertion library for use in libraries and business-model
EntitiesKeep collections hidden in your entities
Disallow Collection access from outside the entity
1 public function banUser(Uuid $userId) 2 { 3 $user = $this->repository->find($userId); 4 5 $user->getBans()->add(new Ban($user)); 6 }
1 class User 2 { 3 private $bans; 4 5 public function getBans() : Collection { 6 return $this->bans; 7 } 8 }
1 class User 2 { 3 private $roles; 4 5 public function promote(Role $role) { 6 $this->roles[] = $role; 7 } 8 9 public function is(Role $role) : bool { 10 return $this->roles->has($role); 11 } 12 }
Entities 1 class User { 2 private $id; 3 private $username; 4 5 public function __construct(string $username) { 6 $this->id = Uuid::uuid4(); 7 $this->username = $username; 8 } 9 }
Your db operations will block each other
You are denying bulk inserts
You cannot make multi-request transactions
Your object is invalid until saved
Your object does not work without the DB
Immutable data is simple
Immutable data is cacheable (forever)
Immutable data is predictable
Immutable data enables historical analysis Or append-only data-structures
Avoid Auto-generated Identifiers Stay valid after __construct
Avoid Soft-deletes Avoid setters
DateTimeImmutable
Value ObjectsMartin Fowler defines a Value Object as a small object such as money or a date range object.
Examples: numbers, text strings, dates, times, a person’s full name (composed of first, middle, last name, and title), currencies, colours, phone numbers, and postal code.
1 class Email { 2 public function __construct($email) { 3 if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { 4 throw new InvalidArgumentException('...'); 5 } 6 7 $this->email = $email; 8 } 9 10 public function __toString() : string { 11 return $this->email; 12 } 13 }
ValueObjects ensure consistency Immutability Validate your data
AggregatesMartin Fowler defines Aggregates as a cluster of domain objects that can be treated as a
single unit.Aggregates are all about transactions.
1 class Order { 2 function __construct( 3 Customer $customer, 4 ProductList $productList 5 ) { 6 $this->id = Uuid::uuid4(); 7 $this->customer = $customer; 8 $this->productList = $productList; 9 $this->status = Status::open(); 10 } 11 12 public function getTotal() { 13 // ... 14 } 15 16 // ... 17 }
Repositories
1 interface OrderRepository { 2 public function findById($id) : Order; 3 4 public function findByUser(User $user) : ArrayCollection; 5 }
Repositories act as storage locations, where a retrieved object is returned in the exact same state it was persisted
1 class DoctrineOrderRepository implements OrderRepository { } 2 3 class FileOrderRepository implements OrderRepository { } 4 5 class InMemoryOrderRepository implements OrderRepository { }
Infrastructure Layer
Prefer Query Functions
FactoriesFactories help in decoupling the client from knowing how to build complex
objects and Aggregates
1 class ComplexObjectFactory { 2 3 public function create ( 4 User $user, 5 ProductList $productList, 6 ShipAddress $shipAddress 7 ) { 8 $object = new Object(...); 9 10 // complex logic 11 12 return $object; 13 } 14 } 15
Services
When there are operations that need to be represented, we can consider them to be
services
1 class OrderCreator { 2 3 /** 4 * @var EntityManagerInterface 5 */ 6 private $entityManager; 7 8 /** 9 * @var EventDispatcherInterface 10 */ 11 private $eventDispatcher; 12 13 public function create( 14 Customer $customer, 15 ProductList $productList 16 ) : Order { 17 $order = $this->factory->create(...); 18 19 // ... some domain validations 20 21 $this->entityManager->persist($order); 22 23 $this->eventDispatcher->dispatch( 24 OrderEvent::CREATED, 25 new OrderEvent($order) 26 ); 27 28 // ... 29 30 return $order; 31 } 32 }
CouponDiscount = null
Prefer NullObject Pattern
Command PatterUbiquitous Language
1 $command = new SuspendCustomer($customer); 2 3 $commandBus->handle($command);
Commands express intend (user actions)Commands are simple
Commands are Value Objects
CQRSCommand-Query Responsibility Segregation
Read Write
90% 10%
ViewModels / Flexible
Eventually consistent
Validation / Business rules
Coherence (ACID)