Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
HEXAGONAL ARCHITECTURE
Message oriented software design
By Matthias Noback
ARCHITECTURE
What's the problem?
!
!
!
Nice app
!
!
!
Sad app
Your brain can't handle it
M V C ?
Coupling to frameworks
and libraries
!
!
!
How do you start a new
project?
Pick a framework

Install a skeleton project

Remove demo stuff

Auto-generate entities

Au...
That's actually outside in
The boring stuff
The interesting stuff
Symfony
Doctrine
RabbitMQ
Redis
Angular
Slow tests
DB
Browser
Message
queue
Key-
value
Filesystem
Why do frameworks not solve this for us?
Because they can't ;)
Frameworks are about
encapsulation
Low-level API
$requestContent = file_get_contents('php://input');
$contentType = $_SERVER['CONTENT_TYPE'];
if ($contentTyp...
Nicely hides the details
$data = $serializer->deserialize(
$request->getContent(),
$request->getContentType()
);
Low-level API
$stmt = $db->prepare(
'SELECT * FROM Patient p WHERE p.anonymous = ?'
);
$stmt->bindValue(1, true);
$stmt->e...
Hides a lot of details
$patient = $repository->createQueryBuilder('p')
->where('p.anonymous = true')
->getQuery()
->getRes...
What about abstraction?
$patient = $repository->createQueryBuilder('p')
->where('p.anonymous = true')
->getQuery()
->getResult();
Concrete
Concret...
$patients = $repository->anonymousPatients();
Abstract
Nice
DIY
Coupling to the delivery
mechanism
public function registerPatientAction(Request $request)
{
$patient = new Patient();
!
$form = $this->createForm(new Regist...
Reusability: impossible
Some
functionality
The web
The CLI
Some
functionalityRun
it
Lack of intention-revealing code
data
data
data
public function updateAction(Request $request)
{
$patient = new Patient();
!
$form = $this->createForm(new PatientType(), ...
R.A.D.
Rapid Application Development
B.A.D.
B.A.D. Application Development
In summary
Coupling to a framework

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

Slow tests

Lack of intention in the ...
THE ESSENCE
of your application
The essence
Other things
The "heart"?
"The heart of software is its ability to solve
domain-related problems for its users.
–Eric Evans, Domain Driven Design
Al...
What's essential?
Domain model
Interaction with it
Use cases
What's not essential?
“The database is an implementation detail”
–Cool software architect
The core doesn't need to
know about it
!
!
!
!
!
!
What about interaction?
!
The core doesn't need to
know about it
!
!
!
Infrastructure
The world outside
!
!
!
Web browser
Terminal
Database
Messaging
Filesystem
(E)mail
Mmm... layers Layers
allow you to
separate
Layers
allow you to
allocate
Layers
have
boundaries
Rules
for crossing
Rules about
communication
Actually: rules about dependencies
The dependency rule
–Robert Martin, Screaming Architecture
What crosses layer
boundaries?
Message
Messages
someFunctionCall(
$arguments,
$prepared,
$for,
$the,
$receiver
);
$message = new TypeOfMessage(
$some,
$relevant,...
What about the application
boundary?
The app
Message
The world outside
How does an app allow
incoming messages at all?
By exposing input ports
Routes
Console commands
A WSDL file for a SOAP API
Ports use protocols for
communication
Each port has a language of its own
Web (HTTP)
Messaging (AMQP)
HTTP
Request
Form
Request
Controller
Entity
Value object
W
eb
port
Translate
the
request
Repository
Adapters
The translators are called: adapters
"Ports and adapters"
Ports: allow for communication to happen

Adapters: translate messages from the world outside
== Hexa...
An example
Plain HTTP
message
$_POST,
$_GET,
$_SERVER,
Request
POST /patients/ HTTP/1.1
Host: hospital.com
!
name=Matthias...
Command
$command = new RegisterPatient(
$request->get('name'),
$request->get('email')
);
Expresses
intention
Implies
chang...
class RegisterPatientHandler
{
public function handle(RegisterPatient $command)
{
$patient = Patient::register(
$command->...
Command
Command
handler A
Command
bus
Command
handler B
Command
handler C
HTTP
Request
Form
Request
Controller
Patient
(entity)
W
eb
port
PatientRepository
RegisterPatient-
Handler
RegisterPatient...
Change
New entity
(Patient)
Entity-
Manager
UnitOf-
Work
$patient = Patient::register(
$command->name(),
$command->email()...
SQL query
EntityManager
UnitOfWork
QueryBuilder
Persistence
port
Prepare
for
persistence
PatientRepository
C
ore
Infrastru...
Messaging (AMQP)
Persistence
(MySQL)
What often goes wrong:
we violate boundary rules...
EntityManager
UnitOfWork
QueryBuilder
PatientRepository
C
ore
Infrastructure
RegisterPatient-
Handler
Domain
Infrastructure
Application
Domain
PatientRepository
(uses MySQL)
EntityManager
UnitOfWork
...
PatientRepository
(uses MySQL)
Domain
Infrastructure
Application
Domain
RegisterPatient-
Handler
Domain
PatientRepository
(interface)
Dependency
inversion
PatientRepository
(uses MySQL)
RegisterPatient-
Handler
Domain
InMemory-
PatientRepository
Speedy
alternative
RegisterPatient-
Handler
PatientRepository
(uses MySQL)
PatientRepos...
"A good software architecture allows decisions [...]
to be deferred and delayed."
–Robert Martin, Screaming Architecture
IN CONCLUSION
what did we get from all of this?
Separation of concerns
Core
Infrastructure
Command
Command
Command
handler
Command
handler
Stand-alone use cases
Command
Command
handler
Intention-
revealing
Reusable
Infrastructure stand-ins
Regular
implementation
Interface
Stand-in, fast
implementation
This is all very much
supportive of...
See also: Modelling by Example
DDD
TDD
BDD
CQRS
QUESTIONS?
joind.in/16064
FEEDBACK?
Hexagonal Architecture - message-oriented software design (PHPCon Poland 2015)
Hexagonal Architecture - message-oriented software design (PHPCon Poland 2015)
Hexagonal Architecture - message-oriented software design (PHPCon Poland 2015)
Prochain SlideShare
Chargement dans…5
×

Hexagonal Architecture - message-oriented software design (PHPCon Poland 2015)

1 104 vues

Publié le

Commands, events, queries - three types of messages that travel through your application. Some originate from the web, some from the command-line. Your application sends some of them to a database, or a message queue. What is the ideal infrastructure for an application to support this on-going stream of messages? What kind of architectural design fits best?
This talk provides answers to these questions: we take the hexagonal approach to software architecture. We look at messages, how they cross boundaries and how you can make steady communication lines between your application and other systems, like web browsers, terminals, databases and message queues. You will learn how to separate the technical aspects of these connections from the core behavior of your application by implementing design patterns like the command bus, and design principles like dependency inversion.

Publié dans : Logiciels
  • @nox86 It is actually a decoupled version of that. In Hexagonal architecture, the layers are not physically separated as well.
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • @matthiasnoback Is it well known "tree layer architecture" with new buzzword? ref:https://en.wikipedia.org/wiki/Multitier_architectur
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici

Hexagonal Architecture - message-oriented software design (PHPCon Poland 2015)

  1. 1. HEXAGONAL ARCHITECTURE Message oriented software design By Matthias Noback
  2. 2. ARCHITECTURE What's the problem?
  3. 3. ! ! ! Nice app
  4. 4. ! ! ! Sad app
  5. 5. Your brain can't handle it M V C ?
  6. 6. Coupling to frameworks and libraries ! ! !
  7. 7. 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!"
  8. 8. That's actually outside in The boring stuff The interesting stuff Symfony Doctrine RabbitMQ Redis Angular
  9. 9. Slow tests DB Browser Message queue Key- value Filesystem
  10. 10. Why do frameworks not solve this for us? Because they can't ;)
  11. 11. Frameworks are about encapsulation
  12. 12. 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); ... }
  13. 13. Nicely hides the details $data = $serializer->deserialize( $request->getContent(), $request->getContentType() );
  14. 14. 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);
  15. 15. Hides a lot of details $patient = $repository->createQueryBuilder('p') ->where('p.anonymous = true') ->getQuery() ->getResult();
  16. 16. What about abstraction?
  17. 17. $patient = $repository->createQueryBuilder('p') ->where('p.anonymous = true') ->getQuery() ->getResult(); Concrete Concrete Concrete
  18. 18. $patients = $repository->anonymousPatients(); Abstract Nice DIY
  19. 19. Coupling to the delivery mechanism
  20. 20. 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
  21. 21. Reusability: impossible
  22. 22. Some functionality The web The CLI
  23. 23. Some functionalityRun it
  24. 24. Lack of intention-revealing code
  25. 25. data data data
  26. 26. 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?
  27. 27. R.A.D. Rapid Application Development B.A.D. B.A.D. Application Development
  28. 28. In summary Coupling to a framework Coupling to a delivery mechanism (e.g. the web) Slow tests Lack of intention in the code
  29. 29. THE ESSENCE of your application
  30. 30. The essence Other things
  31. 31. The "heart"?
  32. 32. "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."
  33. 33. What's essential? Domain model Interaction with it Use cases
  34. 34. What's not essential?
  35. 35. “The database is an implementation detail” –Cool software architect
  36. 36. The core doesn't need to know about it ! ! !
  37. 37. ! ! ! What about interaction? !
  38. 38. The core doesn't need to know about it ! ! !
  39. 39. Infrastructure The world outside ! ! ! Web browser Terminal Database Messaging Filesystem (E)mail
  40. 40. Mmm... layers Layers allow you to separate Layers allow you to allocate Layers have boundaries Rules for crossing
  41. 41. Rules about communication Actually: rules about dependencies
  42. 42. The dependency rule –Robert Martin, Screaming Architecture
  43. 43. What crosses layer boundaries? Message
  44. 44. Messages someFunctionCall( $arguments, $prepared, $for, $the, $receiver ); $message = new TypeOfMessage( $some, $relevant, $arguments ); handle($message);
  45. 45. What about the application boundary? The app Message The world outside
  46. 46. How does an app allow incoming messages at all? By exposing input ports Routes Console commands A WSDL file for a SOAP API
  47. 47. Ports use protocols for communication Each port has a language of its own
  48. 48. Web (HTTP)
  49. 49. Messaging (AMQP)
  50. 50. HTTP Request Form Request Controller Entity Value object W eb port Translate the request Repository
  51. 51. Adapters The translators are called: adapters
  52. 52. "Ports and adapters" Ports: allow for communication to happen Adapters: translate messages from the world outside == Hexagonal architecture Alistair Cockburn
  53. 53. An example Plain HTTP message $_POST, $_GET, $_SERVER, Request POST /patients/ HTTP/1.1 Host: hospital.com ! name=Matthias&email=matthiasn oback@gmail.com Command $command = new RegisterPatient( $request->get('name'), $request->get('email') );
  54. 54. Command $command = new RegisterPatient( $request->get('name'), $request->get('email') ); Expresses intention Implies change Independent of delivery mechanism Only the message
  55. 55. class RegisterPatientHandler { public function handle(RegisterPatient $command) { $patient = Patient::register( $command->name(), $command->email() ); $this->patientRepository->add($patient); } } Command Command handler
  56. 56. Command Command handler A Command bus Command handler B Command handler C
  57. 57. HTTP Request Form Request Controller Patient (entity) W eb port PatientRepository RegisterPatient- Handler RegisterPatient (command) Infrastructure Application Dom ain
  58. 58. 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='matthiasnoback@gmai l.com';
  59. 59. SQL query EntityManager UnitOfWork QueryBuilder Persistence port Prepare for persistence PatientRepository C ore Infrastructure
  60. 60. Messaging (AMQP) Persistence (MySQL)
  61. 61. What often goes wrong: we violate boundary rules...
  62. 62. EntityManager UnitOfWork QueryBuilder PatientRepository C ore Infrastructure
  63. 63. RegisterPatient- Handler Domain Infrastructure Application Domain PatientRepository (uses MySQL) EntityManager UnitOfWork QueryBuilder
  64. 64. PatientRepository (uses MySQL) Domain Infrastructure Application Domain RegisterPatient- Handler
  65. 65. Domain PatientRepository (interface) Dependency inversion PatientRepository (uses MySQL) RegisterPatient- Handler
  66. 66. Domain InMemory- PatientRepository Speedy alternative RegisterPatient- Handler PatientRepository (uses MySQL) PatientRepository (interface)
  67. 67. "A good software architecture allows decisions [...] to be deferred and delayed." –Robert Martin, Screaming Architecture
  68. 68. IN CONCLUSION what did we get from all of this?
  69. 69. Separation of concerns Core Infrastructure
  70. 70. Command Command Command handler Command handler Stand-alone use cases Command Command handler Intention- revealing Reusable
  71. 71. Infrastructure stand-ins Regular implementation Interface Stand-in, fast implementation
  72. 72. This is all very much supportive of... See also: Modelling by Example DDD TDD BDD CQRS
  73. 73. QUESTIONS? joind.in/16064 FEEDBACK?

×