hexagonal architecture - message-oriented software design (php benelux 2016)

76
HEXAGONAL ARCHITECTURE Message oriented software design By Matthias Noback

Upload: matthiasnoback

Post on 13-Apr-2017

1.738 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

HEXAGONAL ARCHITECTURE Message oriented software design

By Matthias Noback

Page 2: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

ARCHITECTUREWhat's the problem?

Page 3: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Nice app

Page 4: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Sad app

Page 5: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Your brain can't handle it

M V C ?

Page 6: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Coupling to frameworks and libraries

Page 7: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

How do you start a new project?

Pick a framework

Install a skeleton project

Remove demo stuff

Auto-generate entities

Auto-generate CRUD controllers

Done

"It's a Symfony project!"

Page 8: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

That's actually outside inThe boring stuff

The interesting stuff

SymfonyDo

ctrine

RabbitMQ

Redis

Angular

Page 9: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Slow tests

DB

Browser

Message queue

Key-value

Filesystem

Page 10: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Why do frameworks not solve this for us?

Because they can't ;)

Page 11: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Frameworks are about encapsulation

Page 12: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Low-level API

$requestContent = file_get_contents('php://input'); $contentType = $_SERVER['CONTENT_TYPE']; if ($contentType === 'application/json') { $data = json_decode($requestContent, true); } elseif ($contentType === 'application/xml') { $xml = simplexml_load_string($requestContent); ... }

Page 13: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Nicely hides the details

$data = $serializer->deserialize( $request->getContent(), $request->getContentType() );

Page 14: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Low-level API

$stmt = $db->prepare( 'SELECT * FROM Patient p WHERE p.anonymous = ?' ); $stmt->bindValue(1, true); $stmt->execute(); $result = $stmt->fetch(\PDO::FETCH_ASSOC); $patient = Patient::reconstituteFromArray($result);

Page 15: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Hides a lot of details

$patient = $repository->createQueryBuilder('p') ->where('p.anonymous = true') ->getQuery() ->getResult();

Page 16: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What about abstraction?

Page 17: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

$patient = $repository->createQueryBuilder('p') ->where('p.anonymous = true') ->getQuery() ->getResult();

Concrete

Concrete

Concrete

Page 18: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

$patients = $repository->anonymousPatients();

Abstract

Nice

DIY

Page 19: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Coupling to the delivery mechanism

Page 20: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

public function registerPatientAction(Request $request) { $patient = new Patient();

$form = $this->createForm(new RegisterPatientForm(), $patient);

$form->handleRequest($request);

if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($patient); $em->flush();

return $this->redirect($this->generateUrl('patient_list')); }

return array( 'form' => $form->createView() ); }

Request and Form are web-specific

EntityManager is ORM, i.e. relational DB-specific

Page 21: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Reusability: impossible

Page 22: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Some functionality

The web

The CLI

Page 23: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Some functionality

Run it

Page 24: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Lack of intention-revealing code

Page 25: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

data

data

data

Page 26: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

public function updateAction(Request $request) { $patient = new Patient();

$form = $this->createForm(new PatientType(), $patient);

$form->handleRequest($request);

if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($patient); $em->flush();

return $this->redirect($this->generateUrl('patient_list')); }

return array( 'form' => $form->createView() ); }

from the HTTP request

copied into an entity

then stored in the database

What exactly changed?!

And... why?

Page 27: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

R.A.D.

Rapid Application Development

B.A.D.

B.A.D. Application Development

Page 28: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

In summary

Coupling to a framework

Coupling to a delivery mechanism (e.g. the web)

Slow tests

Lack of intention in the code

Page 29: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

THE ESSENCEof your application

Page 30: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

The essence

Other things

Page 31: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

The "heart"?

Page 32: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

"The heart of software is its ability to solve domain-related problems for its users.

–Eric Evans, Domain Driven Design

All other features, vital though they may be, support this basic purpose."

Page 33: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What's essential?

Domain model

Interaction with it

Use cases

Page 34: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What's not essential?

Page 35: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

“The database is an implementation detail”

–Cool software architect

Page 36: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

The core doesn't need to know about it

Page 37: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What about interaction?

Page 38: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

The core doesn't need to know about it

Page 39: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Infrastructure

The world outside

Web browser

TerminalDatabase

Messaging

