Domain-Driven Design: da curiosidade à prática

6º meetup da comunidade PHP Pernambuco

Luciano Queiroz

Senior PHP Software Engineer @ LPCDev

Backend Engineer @ Hello Fresh

Motivação

Brasil????

Agenda

  • Strategic Design
  • Bounded Contexts / Ubiquitous Language
  • Event Storming
  • Tactical Design
  • Architecture
  • Domain Blocks
  • Event Sourcing

O que é DDD?

Problem Space

Solution Space

O que é DDD?

"DDD é um conjunto de ferramentas que te auxiliam a entregar softwares de alto valor: estrategicamente e tecnicamente."

Vaughn Vernon - Domain-Driven Design Distilled

Domain-Driven design

1

Software é interpretado como centro de custo e não investimento.

2

O banco e modelagem de dados é muito priorizado ao invés das operações e processos do domínio.

"Businesses regularly put too much effort into developing glorified database table editors."

Vaughn Vernon - Implementing Domain-Driven Design

3

Desenvolvedores muito apegados a ferramentas e tecnologias para resolver problemas.

You're allowed and encouraged to use third party libraries, as long as you put them together yourself without relying on a framework or microframework to do it for you. An effective developer knows what to build and what to reuse, but also how his/her tools work. Be prepared to answer some questions about those libraries, like why you chose them and what other alternatives you're familiar with.

4

Estimativas são muito valorizadas, e criar estimativas leva tempo e energia, resultando em delay nas entregas. Desenvolvedores para atender as estimativas desenvolvem uma "Big ball of mud", porque não tem tempo/liberdade/conhecimento para modelar um software que reflete exatamente como o domínio funciona.

5

Baixa colaboração entre stakeholders e developers, resultando em muita tradução entre o que o stakeholder pensa e o código que o desenolvedor escreve.

Strategic Design

Como levar um motorista de um ponto ao outro no menor tempo possível?

Navigation

Destination

Origin

Route

Driver

Navigation

Destination

Origin

Route

Driver

Car

Plate

Alerts

Navigation

Destination

Origin

Route

Driver

Car

Plate

Alert

Collaborator

Location

Score

Rides

Navigation

Destination

Origin

Route

Alert

Collaborator

Location

Score

Driver

Car

Plate

RideAvailability

Commutation

Rider

Commutation

Commutation

Why not... Car rental?

Navigation

Destination

Origin

Route

Alert

Collaborator

Location

Score

Driver

Car

Plate

RideAvailability

Commutation

Rider

Commutation

Commutation

Rental

CarRentAvailability

Car

Duration

Total

Price

Renter

Commutation

Rental

Bounded Contexts

NavigationContext

RentalContext

CollaborationContext

CarPoolContext

Navigation

Routes

Destination

Origin

ETA

ETA

Commutation

Car

Rental

Price

Duration

Renter

CarOwner

SeatsAvailable

CarCapacity

Rider

Driver

Driver

Collaborator

Editor

Alert

Location

Car

Identifying the core domain

What's the core domain of the previous domain model?

NavigationContext

RentalContext

CollaborationContext

CarPoolContext

Navigation

Routes

Destination

Origin

ETA

ETA

Commutation

Car

Rental

Price

Duration

Renter

CarOwner

SeatsAvailable

CarCapacity

Rider

Driver

Driver

Collaborator

Editor

Alert

Location

Car

NavigationContext

RentalContext

CollaborationContext

CarPoolContext

Navigation

Routes

Destination

Origin

ETA

ETA

Commutation

Car

Rental

Price

Duration

Renter

CarOwner

SeatsAvailable

CarCapacity

Rider

Driver

Driver

Collaborator

Editor

Alert

Location

Car

Sub Domains

NavigationContext

RentalContext

CollaborationContext

CarPoolContext

Navigation

Routes

Destination

Origin

ETA

ETA

Commutation

Car

Rental

Price

Duration

Renter

CarOwner

SeatsAvailable

CarCapacity

Rider

Driver

Driver

Collaborator

Editor

Alert

Location

Car

Generic Domain

NavigationContext

RentalContext

CollaborationContext

CarPoolContext

Navigation

Routes

Destination

Origin

ETA

ETA

Commutation

Car

Rental

Price

Duration

Renter

CarOwner

SeatsAvailable

CarCapacity

Rider

Driver

Driver

Collaborator

Editor

Alert

Location

Car

Event Storming

Tactical Design

Architecture

Driver

Car (n)

Profile

Plate

Entities

<?php

declare(strict_types=1);

namespace RecipeApi\Domain;

use Prooph\EventSourcing\AggregateRoot;

class Driver extends AggregateRoot
{
    private $driverId;
    private $cars = [];
    private $email;

    public static function new(
        DriverId $driverId,
        Email $email
    ) : self {
        $self = new self();
        $self->recordThat(DriverWasRegistered::fromRequestData($recipeId, $email));
        return $self;
    }

    public function aggregateId(): RecipeId
    {
        return $this->driverId;
    }

    public function cars(): array
    {
        return $this->cars;
    }

    public function whenDriverWasRegistered(DriverWasRegistered $event)
    {
        $this->driverId   = DriverId::fromString($event->aggregateId());
        $this->email      = $event->email();
    }

    public function addCar(Car $car)
    {
        $this->recordThat(CarWasAdded::fromRequestData($this->driverId, $car));
    }

    public function whenCarWasAdded(CarWasAdded $event)
    {
        $this->cars[] = $event->car();
    }
}

Value Object

<?php

use Rhumsaa\Uuid\Uuid;

final class DriverId
{
    private $uuid;

    private function __construct(Uuid $uuid)
    {
        $this->uuid = $uuid;
    }

    public static function new(): self
    {
        return new self(Uuid::uuid4());
    }

    public static function fromString(string $uuid): self
    {
        return new self(Uuid::fromString($uuid));
    }

    public function __toString(): string
    {
        return (string) $this->uuid;
    }

    public function uuid(): Uuid
    {
        return $this->uuid;
    }
}

Event Sourcing

DriverWasCreated

2 CarWasAdded

1 CarWasRemoved

DriverWasCreated

1 CarWasAdded

Made with Slides.com