Given at TrueNorthPHP 2014:
"MVC presents a great way to divide responsibilities in your application but it offers no help in building the most critical part: the model or domain. This talk will introduce ways that can help you to encapsulate the richness of your domain. We'll look at Action Domain Response as a new way of thinking about the concepts presented in MVC before examining Hexagonal Architecture, allowing you to easily reuse your domain across multiple delivery mechanisms. We'll then finish with an introduction to Domain Driven Design, a technique that allows you to closely align your domain with the business problems it is solving while helping keep things well designed and easily maintainable. By the end of this talk you should have the knowledge needed to begin modelling your domains more powerfully while keeping them aligned to the real world problems they solve."
3. “a specified sphere of activity or knowledge.”
–http://www.oxforddictionaries.com/definition/english/domain
4. “A domain is a field of study that defines a set of
common requirements, terminology, and
functionality for any software program
constructed to solve a problem…”
–http://en.wikipedia.org/wiki/Domain_(software_engineering)
8. Problems with ‘web’ MVC
❖ Easy to muddy responsibilities in the controller!
❖ Use of the term ‘Model’ is an issue…!
❖ Offers no guidance in modelling the most critical part of
our apps: the model or domain
9. “Model–view–controller (MVC) is a software
architectural pattern for implementing user
interfaces.”
–http://en.wikipedia.org/wiki/Model–view–controller
12. What is Action Domain Responder?
❖ Created by Paul M Jones!
❖ Web specific refinement of MVC!
❖ Designed to map more closely to what actually happens
in the lifecycle of a web request
13. What is Action Domain Responder?
❖ Model!
❖ View!
❖ Controller
14. What is Action Domain Responder?
❖ Controller!
❖ Model!
❖ View
15. What is Action Domain Responder?
❖ Controller Action!
❖ Model Domain!
❖ View Responder
16. Action
❖ In ADR an action is mapped to a single class or closure!
❖ Creates a single place for all code dealing with an action!
❖ Does not directly create a view or HTTP response
17. Responder
❖ ADR recognises that a web response is more than a
view!
❖ Action instantiates a responder object and injects
domain data in it!
❖ Responder is responsible for generating all aspects of
the response
18. Domain
❖ ADR offers no help on modelling a domain…!
❖ …but at least Paul calls it a domain!!
❖ Other patterns later will offer more help here
19. ADR Example
<?php!
!
interface ActionInterface {!
public function __construct(ResponderFactoryInterface $factory);!
public function __invoke(RequestInterface $request);!
}!
20. ADR Example
<?php!
!
class FooAction implements ActionInterface {!
protected $responderFactory;!
!
public function __construct(ResponderFactoryInterface $factory) {!
$this->responderFactory = $factory;!
}!
!
public function __invoke(RequestInterface $request) {!
//Domain logic here!
$responder = $this->responderFactory->generateForRequest($request);!
!
return $responder();!
}!
}!
24. What’s wrong with ‘Hexagonal Architecture’?
❖ Has nothing to do with hexagons!
❖ Has nothing to do with the number 6!
❖ Ports and adapters describes what this actually does
25. What are Ports and Adapters?
❖ Invented by Alistair Cockburn!
❖ Architectural pattern for isolating an application from
it’s inputs.
26. “Allow an application to equally be driven by
users, programs, automated test or batch scripts,
and to be developed and tested in isolation from
its eventual run-time devices and databases.”
–Alistair Cockburn
27. “Allow an application to equally be driven by
users, programs, automated test or batch scripts,
and to be developed and tested in isolation from
its eventual run-time devices and databases.”
–Alistair Cockburn
32. HTTP Adapter
<?php!
!
class FooAction implements ActionInterface {!
protected $responderFactory;!
protected $service;!
!
public function __construct(ResponderFactoryInterface $factory,
ApplicationServiceInterface $service) {!
$this->responderFactory = $factory;!
$this->service = $service;!
}!
!
public function __invoke(RequestInterface $request) {!
$result = $this->service->__invoke($request->getParamsArray());!
$responder = $this->responderFactory->generateForRequest($request);!
!
return $responder($result);!
}!
}!
33. AMQP Adapter
<?php!
!
class FooConsumer implements AMQPConsumer {!
protected $service;!
!
public function __construct(ApplicationServiceInterface $service) {!
$this->service = $service;!
}!
!
public function __invoke(AMQPMessage $msg) {!
$data = json_decode($msg->body, true);!
$result = $this->service->__invoke($data);!
if ($result->isStatusOk()) {!
$msg->delivery_info['channel']!
->basic_ack($msg->delivery_info['delivery_tag']);!
}!
}!
}!
34. Advantages of Ports and Adapters
❖ Encapsulation of the domain!
❖ Allows development of the domain and adapters to
be independent!
❖ Allows better end to end testability of the domain!
❖ Makes it simple to add new entry points to an app
35. Further information on Ports and Adapters
❖ The original article introducing ports and adapters:
http://alistair.cockburn.us/Hexagonal+architecture
37. What is Domain Driven Design?
❖ Concept coined by Eric Evans!
❖ Ideas can be grouped into two related areas:!
❖ Architectural patterns!
❖ Object patterns
42. Ubiquitous language
❖ Develop a shared language to describe each domain
and model the software after it!
❖ The domain should be an expression of the ubiquitous
language in code!
❖ Aim is to unite all members of a product team, from
developers to product managers
43. Bounded contexts
❖ Represents the boundary around a domain!
❖ All code within a domain is completely encapsulated
with specific entry points!
❖ Code and concepts are unique per domain
44. Context map
❖ Describes relationships between domains!
❖ Outlines all points of contact between domains!
❖ Can also include existing systems
46. Entities
❖ Represents a concept in your domain!
❖ Each instance of a entity should be considered unique!
❖ Houses logic and operation on the concept
47. Value Objects
❖ Used when you only care about the attributes and logic
of the concept!
❖ Immutable!
❖ All methods must be side effect free!
❖ Mutator methods must return a new instance of the
value object!
❖ Prefer value objects over simple types
48. Value Objects
<?php!
!
class Person {!
public function __construct($firstName, $lastName) {!
//Code here!
}!
}!
!
$person = new Person('Cook', 'Jeremy'); //WHOOPS!!
49. Value Objects
<?php!
!
class Firstname {!
protected $firstname;!
!
public function __construct($firstname) {!
if (! is_string($firstname)) {!
throw new InvalidArgumentException(/**ErrorMessage**/);!
}!
$this->firstname = $firstname;!
}!
!
public function __toString() {!
return $this->firstname;!
}!
}!
50. Value Objects
<?php!
!
class Person {!
public function __construct(Firstname $firstName, Lastname $lastName) {!
//Code here!
}!
}!
!
//This will now cause an error!
$person = new Person(new Lastname('Cook'), new Firstname('Jeremy'));!
51. Entities vs Value Objects
!==
Bank Account
Owner: Jeremy
Balance: $1,000,000
Account #: 12345
===
Currency
Name: Canadian Dollar
Abbr: CAD
Symbol: $
Bank Account
Owner: Jeremy
Balance: $1,000,000
Account #: 12346
Currency
Name: Canadian Dollar
Abbr: CAD
Symbol: $
52. Aggregates
❖ A collection of entities contained by another entity!
❖ The containing entity is the aggregate root!
❖ Individual aggregate instances can only be accessed
through the aggregate root
53. Repositories
❖ A specialised adapter that maps entities to and from the
persistence layer!
❖ Provides methods to retrieve entities and save them!
❖ Abstracts the details of the persistence layer away from
the domain
54. Domain Services
❖ Encapsulates an operation that is not owned by another
part of the domain model!
❖ A good service has three properties:!
❖ Models a domain concept that does not conceptually
belong to an entity or value object!
❖ Stateless!
❖ Defined in terms of the domain model
55. Domain Services
<?php!
!
class MoneyTransfer {!
public static function transferBetweenAccounts(Account $from, Account
$to, Money $amount) {!
$from->debitForTransfer($money, $to);!
$to->creditFromTransfer($money, $from);!
}!
}!
!
//In the application service...!
$from = $accountRepository->findByAccNumber('123456');!
$to = $accountRepository->findByAccNumber('123457');!
$money = new Money('100', new Currency('CAD'));!
MoneyTransfer::transferBetweenAccounts($from, $to, $money);!
56. Domain Events
❖ Allows a domain to signal that something as happened!
❖ Full part of the domain and a representation of
something that has happened!
❖ Used to signal something that might trigger a state
change in another domain
57. Domain Events
<?php!
!
class MoneyTransfer {!
public static function transferBetweenAccounts(Account $from, Account
$to, Money $amount) {!
$from->debitForTransfer($money, $to);!
$to->creditFromTransfer($money, $from);!
}!
}!
!
//In the application service...!
$from = $accountRepository->findByAccNumber('123456');!
$to = $accountRepository->findByAccNumber('123457');!
$money = new Money('100', new Currency('CAD'));!
MoneyTransfer::transferBetweenAccounts($from, $to, $money);!
$event = EventFactory::createEventForSuccessfulAccountTransfer($from, $to,
$money);!
$eventType = EventTypes::SUCCESSFUL_MONEY_TRANSFER;!
$eventDispatcher->raiseEvent($eventType, $event);
58. Further Information on DDD
❖ Eric Evans!
❖ “Domain Driven Design” book!
❖ Short introduction: https://domainlanguage.com/ddd/
patterns/DDD_Reference_2011-01-31.pdf!
❖ Implementing Domain Driven Design by Vaughn Vernon!
❖ Mathias Verraes: http://verraes.net!
❖ DDD in PHP Google Group: https://groups.google.com/
forum/#!forum/dddinphp