Sobre Domain Driven Design

Domain Driven Design prioriza o negócio, me estimula a criar um código com maior cobertura de testes e melhor divisão de responsabilidades.

Este artigo apresenta anotações e conclusões da minha caminhada com DDD até aqui e estará em constante aperfeiçoamento:

Executar DDD exige habilidade com testes unitários

A essência na implementação desta abordagem é separar código de domínio (as famosas regras de negócio) de praticamente todos os aspectos computacionais como o mecanismo de persistência, os endpoints e o sistema de arquivos.

Isso naturalmente exige capacidade de criar código desacoplado.

Código desacoplado vai acabar desaguando na habilidade de criar classes coesas, funções pequenas, cada componente de código com uma função clara.

A disciplina que melhor cria código desacoplado, DDD ou não, é a disciplina de Testes Unitários.

Sem essa prática você simplesmente não tem recurso técnico para separar o código de domínio dos aspectos computacionais, se você nunca fez teste unitário, talvez nem consiga distingui-los.

Seu time está querendo trabalhar com DDD? Maravilha. Depois dos testes unitários.

PS: Teste de integração não ajuda PORCARIA nenhuma com DDD, integração testa as coisas acopladas, teste unitário exige desacoplamento.

Equilibrar performance e DDD É difícil

Imagine um recurso de atualização em lote que transfere todas as tarefas de um usuário para outro.

O que é mais rápido, 1) atualizar individualmente, carregando os dados de cada tarefa em memória, checando eventuais regras, e depois executando um update um a um ou 2) executar um sql update direto na base de dados?

Óbvio que é o sql update tem melhor performance, embora seja pobre nos aspectos de negócio e até arriscado.

O que sobrecarrega menos o servidor, 1) pegar um array/lista de entidades/structs, rodar algum tipo de codificação json e devolver tudo para o cliente ou 2) montar um stream que para cada item vai fazendo a codificação json e enviando a string para o buffer e liberando memória, um a um?

Óbvio que é o stream, pois com menos dados em memória você escala horizontalmente mais fácil com máquinas/dynos/vms com memória ram mais baixa.

Agora, em ambos os casos, a performance depende do aspecto computacional, como você articula isso com DDD?

Performance e DDD de maneira NENHUMA excluem-se mutuamente. Na verdade é perfeitamente possível criar estruturas e abstrações que permitirão um único sql update em um conjunto de dados ou uma resposta via stream.

Temos que ser programadores melhores para criar abstrações de domínio que possam ser implementadas com práticas que otimizem performance computacional.

Em muitos casos eu opto por abrir mão de atuar com DDD para poder fazer uma solução que atende um requisito de performance.

É uma escolha consciente de que faço isso não por ser melhor para o projeto, mas por eu mesmo não ser tecnicamente mais preparado hoje para fazer algo mais robusto no tempo e orçamento disponível.

Disciplina para não cair na tentação de excesso de regras no Front End

A experiência de programação front end melhorou muito em termo de expressividade e a cultura atual de desenvolvimento tem privilegiado colocar mais coisas no front end.

No livro original Erich coloca o uso de interfaces ricas e DDD como mutuamente exclusivos. Se você intenciona colocar lógica direto no código de interface, é impossível fazer DDD porque você simplesmente não estará separando seu domínio de um aspecto computacional, que é a camada de apresentação.

Um bom domínio deve permitir que o software se expresse para além de um framework de front end. A aplicação deve concentrar suas regras de domínio em uma boa API ou em um bom CORE de serviços e a(s) camada(s) de apresentação cuidar de apresentar.

Isso exige disciplina porque está cada vez mais tentador e mais fácil fazer um bom código no front end. Mas aqui vale o mesmo princípio do primeiro ponto, o código precisa estar bem desacoplado.

E se o software tem intenção de longevidade, pode apostar que você vai precisar trocar esse framework de front end em alguns anos.

Em termos de negócio, DDD é top para projetos de +4 anos

Considero quase impossível sustentar a dedicação para usar DDD em um projeto de tiro curto, algo que vai atender demanda específica ou que resolve alguma urgência.

Não há milagre, criar um bom código de domínio desacoplado leva mais tempo no início e ponto final.

Então se o projeto/negócio não tem uma perspectiva de longevidade e/ou se o dono do negócio fala que tudo bem para ele ou ela se for necessário refazer tudo em 4 anos, DDD não vale a pena, é melhor seguir por uma abordagem altamente pragmática.

