Olá Hugo, muito interessante teu artigo principalmente quando relata problemas enfrentados no "mundo real" que estão poucos ligados de fato ao modelo arquitetônico da solução.
Tenho algumas questões e gostaria do teu ponto de vista. Quero ressaltar que são dúvidas embasadas em domínios que possuem regras de negócio e não CRUDs:
Você diz que as entidades em certos momentos podem ser anêmicas ou ricas. Como você faz OOP em cima de entidades anêmicas? Não consigo imaginar isso de nenhuma forma pois são somente estruturas de dados passando para os casos de uso/serviço e todas as regras de negócio ficando por conta dessa camada.
Quando a entidade de persistência e domínio são representados na mesma classe noto problemas de encapsulamento, por exemplo para que o Hibernate funcione exige construtor padrão e get/set para os atributos. Como garantir encapsulamento para uma classe assim?
Quando faz o acesso do caso de uso há uma dependência externa acessando diretamente a classe concreta não seria um pouco ingênuo? Acho que o preço de por uma interface ali pra abstrair muito barato do que, se no futuro, tiver que acessar outro serviço externo ou a API do atual mudar. Já tive essa dor de depender de classe externa e ter que alterar inúmeros pontos de chamada puramente por não ter abstraído isso quando foi concebido.
Mineiro muito bem-humorado, apaixonado por tecnologia e cafe.
Entusiasta na arte da escrita, e adoro aprender e compartilhar conhecimento.
Engenheiro de Software at Kiwify
Location
Brasil
Education
Sistemas de Informação - Universidade Federal de Viçosa
Kauan,
Atualmente para que as entidades sejam gerenciadas através do EntityManager ou Session do Hibernate não é necessário que a classe contenha getters e setters, apenas o construtor default. Então é possível favorece o uso do construtor cheio ou de builders para manter o encapsulamento, e também distribuir a responsabilidades de atualizar o estado dos atributos a metodos. Dessa forma podemos nos beneficiar do mecanismo de Dirty Checking do Hibernate para que ele mesmo defina qual são as melhores operações SQL e o melhor momento para atualizar o estado da entidade no BD.
Software Engineer - Backend | Cloud
I write about software engineering, career, and distributed systems.
In my spare time, I play video games and D&D.
Opinions are my own.
Boas perguntas Kauan! Vou considerar o disclaimer que você mencionou (não-cruds). Vamos lá:
Nesse caso não faz né? Se seu domínio exige entidades ricas por qualquer que seja o motivo eu não vejo razão pra tentar justificar um domínio anêmico. Esse é o principal mote do meu texto: "Os requisitos e o teu problemas que vão guiar o teu design". Se o seu design requer um domínio complexo então as suas entidades não serão anêmicas e logo você vai usar OOP. Se o seu domínio for composto apenas de estrutura de dados indo pra lá e pra cá então você vai ser mais anêmico, menos OO e mais procedural.
Concordo, você precisa obedecer as regras do framework. Mas aí fica a pergunta: Por que você precisa do encapsulamento no caso específico de uma entidade anêmica? A vantagem do encapsulamento ali vale mais do que a simplificidade de uso do framework? Se sim, eu diria pra manter os modelos separados, se não então mantém eles juntos.
Porque seria ingênuo? O Linhares na thread que originou essa discussão fez um excelente ponto que software complexo de vdd é extremamente difícil de você olhar o futuro e acertar qual vai ser a interface correta. Existem boas chances do nosso serviço que você pensou não encaixar direitinho na interface que você possuia. Tendo dito isso, note que eu descrevo qual foi minha experiência nos últimos 8 anos. Os nossos serviços dependem exclusicamente de um serviço externo que é fornecido por uma equipe específica. Se o fornecedor mudar, provavelmente será a mesma equipe que vai mudar ele, eu só preciso mudar a implementação da minha Facade em 1 único ponto. No nosso caso que você teve que alterar diversos pontos, o que deve ter ocorrido foi uma Facade não ser bem definida e detalhes externos vazaram para dentro do caso de uso. Se você trabalha em um software que dependencias externas mudam ou podem mudar com frequência, uma interface faz sentido, até porque você provavelmente tem os requisitos necessários pra criar uma abstração. Agora, criar uma abstração porque as coisas podem mudar, sem requisitos, só no "eu acho que vai mudar", existem boas chances que a sua interface não vai conseguir abstrair o contrato de fato. Como eu falei, tem software rodando faz 10 anos com os mesmos serviços como dependência, isso cobriu 90% dos casos. Valeria realmente a pena ter gastado energia pros outros 10%? No nosso contexto, não valeu e não vale à pena.
Gostei demais das perguntas, torna a discussão bem rica! obrigado demais por participar.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Olá Hugo, muito interessante teu artigo principalmente quando relata problemas enfrentados no "mundo real" que estão poucos ligados de fato ao modelo arquitetônico da solução.
Tenho algumas questões e gostaria do teu ponto de vista. Quero ressaltar que são dúvidas embasadas em domínios que possuem regras de negócio e não CRUDs:
Kauan,
Atualmente para que as entidades sejam gerenciadas através do EntityManager ou Session do Hibernate não é necessário que a classe contenha getters e setters, apenas o construtor default. Então é possível favorece o uso do construtor cheio ou de builders para manter o encapsulamento, e também distribuir a responsabilidades de atualizar o estado dos atributos a metodos. Dessa forma podemos nos beneficiar do mecanismo de Dirty Checking do Hibernate para que ele mesmo defina qual são as melhores operações SQL e o melhor momento para atualizar o estado da entidade no BD.
Boas perguntas Kauan! Vou considerar o disclaimer que você mencionou (não-cruds). Vamos lá:
Gostei demais das perguntas, torna a discussão bem rica! obrigado demais por participar.