Solutions Architecture, Software Development, Machine Learning and Embedded Ai.

Um pouco de conceitos sobre DDD – Parte V de VII


Na série de recortes de trechos de trabalhos acadêmicos que fiz no passado sobre DDD (Domain-Driven Design)... aqui vai a parte 5 contendo trechos do capítulo 5 de meus resumos sobre DDD. Geralmente, os padrões táticos do DDD são os mais conhecidos na comunidade de Desenvolvimento de Software, por isso, vale lembrar que também existem as técnicas de modelagem estratégica do DDD.

>

5. Padrões Táticos do DDD

No DDD, o modelo do domínio é criado (ou capturado) com base na linguagem ubíqua e no paradigma de modelagem de software conhecido como Model-Driven Design (MDD) (Evans, 2011).

Evans (2011) recomenda a modelagem de uma parte do software que reflita literalmente o modelo do domínio, tornando óbvias a relação entre o código e o modelo. Assim, um único modelo servirá tanto para análise quanto para implementação, atendendo estes dois propósitos ao mesmo tempo que emprega a linguagem ubíqua (Evans, 2011).

Desta maneira, espera-se que o modelo do domínio ganhe relevância para o projeto, uma vez que o código expressa a intenção real do modelo e vice-versa. Neste sentido, linguagens de programação orientadas a objetos facilitam a atividade de implementação por ser compatível com este nível de abstração do domínio (Evans, 2011).

Para projetos que usam o DDD, além da participação dos analistas de negócios ou analistas de requisitos e arquitetos é fundamental que os desenvolvedores que irão implementar o software participem ativamente do processo de modelagem deste software, colaborando para que o código e o modelo estejam sincronizados e que as mudanças realizados em um lado sejam refletidas noutro. Assim, um senso de propriedade coletiva sobre o modelo e o código é criado e mantido (Evans, 2003).

Nas seções seguintes deste capítulo, serão descritos os conceitos utilizados no DDD para permitir a implementação do modelo do domínio em um dado contexto delimitado. Os elementos que são apresentados aqui formam os blocos básicos de construção de um Projeto Orientado ao Modelo sob a perspectiva do DDD.

5.1 Entidade

De acordo com o contexto do domínio que está sendo modelado e da linguagem ubíqua em uso, é feita uma abstração do domínio onde captura-se aqueles elementos ou conceitos do negócio que requerem uma identificação única para cada objeto criado e alterado no sistema de software. Com base nesta abstração, os atributos (dados) e conjuntos de operações (comportamentos) aplicáveis à estes atributos são encapsulados em uma classe de objetos (OOP) conhecida no DDD como Entidade (Evans, 2003), que são tipos de Objeto por Referência (Evans, 2011).

Uma importante característica destes objetos (Entidades) é que seu estado pode sofrer várias alterações (ou mutações) ao longo do seu ciclo de vida e, ainda assim, deve ser possível identificá-lo e distingui-lo dos demais por meio de sua identidade única (Vernon, 2013).

No entanto, para obter-se uma identidade única para as Entidades, diversas estratégias poderão ser utilizadas conforme a complexidade exigida (Vernon, 2013):

  • O usuário do sistema provê valores únicos para ser usados como identidade da Entidade. Neste caso, a aplicação deverá garantir que se trata de uma chave ou identidade válida e exclusiva; (Vernon, 2013; p. 173)
  • A identidade única poderá ser gerada internamente pela aplicação à partir de um algoritmo específico que garanta sua unicidade. Este algoritmo pode ser desenvolvido juntamente com a aplicação ou ser obtido através de bibliotecas ou frameworks de programação. Exemplos típicos de identificadores únicos fornecidos por frameworks são o universally unique identifier (UUID) da plataforma Java, e o globally unique identifier (GUID) da plataforma .NET; (Vernon, 2013; p. 175)
  • A aplicação poderá obter a identidade única à partir de uma camada de persistência que utilize, por exemplo, um banco de dados relacional do tipo MySQL que dê suporte à criação de colunas do tipo auto-incremento; (Vernon, 2013; p. 180)
  • A aplicação poderá ainda receber a identidade única através de outro sistema ou Contexto Delimitado responsável por realizar esta atribuição de identidade. (Vernon, 2013; p. 182)

