60
TrueNorthPHP 2014 Beyond MVC: From Model to Domain Jeremy Cook

Beyond MVC: from Model to Domain

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: Beyond MVC: from Model to Domain

TrueNorthPHP 2014

Beyond MVC: From Model to Domain

Jeremy Cook

Page 2: Beyond MVC: from Model to Domain

What is a domain?

Page 3: Beyond MVC: from Model to Domain

–http://www.oxforddictionaries.com/definition/english/domain

“a specified sphere of activity or knowledge.”

Page 4: Beyond MVC: from Model to Domain

–http://en.wikipedia.org/wiki/Domain_(software_engineering)

“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…”

Page 5: Beyond MVC: from Model to Domain

What is MVC?

Page 6: Beyond MVC: from Model to Domain

Interaction of MVC Layers

User

Model!

Controller!

Uses

Manipulates

View!

Updates

Sees

Page 7: Beyond MVC: from Model to Domain

Interaction of MVC Layers

User

Model!

Controller!

View!

Page 8: Beyond MVC: from Model to Domain

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

Page 9: Beyond MVC: from Model to Domain

–http://en.wikipedia.org/wiki/Model–view–controller

“Model–view–controller (MVC) is a software architectural pattern for implementing user

interfaces.”

Page 10: Beyond MVC: from Model to Domain

This talk is about managing complexity

Page 11: Beyond MVC: from Model to Domain

Introducing Action Domain Responder

Page 12: Beyond MVC: from Model to Domain

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

Page 13: Beyond MVC: from Model to Domain

What is Action Domain Responder?

❖ Model!

❖ View!

❖ Controller

Page 14: Beyond MVC: from Model to Domain

What is Action Domain Responder?

❖ Controller!

❖ Model!

❖ View

Page 15: Beyond MVC: from Model to Domain

What is Action Domain Responder?

❖ Controller Action!

❖ Model Domain!

❖ View Responder

Page 16: Beyond MVC: from Model to Domain

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

Page 17: Beyond MVC: from Model to Domain

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

Page 18: Beyond MVC: from Model to Domain

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

Page 19: Beyond MVC: from Model to Domain

ADR Example

<?php!!interface ActionInterface {! public function __construct(ResponderFactoryInterface $factory);! public function __invoke(RequestInterface $request);!}!

Page 20: Beyond MVC: from Model to Domain

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

Page 21: Beyond MVC: from Model to Domain

Further information on ADR

❖ https://github.com/pmjones/adr

Page 22: Beyond MVC: from Model to Domain

Hexagonal Architecture

Page 23: Beyond MVC: from Model to Domain

Ports and Adapters Hexagonal Architecture

Page 24: Beyond MVC: from Model to Domain

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

Page 25: Beyond MVC: from Model to Domain

What are Ports and Adapters?

❖ Invented by Alistair Cockburn!

❖ Architectural pattern for isolating an application from it’s inputs.

Page 26: Beyond MVC: from Model to Domain

–Alistair Cockburn

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

Page 27: Beyond MVC: from Model to Domain

–Alistair Cockburn

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

Page 28: Beyond MVC: from Model to Domain

Ports and Adapters

Application

Page 29: Beyond MVC: from Model to Domain

Ports and Adapters

Application

Page 30: Beyond MVC: from Model to Domain

Ports and Adapters

Application

Adapters AdaptersA

dapt

ers A

dapters

AdaptersAdapters

Page 31: Beyond MVC: from Model to Domain

Ports and Adapters

Domain

Adapters AdaptersA

dapt

ers A

dapters

AdaptersAdapters

Page 32: Beyond MVC: from Model to Domain

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

Page 33: Beyond MVC: from Model to Domain

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']);! }! }!}!

Page 34: Beyond MVC: from Model to Domain

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

Page 35: Beyond MVC: from Model to Domain

Further information on Ports and Adapters

❖ The original article introducing ports and adapters: http://alistair.cockburn.us/Hexagonal+architecture

Page 36: Beyond MVC: from Model to Domain

Introducing Domain Driven Design

Page 37: Beyond MVC: from Model to Domain

What is Domain Driven Design?

❖ Concept coined by Eric Evans!

❖ Ideas can be grouped into two related areas:!

❖ Architectural patterns!

❖ Object patterns

Page 38: Beyond MVC: from Model to Domain

DDD Interaction Map

Page 39: Beyond MVC: from Model to Domain

Read some books

Page 40: Beyond MVC: from Model to Domain

Architectural patterns

Page 41: Beyond MVC: from Model to Domain

Your app has multiple domains

Page 42: Beyond MVC: from Model to Domain

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

Page 43: Beyond MVC: from Model to Domain

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

Page 44: Beyond MVC: from Model to Domain

Context map

❖ Describes relationships between domains!

❖ Outlines all points of contact between domains!

❖ Can also include existing systems

Page 45: Beyond MVC: from Model to Domain

Object patterns

Page 46: Beyond MVC: from Model to Domain

Entities

❖ Represents a concept in your domain!

❖ Each instance of a entity should be considered unique!

❖ Houses logic and operation on the concept

Page 47: Beyond MVC: from Model to Domain

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

Page 48: Beyond MVC: from Model to Domain

Value Objects

<?php!!class Person {! public function __construct($firstName, $lastName) {! //Code here! }!}!!$person = new Person('Cook', 'Jeremy'); //WHOOPS!!

Page 49: Beyond MVC: from Model to Domain

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

Page 50: Beyond MVC: from Model to Domain

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

Page 51: Beyond MVC: from Model to Domain

Entities vs Value Objects

!==Bank AccountOwner: Jeremy

Balance: $1,000,000Account #: 12345

===Currency

Name: Canadian DollarAbbr: CADSymbol: $

CurrencyName: Canadian Dollar

Abbr: CADSymbol: $

Bank AccountOwner: Jeremy

Balance: $1,000,000Account #: 12346

Page 52: Beyond MVC: from Model to Domain

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

Page 53: Beyond MVC: from Model to Domain

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

Page 54: Beyond MVC: from Model to Domain

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

Page 55: Beyond MVC: from Model to Domain

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

Page 56: Beyond MVC: from Model to Domain

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

Page 57: Beyond MVC: from Model to Domain

Domain Events

$event = EventFactory::createEventForSuccessfulAccountTransfer($from, $to, $money);!$eventType = EventTypes::SUCCESSFUL_MONEY_TRANSFER;!$eventDispatcher->raiseEvent($eventType, $event);

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

Page 58: Beyond MVC: from Model to Domain

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

Page 59: Beyond MVC: from Model to Domain

Avoid projects like this!

Page 60: Beyond MVC: from Model to Domain

Thanks for listening!

❖ Any questions?!

❖ Feel free to contact me!

[email protected]!

❖ @JCook21