Objetos DDD e Valor. Os Objetos de Valor mutáveis ​​são um bom candidato para Não Agregados. Entidade raiz?

9

Aqui está um pequeno problema

Tenha uma entidade, com um objeto de valor. Não é um problema. Substituo um objeto de valor por um novo e, em seguida, o nhibernate insere o novo valor e torna-o órfão, excluindo-o. Ok, isso é um problema.

Segurado é minha entidade em meu domínio. Ele tem uma coleção de endereços (objetos de valor). Um dos endereços é o MailingAddress. Quando queremos atualizar o endereço de correspondência, digamos que o CEP esteja errado, seguindo a doutrina do Sr. Evans, devemos substituir o objeto antigo por um novo, uma vez que é imutável (um objeto de valor, certo?).

Mas não queremos excluir a linha, porque o PK desse endereço é um FK em uma tabela MailingHistory. Então, seguindo a doutrina do Sr. Evans, estamos praticamente ferrados aqui. A menos que eu faça minhas entidades de endereços, não preciso "substituí-la" e simplesmente atualizar seu membro do CEP, como nos bons e velhos tempos.

O que você me sugeriria neste caso? Do meu ponto de vista, os ValueObjects são úteis apenas quando você deseja encapsular um grupo de colunas da tabela de banco de dados (componente no nhibernate). Tudo o que tem um ID de persistência no banco de dados é melhor para torná-lo uma Entidade (não necessariamente uma raiz agregada) para que você possa atualizar seus membros sem recriar todo o gráfico de objetos, especialmente se esse for um objeto profundamente aninhado.

Você concorda? Evans tem permissão para ter um objeto de valor mutável? Ou um objeto de valor mutável é candidato a uma Entidade?

obrigado

Pepito Fernandez
fonte
2
Existe algo como "objeto de valor mutável"? Eu sempre tive o valor da impressão que os objetos são imutáveis.
Herby
@herby Eu acho que você poderia ter um objeto mutável representando um objeto de valor DDD no código, mas você teria que considerar que, uma vez que você modifica o objeto, ele não faz mais referência ao mesmo objeto de valor DDD lógico, mas a um novo. Isso pode ser desejável, mas é uma receita para a confusão - criar objetos de valor imutáveis ​​no código é uma convenção inteligente.
MattDavey

Respostas:

8

Tudo o que tem uma identidade deve ser uma Entidade, e tudo o que não tem uma identidade é um valor simples, portanto, um objeto de valor.

Para citar Martin Fowler (que por sua vez cita Eric Evans)

  • Entidade: Objetos que possuem uma identidade distinta que percorre o tempo e diferentes representações. Você também ouve esses chamados "objetos de referência".
  • Objeto de valor: objetos importantes apenas têm a combinação de seus atributos.

Razão para tornar seu endereço um objeto de valor:

Se o seu endereço for mutável, você provavelmente irá estragar seu histórico de correspondência no final. Por exemplo, se você estiver enviando itens para um cliente, não pode ter certeza de qual endereço realmente enviou algo no passado, se o endereço ao qual sua tabela MailingHistory se refere foi alterado.

A entrada MailingHistory Enviamos o A764 para o endereço 657 pode significar Enviamos o artigo A764 para Boston ontem e enviámos o artigo A764 para Nova York amanhã.

Se o endereço de correspondência tiver sido alterado, não será necessário excluir o antigo. Mantenha-o e marque-o como inativo , e o novo como ativo .


É claro que você poderia tratar seu endereço como uma Entidade, mas somente ao atualizá-lo não mudaria o local real ao qual o endereço está se referindo, portanto, permitindo apenas a correção de erros de digitação.

Se você tem certeza de que pode garantir isso, seria possível usar uma Entidade.


Mas a melhor solução IMHO é não referenciar uma entidade de endereço no seu histórico de correspondência, mas salvar o endereço específico diretamente na sua tabela de histórico de correspondência (basicamente copiando os dados do endereço).

Dessa forma, você sempre sabe para onde enviou suas coisas (ou o que quer que esteja enviando) e, como usaria uma Entidade mutável, sua tabela de endereços não ficará desordenada.