Mas por que 4 anos? Porque esse costuma ser o ciclo de vida das versões de linguagens e frameworks LTS. Raramente uma versão LTS de qualquer coisas continuará recebendo suporte por mais de 4 anos.

E se seu código é bem desacoplado, se na hora de fazer o front end você não colocou muita regra de negócio ali, se você tem um core bem expressivo, com regras claras, você conseguirá mais facilmente manter o núcleo do seu software atualizado com as versões mais recentes da linguagem e será menos caro descartar certas partes da aplicação descontinuadas ou que perderam o sentido.

Contextos delimitados são, provavelmente, o tesouro mais valioso

Recentemente na indústria de software o uso de micro serviços e a ideia de separar uma aplicação em partes menores de software ganhou força. Mas há nessa questão algo muitas vezes de organização de times do que de software, nem sempre dividir uma aplicação em pequenos serviços isolados torna o software melhor.

Muito trabalho de ótima qualidade já foi feito com softwares de grande porte em bases de código unificadas. A questão não é a forma como um grande bloco de software é dividido, mas se essa divisão de um sistema em sub sistemas isolados é robusta e adequada ao domínio.

A abordagem com DDD dá grande ênfase, e traz ferramentas para realizarmos uma melhor reflexão justamente sobre como nossos sistemas podem ser melhor organizados e contextos com LIMITES CLAROS.

O que faz diferença não é como você garante o limite (desde que o cumpra), mas quais limites você define.

Eu adoro a sugestão das 4 camadas

dddlayers
Créditos da imagem: https://www.citerus.se/on-layering-in-dddsample/

Pensar uma aplicação desta maneira tem me ajudado muito. Vamos de trás para frente.

As camadas de Domínio e Infraestrutura tem uma pegadinha. Infraestrutura aqui diz respeito à todo o código que faz algo computacional e que não é necessariamente domínio. Por exemplo, a “Interface” de uma classe de persistência estará no domínio, mas sua implementação estará em infraestrutura. Infraestrutura aqui diz respeito à maior parte do código que atualmente colocamos em nossas pastas “src”.

A camada de domínio será este core bem protegido, de preferência 100% coberto por testes unitários, bem desacoplada, que expressa muito bem os conceitos do software.

A camada de aplicação é onde estão presentes os serviços da aplicação de fato, ou seja, as grandes operações da aplicação que fazem algo a partir de uma entrada e devolvem uma saída.

Perceba, que uma saída em PDF, usará dados da camada de domínio, algum código de geração de PDF na camada de infraestrutura, mas será coordenada pela camada de aplicação. Entra aqui fila de tarefas, ações de “Cron”, etc.

Por fim, a camada de interface de usuário contém o código associado a relação direta com os atores que usam o sistema. Particularmente, gosto de pensar aqui não apenas como apresentação visual, mas como os pontos de contato do software, por exemplo, os endpoints de uma API ou sistema web.

Não necessariamente você precise pensar nestas 4 camadas como pastas dentro da sua aplicação. Há muitas variações possíveis, mas ao menos, como forma de pensamento para ajudar na divisão de responsabilidades, é muito útil.

Para minha carreira, DDD é muito mais que código

Eu entendo software (Sistemas de Informação, não entra aqui jogos, softwares embarcados, etc) como uma forma de resolver um problema de negócio que envolve informação.

Sendo assim, a parte mais relevante do meu software é o problema do negócio, a segunda é a informação, e somente a terceira será a tecnologia.

A abordagem DDD vai priorizar justamente o problema de negócio, delegando para um plano logo após a preocupação com a implementação.

Assim, não se trata apenas de “como implementar DDD”, se trata de que técnicas usar para priorizar na solução de software o problema do negócio, de modo que o negócio seja visto em primeiro plano.

DDD não está pronto

DDD não está pronto, nesta palestra de Eric Evans – que primeiro formulou o conceito – ele se distancia da tentação de uma definição muito restrita e fortalece a ideia que a comunidade discuta e evolua o conceito.

Por fim, existe sempre a questão do front-end, cada vez mais complexo e como ele se relaciona com DDD. Esse texto discute um pouco esse tema, é um ponto de partida. Minha experiência prefere um front end focado em animações, posição e fluxo, não em domínio. O próprio Eric Evans traz no livro que é uma escolha mutuamente exclusiva usar uma interface com o usuário inteligente, mas reconheço que o assunto é complexo e o cenário vem mudando nos últimos anos: https://khalilstemmler.com/articles/typescript-domain-driven-design/ddd-frontend/

Outros Artigos

Comentar? no Twitter.