Neste artigo vamos entender como conceber uma entidade, através das técnicas de abordagem do DDD (Domain Driven Design). No passado (arrisco a dizer que é presente para alguns ainda nos dias de hoje) uma entidade era criada a partir de uma extração de substantivos, que eram entendidos pelo analista de sistema, e assim esta “entidade” no fim das contas virava uma classe onde mapeava para o banco de dados, se mostrando totalmente anêmica, ou seja, criando apenas uma camada de conversão entre o banco de dados e a aplicação.
Mas qual o problema desta abordagem?
Primeiro temos que analisar o porquê de se trabalhar assim. Eu imagino algumas possibilidades:
- Você cria uma classe que representa o banco de dados, para ter um entendimento mais semântico, ou mesmo deixar “tipado” na aplicação, para que seja possível pegar algum erro em tempo de compilação.
NOTA: Há benefício em tentar manter a semântica representando através de classes, porém, neste caso estamos apenas assegurando em tratar o conhecimento aplicado ao banco de dados, e não o conhecimento de negócio. O conhecimento de negócio deve o alvo e não reflexo.
- Você cria uma classe para usar de mapeamento para seu framework ORM consiga trabalhar, afinal de contas, ele precisa dessa camada, para entender o seu modelo, e traduzir para criação da estrutura e consumo do banco de dados relacional.
NOTA: Trabalhar com framework ORM é muito comum, já faz algum tempo. Ele agiliza o desenvolvimento, eu diria até que traz elegância ao design de código. Porém nosso foco é outro, o ORM exige classes de mapeamentos, do banco de dados relacional para aplicação. Isso foi visto por muito tempo como entidade, na realidade ainda é usado, isso vem de encontro com uma quebra de responsabilidade única. Neste caso a classe fica com responsabilidade de fazer o mapeamento e manter a regras de negócio. Uma entidade deveria se preocupar apenas com suas responsabilidades, nunca com terceiros. ORM faz com que não seja possível deixar alguns membros da classe com visibilidade privada. Um entidade deve ser uma representação de negócio, não importa como irá armazenar os dados, uma entidade pode virar 10 tabelas no banco relacional por exemplo. Claro que temos condição com ORM de fazer isso, através de mapeamentos, para uma classes representar várias tabelas no banco de dados. Mas ainda sim, estamos com excesso de responsabilidade.
Martin Fowler disserta em seu Blue Book sobre: Data Layer, onde temos o objetos de domínio e mapeamentos para camada de dados.
- Você adotou isso como prática, por ver isso como uma convenção, utilizada em muitos projetos, mesmo sem trabalhar com algum framework ORM.
NOTA: É sempre bom tentar manter uma prática de mercado, visando a manutenção de outros desenvolvedores, tendo em vista a adoção de um padrão como este, que estamos descrevendo. Porém ainda vejo o prejuízo de sobrecarga de responsabilidade, onde nos vemos “sujando” nossa entidade com requisitos de banco de dados e não somente da entidade.
Abstração
O processo de identificação de entidade está fortemente ligado a linguagem ubíqua, onde iremos entender e abstrair o modelo de domínio do negócio. Uma técnica muito comum para identificar uma entidade é comparar os valores envolvidos na possível entidade, por exemplo considere um conceito de pessoa. Se compararmos duas pessoas, com o mesmo Nome, significa que elas são a mesma Pessoa?
Sabemos que a resposta é não, portanto, se nome não é o atributo distintivo de uma pessoa, o que é? Endereço? Documento?
Uma pessoa é identificada por mais do que seus atributos, como nome, endereço, etc. Cada pessoa tem uma identidade única, que se manifesta de maneiras diferentes em diferentes sistemas. Cada sistema tem seus próprios atributos com os quais se preocupar, mas a pessoa é sempre a mesma entidade. Isso é algo vital no entendimento do que é uma entidade. Veja como o sigificado da entidade e não como é armazenado no meio x, y ou z.
Outro ponto importante no momento de decidir, é se perguntar: Se duas pessoas tiverem valores diferentes, mas o mesmo valor de identidade, elas são a mesma pessoa?
Se a resposta for sim, esta deve ser uma entidade. Neste caso devemos atribuir uma identidade substituta, o que normalmente se mostra um GUID ou uma sequência numérica provida pelo banco de dados, desde de que seja seguro, não há problema.
Bom, esta pergunta nem sempre terá como resposta sim, o que devemos fazer quando a resposta é não, neste caso devemos assumir que se trata de um objeto de valor, como vamos ver adiante.
Objeto de valor
Devemos nos esforçar para que a entidade seja um ponto que centraliza objetos de valor, em vez de um centralizador sub entidades, assim temos tipos de valor, onde podemos quantificar, testar, utilizar, otimizar e manter.
Vamos enumerar as caracteristicas de um objeto de valor:
- Mede, quantifica ou descreve uma coisa dentro do domínio
NOTA: Este conceito deve descrever um atributo que não está dentro do domínio de forma explícita, por exemplo, temos altura de uma pessoa, este não se trata de algo que que irá virar uma entidade (segundo as regras que vimos), porém mede e quantifica a altura de uma pessoa. Isso é uma característica conceitual.
- É imutavel
NOTA: Este se trata de uma regra comportamental na aplicação, bem simples: Este valor deve ser imutável depois que foi criado. Este deve ser construído no momento da construção da entidade. A linguagem de programação tem a responsabilidade de manter o encapsulamento, para que o valor seja imutável de fato.
- Comportamento livre de efeitos colaterais
NOTA: Caso seja o valor possua um comportamento específico, este não deve interferir na imutabilidade, ou seja, pode haver um comportamento, porém não pode violar a imutabilidade.
Agregados
Vamos entender o que é agregados, e onde impacta no assunto: Entidade.
Os agregados traçam um limite em torno de uma ou mais entidades. Um agregado cria um funil para todas as suas entidades para qualquer operação que ele suporte, escrita e leitura.
Cada agregado deve elencar uma entidade como raiz, que é o único membro visível (de forma virtual, não efetivamente invisível pela linguagem) do agregado ao qual qualquer membro fora do agregado tem permissão para enxergar.
Agregados são conceitos de domínio, que geralmente contém coleções, junto com campos simples, por exemplo: Um entidade com nome pedido é elencada como raiz do agregado, esta poderá conter um referencial da lista de itens do pedido. Para efeitos de operação em nosso sistema, devemos manter sempre o pedido como responsável por executar as operações.
Misture e bata tudo junto
Sabendo os conceitos descritos acima, podemos criar nossa entidade com segurança, tendo em mente que nossa entidade é um invólucro que devemos manter com cuidado, ela vira base para muitas outras definições do projeto.
A entidade também deve ter plena consciência sobre si, ou seja, ela deve conseguir saber como e quando executar as operações sobre si. Repare no termos: “quando” e “como”. Vamos para um exemplo.
Um pedido sempre deve ser criado com o status: “Aguardando pagamento”.
Ao receber a requisição de alterar status para confirmar o pagamento, o pedido deve alterar o pedido para pago e enviar uma notificação de pedido pago para o cliente.
Vamos aos detalhes…
Ao construir um pedido, sempre o status deve estar como “aguardando pagamento”… Perceba que sabemos quando o status deve estar nesse estado.
Ao receber a requisição de alterar status para confirmar o pagamento, o pedido deve alterar o pedido para pago… Neste sabemos quando alterar o estado do status de pagamento, e mais, sabemos que o pedido não pode ter a capacidade de enviar uma notificação através de um evento de domínio, ou seja, concluímos que o pedido sabe se atualizar e manter consistente, mas ele deve tomar responsabilidade sobre si, e delegar as demais responsabilidade para seu.
Conclusão
Uma entidade vira uma bola de neve, gerando dependência no seu contexto delimitado, gerando acoplamento neste. Como sabemos, é impossível 100% de desacoplamento, o que temos que ter em vista é reduzir o acoplamento e aumentar a coesão. Mas temos o dever de tentar manter nossa entidade consistente, e como um reflexo das regras de negócio de nosso sistema, e não uma mera representação de nossa estrutura do banco de dados em POO.
Espero ter elucidado sobre os conceitos de entidade.
Espero te ajudado!
Ate a próxima!