A (small) Hexagonal architecture
inside a Symfony application

By Alessandro Lai / @AlessandroLai

IT Meeting - 18/03, Facile.it

Hexagonal Architectures

Hexagonal Architecture is an architecture defined by establishing a perimeter around the domain of your application and establishing adapters for input/output interactions.

By establishing this isolation layer, the application becomes unaware of the nature of the things it's interacting with.

Scheme

Hexagonal Architectures: TL;DR

  • The hexagon is the core of you app
  • The hexagon contains all the business domain logic
  • The hexagon communicates
    ONLY through ports and adapters

So...

  • Why so popular right now?
    • Microservices!
  • Why don't we see it so much?

A little history...

  • Listened to a XPUG presentation about it
  • At the same time, I was nearly ready
    to start a new project...

Blaine

  • Shiny new technologies
    • PHP 7 (yay!)
    • Symfony 3
    • Docker & Docker-composer
  • Looked like a microservice...
    • Isolated
    • In charge of a single domain (invoices)
    • Adapter from BU to accounting software

Complications

  • A microservice is surrounded by other microservices
  • MVP was substitution of previous system
    (Caronte)
  • Couldn't force all the clients to change immediately
    (Shark, Cougar)

Change of plans

What if we use hexagons as a design pattern
instead of an architectural one?

Bundles as hexagons

  • InvoiceBundle
    core domain
  • ApiBundle
    REST endpoints
  • PDFBundle
    invoice as files
  • WebPanelBundle
    a simple web interface
  • ESABundle
    adapter to accounting software

InvoiceBundle

I used the technologies as adapters:

  • Doctrine
    • Entities as persistence and domain model
    • Additional models and interfaces to avoid exposure of core
  • Symfony validator
    • On entities to enforce business logic and reject errors
  • Symfony services
    • Adapters/ports from/to the hexagon or between bundles

ApiBundle

  • POST: creation of new invoices
    • Should emulate same behaviour of previous API (Caronte)
    • POSTing is tested to ensure similarity
    • Some changes where required anyway...
  • GET: fetch the invoice in PDF format
    • PDFBuilder (adapter to hexagon)
    • InvoiceLocator Repositories (adapter from Blaine to Caronte DB)
    • PrintableMappers (adapter to PDFBundle)

PDFBundle

  • PrintableModels
    • Level of abstraction
  • PrintableMappers
    • Adapter from other bundles
  • Internal rendering of PDF (Twig + PsPDF)
  • Result is sent back as file content (string)

WebPanelBundle

  • Bootstrap
  • Simple web interface
  • Just an interface for the services of the bundles

ESABundle

  • Work in progress...
  • Internal models (isolation)
  • Easy to replace

The End