Recebi uma pergunta interessante sobre arquietura esses dias. A pergunta era se deve ser possível trocar o método de acesso a dados de um repositório (repositório do DDD) sem influenciar a interface desse repositório. Ou seja, se posso, por exemplo, trocar de Entity Framework (EF) para NHibernate (NH) para Datasets e commands, sem afetar meu repositório.

Oras, teoricamente isso deve ser possível certo? Afinal de contas, onde ficariam o encapsulamento se não fosse? Ah, o mundo perfeito…

Infelizmente, no mundo real, não é assim que as coisas funcionam. A técnica e o framework de acesso a dados que você escolhe influenciam diretamente todo o resto da aplicação. Se eu optar por utilizar EF, por exemplo, minhas entidades herdarão obrigatoriamente de “EntityObject” e implementaria automaticamente “IEntityWithChangeTracker”, “IEntityWithKey” e “IEntityWithRelationships”. Já se usar NHibernate posso trabalhar com POCOs. NH não suporta nativamente o uso de LINQ (ainda), EF suporta. Entidades do EF são mais difíceis de testar, POCOs são bem mais fáceis, o que influenciaria todos os meus testes unitários da camada de domínio, que nada (supostamente) teria que ter a ver com os repositórios (que ficam no meio do caminho entre domínio e infra-estrutura). Tudo isso, e muito mais, influenciaria a maneira com que a aplicação seria modelada e trabalharia com as entidades.

Há ainda momentos em que, simplesmente por ajudar muito, vazamos conceitos do framework de acesso a dados para além do repositório, como ao passar uma Expression a um repositório (algo que funcionaria bem com EF por suportar LINQ), ou um objeto para realizar Query By Example no NH. Nos dois casos, trocar o framework daria uma bruta dor de cabeça se não alterássemos a interface do repositório.

Há ainda um conceito muito importante, que se eu encerrasse o post por aqui muita gente tomaria como óbvio e nem pensaria: o conceito de identidade nas entidades de domínio normalmente é expressado por um identificador, como um campo “Id”, do tipo inteiro, que nada tem a ver com o objeto em questão. É como se eu identificasse um cliente por um “número de cliente” que é algo totalmente aleatório e nada tem a ver com o cliente, e não pelo seu CPF, que é algo real. Pois bem, esse conceito é uma herança da primary key de bancos de dados relacionais. Se utilizássemos bancos de dados orientados a objeto, esse “Id” não precisaria existir, e métodos como “EncontrarClientePor(int id)” também não existiriam. você teria no seu lugar um método mais significativo para o domínio, como “EncontrarClientePor(CPF cpf)”, ou “EncontrarClientePor(Telefone tel)”. Viram como a abordagem de armazenamento de dados influencia a assinatura dos repositórios e toda a aplicação?

Ah, o mundo perfeito…