Filesystem(E)mail

Page 40: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Mmm... layers Layers allow you to

separate

Layers allow you to

allocate

Layers have

boundaries

Rules for crossing

Page 41: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Rules about communication

Actually: rules about dependencies

Page 42: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

The dependency rule

–Robert Martin, Screaming Architecture

Page 43: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What crosses layer boundaries?

Message

Page 44: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

MessagessomeFunctionCall( $arguments, $prepared, $for, $the, $receiver );

$message = new TypeOfMessage( $some, $relevant, $arguments ); handle($message);

Page 45: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What about the application boundary?

The app

Messag

e

The world outside

Page 46: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

How does an app allow incoming messages at all?

By exposing input ports

Routes Console commands

A WSDL file for a SOAP API

Page 47: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)
Page 48: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)
Page 49: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Ports use protocols for communication

Each port has a language of its own

Page 50: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Web (HTTP)

Page 51: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Messaging (AMQP)

Page 52: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

HTTP Request

Form

Request

Controller

Entity

Value object

Web p

ort

Tran

slate

the re

quest

Repository

Page 53: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Adapters

The translators are called: adapters

Page 55: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

An example

Plain HTTP message

$_POST, $_GET,

$_SERVER, Request

POST /patients/ HTTP/1.1 Host: hospital.com

name=Matthias&[email protected]

Command

$command = new RegisterPatient( $request->get('name'), $request->get('email') );

Page 56: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Command

$command = new RegisterPatient( $request->get('name'), $request->get('email') );

Expresses intention

Implies changeIndependent

of delivery mechanism

Only the message

Page 57: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

class RegisterPatientHandler { public function handle(RegisterPatient $command) { $patient = Patient::register( $command->name(), $command->email() ); $this->patientRepository->add($patient); } }

CommandCommand handler

Page 58: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

CommandCommand handler A

Command bus

Command handler B

Command handler C

Page 59: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

HTTP Request

Form

Request

Controller

Patient (entity)

Web p

ort

PatientRepository

RegisterPatient- Handler

RegisterPatient (command)

Infras

truc

ture

Application

Domain

Page 60: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Change

New entity (Patient)

Entity-Manager UnitOf-Work

$patient = Patient::register( $command->name(), $command->email() ); $this->patientRepository ->add($patient);

Insert query (SQL)

INSERT INTO patients SET name='Matthias', email='[email protected]';

Page 61: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

SQL query

EntityManager

UnitOfWork

QueryBuilder

Persi

stenc

e port

Prepare

for p

ersist

ence

PatientRepository

Core

Infrastruc

ture

Page 62: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)
Page 63: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Messaging (AMQP)

Persistence (MySQL)

Page 64: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

What often goes wrong: we violate boundary rules...

Page 65: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

EntityManager

UnitOfWork

QueryBuilder

PatientRepository

Core

Infrastruc

ture

Page 66: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

RegisterPatient- Handler

Domain

Infrastr

ucture

Applicatio

n

Domain

PatientRepository (uses MySQL)

EntityManager

UnitOfWork

QueryBuilder

Page 67: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

PatientRepository (uses MySQL)

Domain

Infrastr

ucture

Applicatio

n

DomainRegisterPatient-

Handler

Page 68: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Domain

PatientRepository (interface) Dependency

inversion

PatientRepository (uses MySQL)

RegisterPatient- Handler

Page 69: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Domain

InMemory- PatientRepository

Speedy alternative

RegisterPatient- Handler

PatientRepository (uses MySQL)

PatientRepository (interface)

Page 70: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

"A good software architecture allows decisions [...] to be deferred and delayed."

–Robert Martin, Screaming Architecture

Page 71: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

IN CONCLUSIONwhat did we get from all of this?

Page 72: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Separation of concerns

Core

Infrastructure

Page 73: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

CommandCommand

Command handler

Command handler

Stand-alone use cases

Command

Command handler

Intention-revealing

Reusable

Page 74: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

Infrastructure stand-ins

Regular implementation

Interface

Stand-in, fast implementation

Page 75: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

This is all very much supportive of...

See also: Modelling by Example

DDD

TDD

BDD

CQRS

Page 76: Hexagonal architecture - message-oriented software design (PHP Benelux 2016)

QUESTIONS?joind.in/talk/32a42FEEDBACK?