Versão curta
A lógica do DDD é que os Objetos de Domínio são abstrações que devem atender aos seus requisitos funcionais de domínio - se os Objetos de Domínio não puderem atender facilmente a esses requisitos, isso sugere que você pode estar usando a abstração errada.
A nomeação de objetos de domínio usando substantivos de entidade pode fazer com que esses objetos fiquem fortemente acoplados entre si e se tornem objetos "deuses" inchados e podem gerar problemas como o desta pergunta, como "Onde é o lugar certo para colocar o objeto" Método CreateOrder? ".
Para facilitar a identificação da Raiz Agregada 'certa', considere uma abordagem diferente em que os Objetos de Domínio se baseiam nos requisitos funcionais de negócios de alto nível - ou seja, escolha substantivos que aludam a requisitos funcionais e / ou comportamentos que os usuários do sistema precisam executar.
Versão longa
O DDD é uma abordagem do OO Design, cujo objetivo é resultar em um gráfico de objetos de domínio na camada de negócios do seu sistema - os objetos de domínio são responsáveis por satisfazer seus requisitos de negócios de alto nível e, idealmente, devem poder confiar na camada de dados para coisas como o desempenho e a integridade do armazenamento de dados persistentes subjacente.
Outra maneira de ver isso pode ser os pontos desta lista
- Os substantivos de entidade geralmente sugerem atributos de dados.
- Substantivos de domínio devem sugerir comportamento
- A modelagem DDD e OO se preocupa com abstrações baseadas em requisitos funcionais e na lógica principal de domínio / negócios.
- A camada lógica de negócios é responsável por atender aos requisitos de domínio de alto nível
Um dos equívocos comuns a respeito do DDD é que os Objetos de Domínio devem se basear em alguma "coisa" física do mundo real (ou seja, algum substantivo que você possa apontar no mundo real, atribuído a todos os tipos de dados / propriedades), mas os dados Os atributos dessas coisas do mundo real não necessariamente são um bom ponto de partida ao tentar definir requisitos funcionais.
Obviamente, a lógica de negócios deve usar esses dados, mas os próprios objetos de domínio devem ser abstrações que representam requisitos e comportamentos funcionais de domínio.
Por exemplo; substantivos como Order
ou Customer
não implicam qualquer comportamento e, portanto, geralmente são abstrações inúteis para representar a lógica comercial e os Objetos de Domínio.
Ao procurar os tipos de abstrações que podem ser úteis para representar a lógica de negócios, considere os requisitos típicos que você pode esperar que um sistema cumpra:
- Como vendedor, desejo criar um pedido para um novo cliente para gerar uma fatura dos produtos a serem vendidos com seus preços e quantidade.
- Como consultor de atendimento ao cliente, desejo cancelar um pedido pendente para que o pedido não seja atendido por um operador de armazém.
- Como consultor de atendimento ao cliente, quero devolver uma linha de pedido para que o produto possa ser ajustado no estoque e o pagamento seja reembolsado novamente pelo método de pagamento original do cliente.
- Como operador de armazém, desejo exibir todos os produtos em um pedido pendente e as informações de remessa para que eu possa escolher os produtos e enviá-los pelo correio.
- etc.
Modelando requisitos de domínio com uma abordagem DDD
Com base na lista acima, considere alguns objetos de domínio em potencial para esse sistema de pedidos:
SalesOrderCheckout
PendingOrdersStream
WarehouseOrderDespatcher
OrderRefundProcessor
Como objetos de domínio, eles representam abstrações que se apropriam de vários requisitos de domínio comportamental; de fato, seus substantivos sugerem fortemente os requisitos funcionais específicos que eles atendem.
(Também pode haver infraestrutura adicional, como uma EventMediator
notificação para passar para os observadores que desejam saber quando um novo pedido foi criado ou quando um pedido foi enviado, etc.).
Por exemplo, SalesOrderCheckout
provavelmente precisa lidar com dados sobre Clientes, Remessa e Produtos, no entanto, não se preocupa com nada com o comportamento de pedidos de remessa, classificação de pedidos pendentes ou emissão de reembolsos.
Para SalesOrderCheckout
cumprir seus requisitos de domínio, é impor essas regras de negócios, como impedir que os clientes façam pedidos em excesso de itens, possivelmente executando alguma validação e talvez levantando notificações para outras partes do sistema - ele pode fazer tudo isso sem precisar depender necessariamente de qualquer dos outros objetos.
DDD usando substantivos de entidade para representar objetos de domínio
Existem vários perigos em potencial ao tratar substantivos simples como Order
, Customer
e Product
como Objetos de Domínio; Entre esses problemas estão aqueles a que você alude na pergunta:
- Se um método lida com a
Order
, a Customer
e a Product
, a qual objeto de domínio ele pertence?
- Onde está a raiz agregada para esses três objetos?
Se você escolher Substantivos da entidade para representar objetos de domínio, várias coisas podem acontecer:
Order
, Customer
E Product
estão em risco de crescer em objetos "deus"
- Risco de acabar com um único
Manager
objeto divino para amarrar tudo.
- Esses objetos correm o risco de ficar fortemente acoplados entre si - pode ser difícil atender aos requisitos de domínio sem passar
this
(ou self
)
- Um risco de desenvolver abstrações "vazadas" - ou seja, espera-se que objetos do domínio exponham dezenas de
get
/ set
métodos que enfraquecem o encapsulamento (ou, se não o fizer, algum outro programador provavelmente mais tarde ..).
- Risco de objetos de domínio ficarem inchados com uma mistura complexa de dados corporativos (por exemplo, entrada de dados do usuário por meio de uma interface do usuário) e estado transitório (por exemplo, um 'histórico' de ações do usuário quando o pedido foi modificado).
DDD, Design OO e Modelos Simples
Um equívoco comum sobre o DDD e o OO Design é que os modelos "simples" são de alguma forma 'ruins' ou 'antipadrão'. Martin Fowler escreveu um artigo descrevendo o Modelo de Domínio Anêmico - mas, como ele deixa claro no artigo, o próprio DDD não deve 'contradizer' a abordagem da separação limpa entre camadas
"Também vale enfatizar que colocar o comportamento nos objetos de domínio não deve contradizer a abordagem sólida do uso de camadas para separar a lógica do domínio de coisas como responsabilidades de persistência e apresentação. A lógica que deve estar em um objeto de domínio é lógica de domínio - validações, cálculos , regras de negócios - como você quiser chamá-lo ".
Em outras palavras, o uso de modelos simples para armazenar dados corporativos transferidos entre outras camadas (por exemplo, um modelo de pedido passado por um aplicativo do usuário quando o usuário deseja criar um novo pedido) não é a mesma coisa que um "modelo de domínio anêmico". modelos de dados 'simples' geralmente são a melhor maneira de rastrear dados e transferir dados entre camadas (como um serviço da Web REST, um armazenamento de persistência, um aplicativo ou interface do usuário etc.).
A lógica de negócios pode processar os dados nesses modelos e rastreá-los como parte do estado de negócios - mas não necessariamente se apropria desses modelos.
A raiz agregada
Olhando novamente para o exemplo de domínio Objects - SalesOrderCheckout
, PendingOrdersStream
, WarehouseOrderDespatcher
, OrderRefundProcessor
não há ainda nenhum óbvio Aggregate Raiz; mas isso realmente não importa, porque esses objetos de domínio têm responsabilidades muito separadas que parecem não se sobrepor.
Funcionalmente, não há necessidade de SalesOrderCheckout
conversar com o, PendingOrdersStream
porque o trabalho do primeiro é concluído quando ele adiciona um novo pedido ao Banco de Dados; por outro lado, o PendingOrdersStream
pode recuperar novos pedidos do banco de dados. Na verdade, esses objetos não precisam interagir diretamente (talvez um mediador de eventos possa fornecer notificações entre os dois, mas eu esperaria que qualquer acoplamento entre esses objetos fosse muito solto)
Talvez a raiz agregada seja um contêiner de IoC que injete um ou mais desses objetos de domínio em um controlador de interface do usuário, fornecendo também outras infraestruturas como EventMediator
e Repository
. Ou talvez seja algum tipo de serviço leve do orquestrador localizado no topo da camada de negócios.
A raiz agregada não precisa necessariamente ser um objeto de domínio. Para manter a Separação de Preocupações entre objetos do Domínio, geralmente é bom quando a raiz agregada é um objeto separado sem lógica de negócios.