Estou mergulhando no DDD (Domain driven design) e, enquanto me aprofundo nele, há algumas coisas que não entendo. Pelo que entendi, um ponto principal é dividir a lógica de domínio (lógica de negócios) da infraestrutura (banco de dados, sistema de arquivos etc.).
O que me pergunto é: o que acontece quando tenho consultas muito complexas, como uma Consulta de cálculo de recursos materiais? Nesse tipo de consulta, você trabalha com operações de conjunto pesado, o tipo de coisa para a qual o SQL foi projetado. Fazer esses cálculos dentro da Camada de Domínio e trabalhar com muitos conjuntos é como jogar fora a tecnologia SQL.
Fazer esses cálculos na infraestrutura também não pode acontecer, porque o padrão DDD permite alterações na infraestrutura sem alterar a Camada de Domínio e sabendo que o MongoDB não possui os mesmos recursos, por exemplo, SQL Server, isso não pode acontecer.
Isso é uma armadilha do padrão DDD?
fonte
... is like throwing away the SQL technology
Só porque uma determinada tecnologia pode fazer algo não significa que é a melhor escolha. É uma evidência anedótica, mas conheci muitas empresas que costumavam armazenar lógica de negócios no banco de dados e estão migrando para longe dele devido às dores de cabeça de manutenção de longo prazo que causam. Simplificando, mas os bancos de dados são destinados ao armazenamento de dados e as linguagens de programação são destinadas à transformação de dados. Eu não gostaria de usar um banco de dados para a lógica de negócios mais do que gostaria de tentar usar meu aplicativo para armazenar meus dados diretamente.Respostas:
Atualmente, é provável que você veja leituras (consultas) manipuladas de maneira diferente das gravações (comandos). Em um sistema com uma consulta complicada, é improvável que a própria consulta passe pelo modelo de domínio (o principal responsável por manter a consistência das gravações ).
Você está absolutamente certo de que devemos renderizar ao SQL o que é SQL. Portanto, projetaremos um modelo de dados otimizado em torno das leituras, e uma consulta desse modelo de dados geralmente adotará um caminho de código que não inclui o modelo de domínio (com a possível exceção de alguma validação de entrada - garantindo que os parâmetros na consulta são razoáveis).
fonte
Esta é a base do mal-entendido: o objetivo do DDD não é separar as coisas ao longo de uma linha rígida como "isso está no servidor SQL, portanto não deve ser BL", o objetivo do DDD é separar domínios e criar barreiras entre eles que permitem que os internos de um domínio sejam completamente separados dos internos de outro domínio e definam externos compartilhados entre eles.
Não pense em "estar no SQL" como a barreira BL / DL - não é isso que é. Em vez disso, pense em "este é o fim do domínio interno" como a barreira.
Cada domínio deve ter APIs externas que permitam trabalhar com todos os outros domínios: no caso da camada de armazenamento de dados , ele deve ter ações de leitura / gravação (CRUD) para os objetos de dados que armazena. Isso significa que o próprio SQL não é realmente a barreira, os componentes
VIEW
ePROCEDURE
são. Você nunca deve ler diretamente da tabela: esse é o detalhe da implementação que o DDD nos diz que, como consumidor externo, não devemos nos preocupar.Considere o seu exemplo:
É exatamente o que deveria estar no SQL e não é uma violação do DDD. É para isso que criamos o DDD . Com esse cálculo no SQL, isso se torna parte do BL / DL. O que você faria é usar uma exibição separada / procedimento armazenado / o que você tem e manter a lógica de negócios separada da camada de dados, pois essa é sua API externa. De fato, sua camada de dados deve ser outra Camada de Domínio DDD, onde sua camada de dados possui suas próprias abstrações para trabalhar com as outras camadas de domínio.
Esse é outro mal-entendido: ele diz que os detalhes da implementação podem mudar internamente sem alterar outras camadas do domínio. Não diz que você pode substituir apenas uma peça de infraestrutura inteira.
Novamente, lembre-se de que o DDD trata de ocultar internals com APIs externas bem definidas. A localização dessas APIs é uma questão totalmente diferente e o DDD não define isso. Ele simplesmente define que essas APIs existem e nunca devem mudar .
O DDD não está configurado para permitir a substituição ad-hoc do MSSQL pelo MongoDB - esses são dois componentes de infraestrutura totalmente diferentes.
Em vez disso, vamos usar uma analogia para o que o DDD define: carros a gás versus carros elétricos. Ambos os veículos têm dois métodos completamente diferentes para criar propulsão, mas eles têm as mesmas APIs: um on / off, um acelerador / freio e rodas para impulsionar o veículo. DDD diz que devemos ser capazes de substituir o motor (a gás ou elétrico) em nosso carro. Não diz que podemos substituir o carro por uma motocicleta, e isso é efetivamente o que é MSSQL → MongoDB.
fonte
Se você já esteve em um projeto em que a organização que paga para hospedar o aplicativo decide que as licenças da camada de banco de dados são muito caras, você apreciará a facilidade com a qual pode migrar seu banco de dados / armazenamento de dados. Tudo considerado, embora isso aconteça, não acontece com frequência .
Você pode obter o melhor dos dois mundos, por assim dizer. Se você considerar a execução de funções complexas no banco de dados como uma otimização, poderá usar uma interface para injetar uma implementação alternativa do cálculo. O problema é que você precisa manter a lógica em vários locais.
Desvio de um padrão arquitetural
Quando você se encontra em desacordo com a implementação de um padrão puramente ou se desvia em alguma área, você tem que tomar uma decisão. Um padrão é simplesmente uma maneira de fazer coisas para ajudar a organizar seu projeto. Nesse momento, reserve um tempo para avaliar:
Você verá que alguns padrões de arquitetura são adequados para 80-90% do seu aplicativo, mas não tanto para os bits restantes. O desvio ocasional do padrão prescrito é útil por razões de desempenho ou logísticas.
No entanto, se você achar que seus desvios cumulativos representam muito mais de 20% da arquitetura de seu aplicativo, provavelmente é apenas um ajuste inadequado.
Se você optar por continuar com a arquitetura, faça um favor e documente onde e por que você se desviou da maneira prescrita de fazer as coisas. Quando você obtém um novo membro entusiasmado da sua equipe, pode apontá-los para a documentação que inclui as medições de desempenho e justificativas. Isso reduzirá a probabilidade de solicitações repetidas para corrigir o "problema". Essa documentação também ajudará a desincentivar desvios desenfreados.
fonte
A lógica de manipulação de conjuntos em que o SQL é bom pode ser integrada ao DDD sem problemas.
Digamos, por exemplo, que eu precise conhecer algum valor agregado, contagem total de produtos por tipo. Fácil de executar em sql, mas lento se eu carregar todos os produtos na memória e adicionar todos eles.
Eu simplesmente apresento um novo objeto Domínio,
e um método no meu repositório
Claro, talvez agora eu esteja contando com meu DB tendo certas habilidades. Mas tecnicamente ainda tenho a separação e, desde que a lógica seja simples, posso argumentar que não é 'lógica de negócios'
fonte
Query
como parâmetros.repository.find(query);
. Eu li o mesmo, mas com oSpecs. That opens a door to leave
Query` como uma abstração e /QueryImpl
ou a implementação de consulta específica na camada de infraestrutura.I know some people do that
algumas pessoas são fundamentais e sua estrutura. SpringFramework tem muito disso :-). De qualquer forma, como o @VoiceOfUnreason sugeriu, a chave do DDD é manter a consistência dos escritos. Não tenho certeza sobre forçar o design com modelos de domínio cuja única finalidade é consultar ou parametrizar consultas. Isso pode ser abordado fora do domínio com estruturas de dados (pocos, pojos, dtos, mapeadores de linhas, o que for).Uma das maneiras possíveis de resolver esse dilema é pensar no SQL como uma linguagem assembly: você raramente codifica diretamente nele, mas onde o desempenho importa, é necessário entender o código produzido pelo seu C / C ++ / Golang / Rust e talvez até escreva um pequeno trecho no assembly, se você não puder alterar o código na linguagem de alto nível para produzir o código de máquina desejado.
Da mesma forma, no domínio de bancos de dados e SQL, várias bibliotecas SQL (algumas das quais são ORM ), por exemplo, SQLAlchemy e Django ORM para Python, LINQ for .NET, fornecem abstrações de nível mais alto, mas usam código SQL gerado sempre que possível para obter desempenho. Eles também fornecem alguma portabilidade em relação ao banco de dados usado, possivelmente com desempenho diferente, por exemplo, no Postgres e no MySQL, devido a algumas operações que utilizam um SQL específico ao banco de dados mais ideal.
E, assim como nas linguagens de alto nível, é fundamental entender como o SQL funciona, mesmo que seja apenas para reorganizar as consultas feitas com as bibliotecas SQL mencionadas acima, para conseguir a eficiência desejada.
PS: Prefiro fazer um comentário, mas não tenho reputação suficiente para isso.
fonte
Como sempre, essa é uma daquelas coisas que depende de vários fatores. É verdade que há muito que você pode fazer com o SQL. Também há desafios em usá-lo e algumas limitações práticas dos bancos de dados relacionais.
Como observa Jared Goguen nos comentários, o SQL pode ser muito difícil de testar e verificar. Os principais fatores que levam a isso são que ele não pode (em geral) ser decomposto em componentes. Na prática, uma consulta complexa deve ser considerada in toto. Outro fator complicador é que o comportamento e a correção do SQL dependem muito da estrutura e do conteúdo dos seus dados. Isso significa que testar todos os cenários possíveis (ou mesmo determinar o que são) geralmente é inviável ou impossível. A refatoração do SQL e a modificação da estrutura do banco de dados também são problemáticas.
O outro grande fator que levou ao afastamento do SQL são os bancos de dados relacionais que tendem a escalar apenas verticalmente. Por exemplo, quando você cria cálculos complexos no SQL para executar no SQL Server, eles serão executados no banco de dados. Isso significa que todo esse trabalho está usando recursos no banco de dados. Quanto mais você faz no SQL, mais recursos o banco de dados precisará, tanto em termos de memória quanto de CPU. Geralmente, é menos eficiente fazer essas coisas em outros sistemas, mas não há limite prático para o número de máquinas adicionais que você pode adicionar a essa solução. Essa abordagem é mais barata e mais tolerante a falhas do que construir um servidor de banco de dados monstro.
Esses problemas podem ou não se aplicar ao problema em questão. Se você conseguir resolver seu problema com os recursos disponíveis do banco de dados, talvez o SQL seja adequado para o espaço do problema. Você precisa considerar o crescimento, no entanto. Pode ser bom hoje, mas daqui a alguns anos, o custo da adição de recursos adicionais pode se tornar um problema.
fonte
Deixe-me primeiro esclarecer alguns equívocos.
DDD não é um padrão. E realmente não prescreve padrões.
O prefácio do livro DDD de Eric Evan afirma:
Portanto, é uma maneira de abordar o desenvolvimento de software e a modelagem de domínio, além de um vocabulário técnico que suporta essas atividades (um vocabulário que inclui vários conceitos e padrões). Também não é algo completamente novo.
Outra coisa a ter em mente é que um modelo de domínio não é a implementação de OO que pode ser encontrada em seu sistema - essa é apenas uma maneira de expressá-lo ou de expressar parte dele. Um modelo de domínio é a maneira como você pensa sobre o problema que está tentando resolver com o software. É como você entende e percebe as coisas, como você fala sobre elas. É conceitual . Mas não em um sentido vago. É profundo e refinado, e é o resultado de muito trabalho e coleta de conhecimento. É ainda mais refinado e provavelmente evoluiu ao longo do tempo, e envolve considerações de implementação (algumas das quais podem restringir o modelo). Deve ser compartilhado por todos os membros da equipe (e especialistas em domínio envolvidos) e deve orientar como você implementa o sistema, para que o sistema o reflita de perto.
Nada disso é inerentemente pró ou anti-SQL, embora os desenvolvedores de OO talvez sejam geralmente melhores em expressar o modelo nas linguagens de OO, e a expressão de muitos conceitos de domínio seja melhor suportada pelo OOP. Mas algumas vezes partes do modelo devem ser expressas em um paradigma diferente.
Bem, de um modo geral, existem dois cenários aqui.
No primeiro caso, algum aspecto de um domínio realmente exige uma consulta complexa, e talvez esse aspecto seja melhor expresso no paradigma SQL / relacional - portanto, use a ferramenta apropriada para o trabalho. Reflita esses aspectos em seu domínio e a linguagem usada na comunicação de conceitos. Se o domínio for complexo, talvez isso faça parte de um subdomínio com seu próprio contexto limitado.
O outro cenário é que a necessidade percebida de expressar algo no SQL é resultado de um pensamento restrito. Se uma pessoa ou equipe sempre foi orientada para o banco de dados em seus pensamentos, pode ser difícil para eles, devido à inércia, ver uma maneira diferente de abordar as coisas. Isso se torna um problema quando a maneira antiga falha em atender às novas necessidades e requer algum pensamento imediato. O DDD, como uma abordagem do design, é em parte sobre maneiras de encontrar o caminho para sair dessa caixa, reunindo e destilando o conhecimento sobre o domínio. Mas todo mundo parece ignorar essa parte do livro e se concentra em alguns dos vocabulários e padrões técnicos listados.
fonte
O Sequel se tornou popular quando a memória era cara, porque o modelo de dados relacionais oferecia a possibilidade de normalizar seus dados e armazená-los efetivamente no sistema de arquivos.
Agora a memória é relativamente barata, para que possamos pular a normalização e armazenar no formato em que a usamos ou até duplicar muitos dos mesmos dados por questão de velocidade.
Considere o banco de dados como um dispositivo simples de E / S , cuja responsabilidade é armazenar dados no sistema de arquivos - sim, eu sei que é difícil imaginá-lo, porque escrevemos muitos aplicativos com lógica de negócios importante gravada em consultas SQL - mas tente imaginar que o SQL Server é apenas mais uma impressora.
Você incorporou o gerador de PDF ao driver da impressora ou adicionou um gatilho que imprimirá a página de log de cada pedido de venda impresso em nossa impressora?
Suponho que a resposta será não, porque não queremos que nosso aplicativo seja acoplado ao tipo de dispositivo específico (nem mesmo falando sobre a eficiência dessa ideia)
Nos anos 70-90, o banco de dados SQL era eficiente, agora? - Não tenho certeza, em alguns cenários, a consulta de dados assíncrona retorna os dados necessários mais rapidamente do que várias junções na consulta SQL.
O SQL não foi projetado para consultas complicadas, foi projetado para armazenar dados de maneira eficiente e, em seguida, fornecer interface / linguagem para consultar dados armazenados.
Eu diria que construir seu aplicativo em torno do modelo de dados relacionais com consultas complicadas é abuso do mecanismo de banco de dados. É claro que os provedores de mecanismos de banco de dados ficam felizes quando você acopla firmemente sua empresa ao produto deles - eles terão todo o prazer em fornecer mais recursos que tornam isso mais forte.
fonte