Domain-Driven Design em PHP: transforme o caos em ordem
\n\nVocê já sentiu que seu projeto PHP está crescendo como uma bola de neve? No começo, tudo é simples: alguns controladores, um model, algumas consultas ao banco. Mas depois de seis meses, você está afogado em código espaguete, onde a lógica de negócio está espalhada pelos serviços, e uma simples mudança de requisito leva uma semana.
\n\nFamiliar? Bem-vindo ao clube. Mas a boa notícia é: Domain-Driven Design (DDD) não é uma teoria abstrata dos livros grossos do Eric Evans. É uma ferramenta prática que realmente ajuda a escrever código PHP compreensível tanto para os negócios quanto para os desenvolvedores.
\n\nNeste artigo, vamos explorar o DDD na prática. Sem enrolação, com exemplos reais em PHP. Você vai aprender como implementar DDD no seu projeto sem quebrar a cabeça e sem reescrever tudo do zero. Vamos nessa!
\n\nO que é Domain-Driven Design e por que você precisa dele como dev PHP?
\n\nImagine que você está criando um e-commerce. Você tem descontos, carrinho, pedidos. A lógica de negócio: "desconto não acumula com cupom", "pedido não pode ser cancelado após o envio". Se você guarda essa lógica nos controladores ou a espalha pelos models do ORM, mais cedo ou mais tarde vai se perder.
\n\nDDD é uma abordagem que coloca o domínio de negócio (sua área de conhecimento) no centro do desenvolvimento. Em vez de pensar em tabelas e consultas SQL, você pensa em entidades, valores e eventos.
\n\nPara PHP, isso é especialmente relevante. A linguagem é flexível, mas sem uma arquitetura clara, os projetos rapidamente viram "legado". O DDD fornece uma estrutura que permanece legível mesmo depois de um ano.
\n\nDesign Estratégico vs Design Tático
\n\nO DDD se divide em duas grandes partes:
\n- \n
- Design Estratégico — é o mapa do seu projeto. Você identifica Contextos Delimitados (Bounded Contexts) e constrói uma Linguagem Ubíqua (Ubiquitous Language). Por exemplo, no contexto "Catálogo", um produto é apenas um conjunto de características; já no contexto "Pedido", ele é uma unidade com preço e quantidade. \n
- Design Tático — são os blocos de construção: Entity, Value Object, Aggregate, Repository, Domain Service, Domain Event. Vamos focar neles. \n
Design Tático em PHP: os blocos do DDD
\n\nVamos ver como os principais padrões do DDD se parecem em PHP. Esqueça o ActiveRecord do Laravel ou Symfony — aqui estamos construindo um modelo independente de framework.
\n\n1. Entity (Entidade)
\nUma entidade é um objeto que possui um identificador único e muda ao longo do tempo. Por exemplo, User ou Order. Comparamos entidades pelo ID, não pelos campos.
<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Domain\\Entity;\n\nuse App\\Domain\\ValueObject\\UserId;\nuse App\\Domain\\ValueObject\\Email;\n\nclass User\n{\n public function __construct(\n private UserId $id,\n private string $name,\n private Email $email\n ) {}\n\n public function getId(): UserId\n {\n return $this->id;\n }\n\n public function changeEmail(Email $newEmail): void\n {\n // Aqui pode haver lógica de negócio: verificar se o email já não está em uso\n $this->email = $newEmail;\n }\n\n public function getEmail(): Email\n {\n return $this->email;\n }\n}\n\n\n2. Value Object (Objeto de Valor)
\nUm Value Object é um objeto imutável que é definido por seus atributos, não por um identificador. Dois Value Objects são iguais se todos os seus campos coincidirem. Clássicos: Money, Email, Address.
<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Domain\\ValueObject;\n\nclass Email\n{\n private string $value;\n\n public function __construct(string $value)\n {\n if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {\n throw new \\InvalidArgumentException('Endereço de email inválido');\n }\n $thi