60
Confoo 2015 Beyond MVC: From Model to Domain Jeremy Cook

Beyond MVC: from Model to Domain

Embed Size (px)

Citation preview

Confoo 2015

Beyond MVC: From Model to Domain

Jeremy Cook

What is a domain?

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

“a specified sphere of activity or knowledge.”

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

What is MVC?

Interaction of MVC Layers

User

Model

Controller

Uses

Manipulates

View

Updates

Sees

Interaction of MVC Layers

User

Model

Controller

View

Problems with ‘web’ MVC

❖ Use of the term ‘Model’ is an issue…

❖ Easy to muddy responsibilities in the controller

❖ Offers no guidance in modelling the most critical part of our apps: the model or domain

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

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

interfaces.”

This talk is about managing complexity

Introducing Action Domain Responder

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

What is Action Domain Responder?

❖ Model

❖ View

❖ Controller

What is Action Domain Responder?

❖ Controller

❖ Model

❖ View

What is Action Domain Responder?

❖ Controller Action

❖ Model Domain

❖ View Responder

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

Responder

❖ ADR recognizes 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

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

ADR Example

<?php

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

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

Further information on ADR

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

Hexagonal Architecture

Ports and Adapters Hexagonal Architecture

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

What are Ports and Adapters?

❖ Invented by Alistair Cockburn

❖ Architectural pattern for isolating an application from its inputs.

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

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

Ports and Adapters

Application

Ports and Adapters

Application

Ports and Adapters

Application

Adapters AdaptersA

dapt

ers A

dapters

AdaptersAdapters

Ports and Adapters

Domain

Adapters AdaptersA

dapt

ers A

dapters

AdaptersAdapters

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

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

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

Further information on Ports and Adapters

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

Introducing Domain Driven Design

What is Domain Driven Design?

❖ Concept coined by Eric Evans

❖ Ideas can be grouped into two related areas:

❖ Architectural patterns

❖ Object patterns

DDD Interaction Map

Read some books

Architectural patterns

Your app has multiple domains

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

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

Context map

❖ Describes relationships between domains

❖ Outlines all points of contact between domains

❖ Can also include existing systems

Object patterns

Entities

❖ Represents a concept in your domain

❖ Each instance of a entity should be considered unique

❖ Houses logic and operation on the concept

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

Value Objects

<?php

class Employee { public function __construct($firstName, $lastName) { //Code here }}

$person = new Employee('Cook', 'Jeremy'); //WHOOPS!

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

Value Objects

<?php

class Employee { public function __construct(Firstname $firstName, Lastname $lastName) { //Code here }}

//This will now cause an error$person = new Employee(new Lastname('Cook'), new Firstname('Jeremy'));

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

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

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

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

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

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

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

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

Avoid projects like this!

Thanks for listening!

❖ Any questions?

❖ I’d love some feedback

❖ Feel free to contact me

[email protected]

❖ @JCook21