"The best code is no code at all. Every new line of code you willingly bring into the world is code that has to be debugged, code that has to be read and understood, code that has to be supported. Every time you write new code, you should do so reluctantly, under duress, because you completely exhausted all your other options".
Essa é a conclusão do artigo The Best Code is No Code At All escrito pelo Jeff Atwood, co-fundador do Stack Overflow, no blog Coding Horror e representa algo que eu considero muito importante: evitar ao máximo escrever código desnecessário.
O próprio Dijkstra também tem uma frase muito conhecida nesse sentido: "if we wish to count lines of code, we should not regard them as lines produced but as lines spent".
Um dos principais objetivos do Domain-Driven Design é estimular um entendimento profundo do domínio, que é o motivo pelo qual uma empresa existe mercado, representa a sua proposta de valor, o problema que ela resolve.
A partir desse entendimento é possível decompor o domínio em partes menores, em áreas de conhecimento específicas, que são os subdomínios.
Vamos utilizar como exemplo um domínio que todos conhecem bem, o e-commerce e nele podemos identificar diversos subdomínios como o catálogo de produtos, carrinho e checkout, pagamento, emissão de nota fiscal, controle de estoque, operações de logística, processo de devolução entre muitos outros, dependendo do tipo e porte da operação.
A partir disso é possível avaliar dois aspectos à respeito de cada um deles: a complexidade técnica e a diferenciação que trazem para o negócio.
Abaixo temos um gráfico do livro Learning Domain-Driven Design, do Vlad Khononov, demonstrando os tipos de subdomínio em relação à complexidade e diferenciação.
Os subdomínios podem ser classificado como: Core, Supporting ou Generic.
O tipo Core é o mais importante porque proporciona diferencial competitivo e é onde os maiores esforços devem ser feitos, proporcionando mais retorno sobre o investimento.
Complementando o Core temos o subdomínio do tipo Supporting, que apesar de ter menos complexidade é essencial para o funcionamento do Core.
Por fim, temos o tipo Generic, que geralmente tem alta complexidade mas pouca relevância estratégica devendo ser evitado, principalmente em empresas menores, por tirar o foco daquilo que é essencial para a empresa.
Usando como exemplo o e-commerce, todos eles precisam emitir nota fiscal, mas isso não é algo que traria diferencial estratégico para uma empresa de e-commerce e poderia ser contratado de outro fornecedor ao invés de ser desenvolvido.
Uma pergunta que pode surgir é: e se a minha empresa tiver mais de um Core? Isso é relativamente normal, tem empresas que fazem produtos na área da educação, saúde e contabilidade, nesse caso são verticais de negócio diferentes, cada uma com seu Core. O mais importante é que o resultado dessas verticais possa ser analisado de forma individual, deixando claro qual é o resultado e a margem de cada negócio.
No caso do e-commerce, certamente o Core é o checkout, é a coisa mais importante que existe dentro de uma plataforma de vendas e se ele for ruim, se não tiver a possibilidade de aplicar um cupom de desconto, pagar com meios de pagamento diferentes ou de forma parcelada, calcular o frete, resumindo, se ele não tiver tudo aquilo que é necessário ou tiver e não funcionar bem, todo o restante deixa de fazer entido.
O que adianta uma plataforma de vendas ter a melhor emissão de notas fiscais ou o melhor controle de estoque se ela é ruim no que é essencial, que nesse caso é tudo aquilo que tem relação com a realização da venda.
A não ser que você seja o Mercado Livre, a Amazon ou Magalu, eu recomendaria evitar ao máximo a implementação de qualquer subdomínio do tipo Generic. Isso vai drenar as energias da equipe em algo que apesar de ser importante para a operação poderia ser entregue por diversos fornecedores especializados, por um preço justo e de forma confiável.
É acima de tudo uma questão de não desfocar e não desperdiçar energia e com o tempo que sobra você pode se focar ainda mais no seu Core subdomain e ter ainda mais diferenciação de negócio.
Aplicar Domain-Driven Design não se resume em criar meia dúzia de Aggregates, Entities, Value Objects, Domain Services e Repositories, vai muito além, parte do princípio que existe de fato um entendimento profundo à respeito do domínio.
Uma vez que a modelagem estratégica tenha sido realizada, ou seja, o domínio foi entendido, os subdomínios foram identificados e classificados, é possível definir onde e como serão implementados.
Os bounded contexts, que você pode interpretar simplesmente como um espaço de solução, é o lugar onde o código será escrito.
Enquanto os subdomains existem independente da nossa vontade, já que eles são parte do problema, os bounded contexts representam uma decisão técnica, refletindo o que queremos agrupar e o que queremos separar.
Nesse sentido, quando pensamos em um monolito, significa que a decisão foi de implementar todos os subdomains juntos, na mesma base de código, no mesmo projeto.
Existem sempre vantagens e desvantagens ao criar um bounded context.
Uma das vantagens é que é possível reduzir a o acúmulo de código e a mistura de responsabilidades, que é um fenômeno conhecido como Big Ball of Mud, mas ao separar precisamos lidar com a complexidade técnica necessária fazer a integração entre os bounded contexts.
Abaixo segue uma imagem, do artigo The difference between domains, subdomains and bounded contexts do blog DDD Pratictioners, que demonstra essa relação:
Repare que em A, temos uma relação de um pra um entre um subdomain e um bounded context. Esse pode ser um caminho interessante, mas é bom tomar cuidado para não separar bounded contexts que tem muita dependência e podem tornar a integração muito complexa.
Em B, temos um cenário normal em empresas grandes, com um domínio grande e complexo, onde temos vários bounded contexts para o mesmo subdomain.
Isso acontece porque os subdomains acabam tendo muitas especificidades de negócio, com muitas equipes envolvidas e que justificariam essa separação.
Talvez C seja o cenário mais comum, é o bom e velho monolito onde agrupamos vários subdomains no mesmo bounded context. Pode ser uma boa forma de começar e ganhar a maturidade necessária para depois decidir como é a melhor forma de separá-los.
Nesse sentido, temos uma imagem bem interessante do livro do Implementing Domain-Driven Design do Vaughn Vernon, que trata exatamente sobre essa divisão:
Repare na imagem, são 5 subdomains: Product Catalog, Orders, Invoicing, Inventory, Shipping, distribuidos em 3 bounded contexts: e-Commerce, External Forecasting e Inventory.
Sem dúvida, a modelagem estratégica aumenta muito as chances de sucesso por meio do entendimento do domínio e de como ele se divide em subdomínios, permitindo delegar subdomínios do tipo Generic para outros fornecedores e com isso focar no que realmente tem mais diferencial estratégico para a empresa.
Além disso, os bounded contexts são essenciais para distribuir a complexidade em soluções técnicas diferentes, sendo inclusive um excelente caminho para a definição de uma arquitetura de microservices, fazendo com que as equipes trabalhem de forma mais eficiente e evitando que conceitos de domínio se tornam mais acoplados e complexos.