Objetos imutáveis ​​e DDD andam juntos?

18

Considere um sistema que usa DDD (também: qualquer sistema que use um ORM). O objetivo de qualquer sistema de forma realista, em quase todos os casos de uso, será manipular esses objetos de domínio. Caso contrário, não há efeito ou propósito real.

A modificação de um objeto imutável fará com que ele gere um novo registro após a persistência do objeto, o que cria inchaço maciço na fonte de dados (a menos que você exclua registros anteriores após modificações).

Percebo o benefício de usar objetos imutáveis, mas, nesse sentido, nunca consigo ver um caso útil para o uso de objetos imutáveis. Isso está errado?

Steven Evers
fonte

Respostas:

16

A computação usando objetos imutáveis ​​(como na programação funcional) não implica necessariamente a persistência de todos os objetos gerados!

Steven A. Lowe
fonte
Não estou vendo uma instância em que esse cenário use objetos imutáveis ​​de qualquer maneira - portanto eles estariam lá sem nenhum objetivo específico. Estou errado?
Steven Evers
1
eu estava a pensar que os objetos imutáveis seria útil para cálculos intermédios (em segmentos paralelos)
Steven A. Lowe
11

Imutável no domínio significa que ele deve ser imutável no banco de dados? Por exemplo, considere o seguinte, assumindo que o cliente sempre tenha um endereço:

customer.address = new Address('My Castle', 'Kings street');
customer_repo.save(customer);

agora o seguinte sql é executado considerando o ID do cliente é 1:

INSERT INTO addresses (customer_id, name, street)
VALUES (1, 'My Castle', 'Kings street');

agora a seguinte alteração é feita no endereço:

customer.address = new Address('Pauper palace', 'Outlands');
customer_repo.save(customer);

e a camada de persistência, sendo muito inteligente, executa o seguinte sql:

UPDATE addresses SET name='Pauper palance', street='Outlands'
WHERE customer_id = 1;

Dessa forma, você evita a sobrecarga de uma instrução DELETE AND INSERT separada. Também acho que alguns RDBMSs têm INSERT REPLACE ou algo assim. O MySql tem REPLACE .

andho
fonte
+1 Concordo com você no princípio geral: não vejo por que objetos de domínio imutáveis ​​devem necessariamente significar linhas de banco de dados imutáveis.
Andres F.
? No caso acima se sempre necessário para alterar o atributo da cidade da classe de endereço para um determinado cliente como poderíamos lidar com isso, mais assumir cliente pode ter vários endereços de modo que aa um para muitos navio relação entre cliente e endereços
Sudarshan
1
@Sudarshan, esta é apenas uma maneira de criar um 'objeto de valor imutável', não realmente imutável no banco de dados. Por razões de desempenho. Cada situação precisa ser tratada especificamente, é claro. Agora prefiro o Event Sourcing para o meu domínio, mas sou viciado nele.
andho
@Sudarshan para responder sua pergunta especificamente, você acabou de executar uma consulta de atualização que atualiza a linha para o novo valor. Se for um para muitos, os endereços terão algum tipo de identificador na Raiz Agregada do Cliente, que será usada para identificá-lo exclusivamente no DB. Em seguida, esse identificador e customer_id serão usados ​​para atualizar essa linha na tabela 'address'.
andho
@andho "esta é apenas uma maneira de criar um 'objeto de valor imutável', não realmente imutável no banco de dados". isso realmente fez o meu dia graças
Sudarshan
6

No DDD, objetos imutáveis ​​praticamente se igualam a objetos de valor. Esses objetos não são entidades, eles não têm uma identidade. Portanto, eu sempre persisto objetos de valor como colunas da entidade em que estão contidos (com o N / Hibernate você pode usar componentes para isso). Eles não têm uma mesa própria.

guillaume31
fonte
4

Depende de como o objeto imutável é mapeado no banco de dados. Se for apenas um componente como um DateTime (da biblioteca Joda Time), a alteração do valor resultará em uma atualização e não em uma inserção. No entanto, se o imutável for mais complexo e exigir uma linha em uma tabela, você terá o problema do inchaço.

Suponho que, embora seja um argumento fraco, você pode implementar uma trilha de auditoria dessa maneira. Todas as alterações no imutável podem ser rastreadas através das inserções. Existem muitas maneiras melhores de fazer isso.

No geral, ter objetos de domínio imutáveis ​​(em vez de apenas seus componentes) parece um pouco incompatível com a persistência.