Uma decisão relevante durante o design da Entidade é escolher se a geração da identidade única irá ocorrer antecipadamente como parte da criação do objeto, ou se irá ocorrer tardiamente como parte do processo de persistência. Por isto, devem ser analisados os cenários de concorrência, consistência eventual, consistência transacional e de estabilidade da identidade única gerada conforme explicado por Vernon (2013).

Quando não se identifica um critério natural para a identidade única no próprio domínio da aplicação (como é o caso do uso do CPF ou RG no Brasil para registro de pessoas físicas), deve-se criar uma identidade (ou chave) única alternativa que é conhecida como Surrogate Identity. Esta chave ou identidade única não faz parte originalmente do domínio, mas serve para manter a rastreabilidade da Entidade internamente. É portanto uma chave artificial que pode ser gerada pela camada de persistência como as fornecidas pelas ferramentas ORM (object relational mapping) tal como Hibernate (Vernon, 2013; p. 186).

Por fim, é importante notar que durante o processo de instanciação de uma Entidade, esta deverá ter uma garantia que seu estado se encontra consistente. Isto é, as regras de negócio e requisitos de validação dos dados (invariantes) contidos em seus atributos devem ser aplicadas durante sua construção (com o uso de construtores parametrizados), persistência ou reconstituição que é o momento na qual é recuperada à partir de um armazenamento persistente (Vernon, 2013; p. 205-216).

5.2 Objeto Valor

Evans (2011) explica que Objeto Valor é um tipo de objeto cujo propósito é descrever ou computar alguma característica presente em um elemento do modelo. Neste caso, apenas o conjunto de atributos e a lógica deste elemento é suficiente para expressar um conceito do domínio sem a necessidade de possuir qualquer identidade.

Estes tipos de objetos devem ser imutáveis e possuir operações que sejam livres de efeitos colaterais, ou seja, que não alteram o estado do objeto (nem do sistema) e nem dependam de qualquer estado mutável (Evans, 2011).

A vantagem dos tipos por Valor é que permitem expressar a medição, quantidade, ou descrição de algo de maneira simples e fácil de criar, testar, usar, otimizar e manter (Vernon, 2013).

Exemplos comuns de Objeto Valor são números, strings de texto, datas, hora, tempo, objetos compostos por tipos primitivos ou ainda outros objetos complexos que juntos modelam um conceito do domínio que são expressados pela linguagem ubíqua (Vernon, 2013).

Em resumo, sempre que existir um conceito no modelo do domínio que não precise de uma identidade exclusiva, utilize um Objeto Valor ao invés de uma Entidade, simplificando o modelo e evitando a complexidade de se manter uma Entidade (Evans, 2003).

5.3 Agregado

Quando uma rede de objetos interligados entre si (também conhecida como grafo) sofre alguma alteração em seus dados, pode ser difícil garantir a consistência dos objetos modificados, sobretudo em um modelo com associações complexas (Evans, 2011).

Devido ao fato de cada objeto, supostamente, lidar apenas com o próprio estado consistente, estes podem tornar-se inconsistentes (do ponto de vista geral) por causa de mudanças em objetos relacionados que fazem parte desta rede conceitual de objetos (Evans, 2011).

Por isso, para manter um grafo de objetos consistentes entre si é necessário garantir que o conjunto das regras de negócio aplicavéis, isto é, as invariantes sejam devidamente respeitadas (Vernon, 2013). Para isto, os objetos do tipo entidade e valor objeto que formam o grafo devem ser definidos e protegidos dentro de uma fronteira lógica denominada Agregado (Evans, 2011).

Um Agregado deve possuir uma Entidade como raiz, ou seja, é o único objeto que poderá ser referenciado por outros objetos externos e interagir com os elementos internos do Agregado (Evans, 2011). Isto implica também que o tipo de consistência usada dentro das fronteiras do Agregado quando se aplica uma invariante é do tipo transacional, ou seja, qualquer operação é executada de forma imediata e atômica (Vernon, 2013).

...continua no próximo artigo.

Referências

Evans, 2011: Evans, Eric, Domain-Driven Design Reference, 2011

Evans, 2003: Evans, Eric , Domain-Driven Design: Tackling the Complexity in the Heart of Software, 2003

Vernon, 2013: Vernon, Vaughn , Implementing Domain-Driven Design, 2013