You are on page 1of 40

Hexagonal Architecture

Turn spaghetti code into lasagna

Leonard Mocanu - Tech. Lead


Iulian Popa - Tech. Lead
Agenda
What / Why

Ports / Adaptors

Layers / Boundary

Example

Q&A - 10 min
Why Hexagonal Architecture?
Your Nice Little Application
Your Big Sad Application
Model - View - Controller

M V C
How do you start a new project?
● Pick your favorite framework

● Install all dependencies

● Remove demo stuff

● Generate Entities

● Generate CRUD Controllers

● Done
Framework coupling and lack of intention...
Request and Form objects are web specific
public function newAction(Request $request)
{
$client = new Client();
$form = $this->createForm(new RegisterClientForm, $client);

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {


$em = $this->getDoctrine()->getManager();
$em->persist($client);
$em->flush();

return $this->redirectToRoute('task_success');
}

return $this->render('product/new.html.twig', array(


'form' => $form->createView(),
));
}
R.A.D
application development

B.A.D
application development
Maintainability Unmaintainable
application

analysis design code test support

“The only way to go fast is to go well” - Robert C. Martin (Uncle Bob)


What is Hexagonal Architecture?

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.


Turn spaghetti code into lasagne...
What’s essential...

The inside

Use Cases
What’s not that important...

The outside
Ports
Domain
Infrastructure model

Browser
Infrastructure
Application

Domain model
Core Domain

Terminal Database

E-mail
rt
HTTP Request
b po
We Forms

Controller

e st
Request qu
e re Entity
Adaptors th
te
sla
r an Value Object
T

Validator
Repository
Layers

Layers have properties:

- Layers allow for separation


- Layers create boundaries
- Layers allow you to allocate rules for
crossing layers
Rules for crossing boundaries

Robert Martin (Uncle Bob) - Screaming Architecture


What can cross boundaries?

Message

Message Message
Messages

Simple function... OOP perspective...

sendEmail( $message = new ClientWriteReviewToProduct(


$to, $clientId,
$from, $productId,
$subject $review,
); $rating
);

handle($message);
Application boundaries?

ge

Me
ssa

ssa
Me

ge
sa ge
es M
Ports and adapters
Feedback

≈ Hexagonal Architecture
by Alistair Cockburn
Product

Client

RCA
In summary: ports and adaptors

Ports: allow for communication to happen


- Web port
- Console command port

Adaptors: translate messages from the world outside


- Symfony framework
- Symfony console
- AWS SDK
Imagine this example

$_POST
$_GET
HTTP Message
$_SERVER
message (command)
Request (from
symfony)

POST /client/ HTTP 1.1


Host emag.ro
$command = new RegisterClient (
$request->get('name'),
Content-Type: multipart/form-data
------WebKitFormBoundary7MA4YWxkTrZu0gW
$request->get('email')
Content-Disposition: form-data; name="username" );
iulianpopa
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="password"
secret
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="email"
iulian.popa@emag.ro
Express
intention
Independent of
the delivery
mechanism

Message
(command)

$command = new RegisterClient(


$request->get(‘username’),
$request->get(‘password’),
Implies
$request->get(‘email’)
); change
Message Send for
Handler
(command)
processing

class RegisterClientHandler() {

public function handle(RegisterClient $command) {

$client = new Client();


$client->setUsername($command->get(‘username’))
->setPassword($command->get(‘password’))
->setEmail($command->get(‘email’));
$this->clientRepository->save($client);

}
}
Use a bus for commands
Vote
Feedback
Handler

RegisterClient Leave
Command Bus Feedback
Command
Handler

SimpleBus: Symfony Bridge Register


Client
Tactician: The PHP league Handler

Laravel: built in
rt
HTTP Request b po
We Forms

Register Client Handler


Controller
and
m
C om
Request nt
Clie
ter
gis
Re
re
tu

Client Entity
uc
str

ion
ra

ain
at
Inf

lic

m
Client Repository
p

Do
Ap

re
Co
Entity
New Entity
Manager SQL INSERT
(Client)
Unit of Work

INSERT INTO emag_clients


$client = new Client();
SET username=’iulianpopa’,
$client->setUsername($command->get(‘username’))
->setPassword($command->get(‘password’)) email=’iulian.popa@emag.ro’,
->setEmail($command->get(‘email’)); password=’$2y$10$lWFLKcHrwwPpQ6G
$this->clientRepository->save($client); 6a88ncO3DfrICTcI9hQUXzOWSaKmAHJ
w418QYu’
Client Repository

UnitOfWork

Core Domain
Entity
Manager t
por
Application nc
e
Query st e
r si
Builder
Pe

Infrastructure SQL query


HTTP Request
Events

Persistence
Who noticed the mistake?

The boundary rules are violated...


Client Repository

UnitOfWork

Core Domain
Entity
Manager
rt
Application po
Query nce
Builder si ste
r
Pe SQL query
Infrastructure
Entity
Manager

Core Domain
Register Client SQL query
ClientRepository
Handler

Application

Infrastructure
Client Repository Entity
Interface Manager
D
e
In pen
ve d
rs en
io cy
n
Core Domain
Register Client SQL query
ClientRepository
Handler

Application InMemoryRepository
Speedy
alternative

Infrastructure
Hexagonal architecture is also supportive of ...

DDD
Event Sourcing

BDD

TDD

CQRS
Conclusions
● Separation of concerns

● Agnostic to the outside world

● Easier to test in isolation

● Reutilization & Intention revealing

● The Ports and Adapters are replaceable

● Independent of external services

● When and where you should use Hexagonal Architecture depends on the project
Thank you!
Leonard Mocanu Iulian Popa

@leonardmocanu2 @iulyanpopa

leonard.mocanu@emag.ro iulian.popa@emag.ro

You might also like