Gary Rowe
fonte
De modo nenhum. Os componentes são muito úteis, pois permitem que os objetos do domínio sejam compostos de maneira diferente dos mesmos dados subjacentes. Os problemas vêm com a imutabilidade. Pessoalmente, eu trataria objetos de domínio como mutáveis ​​(com exceção dos campos de chave primária) e manteria isso simples.
Gary Rowe
"No geral, ter objetos de domínio imutáveis ​​(em vez de apenas seus componentes) parece um pouco incompatível com a persistência". Na sua opinião, onde precisaríamos ter objetos de valor que não devem ser modelados como componentes (terminologia do Hibernate)? --- Desculpe, eu havia digitado errado meu último comentário e, portanto, o excluí.
Sudarshan
Evite componentes quando uma única entidade estiver totalmente representada por uma linha e nenhum dos dados for compartilhado por outro objeto de domínio.
21413 Gary Gary Rowe
4

Isso depende do domínio. O DDD não especifica que o paradigma de programação seja orientado a objetos. O paradigma orientado a objetos é, no entanto, um adequado para o aplicativo típico que deve ser persistido em um banco de dados.

O DDD simplesmente declara que você deve criar seu software em torno de um modelo de domínio que represente o problema real que o software está tentando resolver. Se esse problema fosse, por exemplo, matemático por natureza, a implementação da camada de domínio usando programação funcional e estruturas de dados imutáveis ​​faria muito sentido.

Se, por outro lado, o problema é mais um aplicativo corporativo típico e você estiver usando estruturas de objetos imutáveis ​​para todos os seus objetos de domínio, então eu argumentaria que você não está seguindo o DDD. Eu posso apresentar pelo menos dois argumentos:

  • Sua implementação não representa um modelo de domínio do seu domínio com problemas. Seu domínio do problema, neste caso, consiste em entidades com estado para modificar. E não é assim que você o implementou.

  • Você não tem um idioma onipresente. A linguagem e os conceitos no modelo de domínio não seguem o que os especialistas em domínio estão usando.

Nota: o DDD usa objetos imutáveis ​​quando apropriado, eles são chamados apenas de objetos de valor.

Portanto, não estou dizendo que você não pode criar um aplicativo de banco de dados usando estruturas de dados puramente funcionais e não estou dizendo que não deveria. Eu simplesmente não acho que você possa chamá-lo de DDD, dependendo do tipo de aplicativo

Pete
fonte
Peter, ótima resposta. Você pode dar uma olhada na minha pergunta aqui stackoverflow.com/questions/13783666/… e me ajudar a descobrir meu problema. Eu acho que objetos de valor imutável são ótimos para softwares que não são relacionados à empresa. A maioria dos objetos de aplicativos corporativos é mutável na minha opinião. Imagine ter um objeto imutável de valor profundamente aninhado ... ContactInfo-> PhysicalLocation-> Address e você deseja atualizar o CEP ... criar o gráfico inteiro do objeto parece-me anticristo, não apenas um antipadrão. O que você acha?
Pepito Fernandez
3

Se você estiver usando um ORM como o Hibernate / NHibernate, poderá definir sua opção em cascata para excluir automaticamente objetos órfãos. Se uma pessoa tiver um endereço de objeto de valor, quando você alterar o endereço, o novo será salvo e o antigo será excluído porque agora está órfão.

Mike Rowley
fonte
0

Objetos de valor quase sempre são imutáveis ​​no DDD e o padrão flyweight pode ser usado para manter a duplicação desse objeto de valor na memória, assim como o .NET faz com seqüências de caracteres. A principal desvantagem é a memória de um lado e o outro lado é a eficiência criacional. Com o padrão flyweight, uma comparação baseada em valor deve ser feita para determinar se algum objeto de valor novo ou reconstituído já está dentro do cache de flyweight, mas qualquer outra comparação após esse ponto geralmente pode ser feita com segurança por referência, já que uma única instância é imposta. De qualquer maneira, quer o peso da mosca seja usado ou não, os objetos de valor ainda são imutáveis ​​porque eles têm apenas identidade intrínseca e, portanto, mudar seu valor mudaria sua identidade.

jpierson
fonte
-1

Existe outra maneira de usar objetos imutáveis ​​...

Em vez de armazenar os valores 5.0, 6.0, 7.0, 8.0 e copiar todo o registro todas as vezes, você pode armazenar algo assim: 5.0, +1.0, +1.0, +1.0 e criar dependências corretamente para reconstruir a sequência 5.0 , 6.0, 7.0, 8.0. Dessa forma, pequenas modificações levam apenas uma pequena quantidade de memória ...

tp1
fonte