Eu trabalhei com / em vários sistemas ERP e quase todos eles usaram essa abordagem.

Você terá alguma redundância em seu banco de dados, mas é a maneira mais pragmática do IMHO.

bicho-preguiça
fonte
Esta é provavelmente a solução mais livre de dor de cabeça. Somente se você espera que os canais de comunicação futuros exijam colunas extras e seu banco de dados seja muito grande ALTER, o uso de entidades em tabelas separadas poderá se tornar necessário. Isso, por sua vez, exige estratégias como "sempre associe o endereço / telefone / e-mail mais recentes " nas suas SELECTconsultas, o que é difícil manter a manutenção e a eficiência. Mantenha-o simples, se possível.
Timo
O @Timo "sempre aderir ao endereço / telefone / e-mail mais recente" não é difícil se você desnormalizar um pouco os dados adicionando um activesinalizador-. É claro que você deve sempre usar and active = truesuas Joins, manter o sinalizador atualizado e adicionar uma contraint à sua tabela para que, por exemplo, apenas um e-mail para cada cliente possa ter esse sinalizador definido como verdadeiro.
Preguiça
Isso introduz o problema de desativar o anterior. Se você substituiu o objeto de endereço "atual" da sua instância no código e acessa o código de acesso a dados, ele não saberá (1) se existe ou não um novo, nem (2) qual o potencial potencial um foi. Portanto, toda operação de salvamento terá que fazer algo complicado, como "primeiro desative todos os endereços relacionados no banco de dados" e salve o atual com active=true. Não é isso que eu chamaria de simples, e é exatamente por isso que gosto da sua solução.
Timo
2

Eu vejo duas coisas:

  1. Está correto a alteração do código postal afetar um registro do histórico? Eu acho que seria lógico que o registro do histórico aponte para o endereço antigo e inalterado, para que você o envie para o endereço errado.

  2. No momento em que MailingHistory tem FK no endereço, o endereço deixou de ser um objeto de valor e se tornou entidade. Objetos de valor não têm identidade, permitindo que outras entidades façam referência a essa identidade. Você pode ter endereços em uma única tabela com outras tabelas apontando para ela, mas o único efeito é a economia de espaço. Do ponto de vista do domínio, se duas entidades tiverem o mesmo tipo de objeto de valor de referência, elas não compartilharão nenhum tipo de informação.

Eufórico
fonte
2

OMI, o objeto de endereço é uma entidade em seu domínio. É compartilhado por várias entidades, possui identidade própria e é exclusivo em todo o sistema.

Evans diz:

Um objeto definido principalmente por sua identidade é chamado de entidade.

margabit
fonte
Identidades de domínio, na minha opinião, não têm nada a ver com identidade de persistência. De acordo com o livro do Sr. Evan.
Pepito Fernandez 12/12
Você está certo. Eu edito minha resposta. O que quero dizer é que o objeto Address é importante nesse domínio específico, é único. A IMO, a Chave estrangeira e a Chave primária, é um sinal de que é realmente um objeto único em todo o domínio, portanto, possui uma identidade.
Margit 13/12 /
11
"o objeto de endereço ... tem sua própria identidade" - qual atributo de um endereço o identifica exclusivamente? Nenhum atributo único de um endereço é exclusivo, mas a combinação de atributos serve como identidade. Esta é a própria definição de um objeto de valor
MattDavey
@MattDavey: é uma boa conclusão, mas fico confuso quando Tony diz "não queremos excluir a linha, porque o PK desse endereço é um FK em uma tabela MailingHistory". Isso significa para mim que o objeto Endereço também tem um significado fora do 'Segurado' agregado. O que me indica que o objeto 'Address' não deve ser um ValueObject. O que você acha?
Marginal #
Poderíamos dizer que os Objetos de Valor seriam invariavelmente composições de propriedade total (UML) pelo pai? Além disso, um objeto de valor não faria sentido sem seu pai e não pode ser compartilhado entre pais.
Sudarshan