O artigo Estrutura em Larga Escala com DDD é uma análise detalhada das propostas apresentadas por Eric Evans em seu livro sobre clássico sobre Domain-Driven Design. Assim, no âmbito dos projetos realmente grandes, Evans argumenta que a abordagem convencional de design de software pode não ser adequada para enfrentar os desafios complexos que surgem na prática. Portanto, ele oferece uma série de estruturas e padrões para auxiliar os arquitetos de software na criação de sistemas que sejam altamente flexíveis, escaláveis e capazes de se adaptar rapidamente a mudanças nos requisitos e no ambiente de negócios.
Além do Estrutura em Larga Escala com DDD, aqui no blog temos uma grande quantidade de artigos, mas em específico, temos dezenas de artigos voltados para o Domain Driven Design. Nenhum deles é requisito para a leitura desse, mas fique a vontade para le-los caso julgue interessante.
- System Design Flexível
- Domain Driven Design: Contornos Conceituais
- Domain Driven Design: Afirmações
- Operações isentas de efeitos colaterais
- Interfaces reveladoras de intenções
- Classes autônomas
- Fechamento de Operações
Uma Estrutura em Larga Escala com DDD
Para começar, quando lidamos com projetos realmente grandes e maneira de pensar os domínios do sistema precisam ser calibrados para essa escala. Comentei em outros artigos que não vejo que o DDD se aplica a projetos pequenos. Já projetos médios ou grandes podem considera-lo como uma opção relevante. Eric Evans em seu livro nos brindou com um capítulo focado em estruturas em larga escala.
O diagrama que segue é uma invenção que fiz com base no meu entendimento com alguns insights que tive. Ao longo do artigo vamos explorar as estruturas, modelos ou patterns que desenham um software de larga escala, segundo o autor.
Assim, note que há 5 grandes estruturas: metáfora, camadas de responsabilidade, ordem de evolução, nível de conhecimento e estrutura de componentes plugáveis: Todos eles são possibilidades relevantes que vão do flexível até o rígido. O rígido deve ser um objetivo, mas se for feito prematuramente, a evolução do software poderá degrindolar. Além disso, note que a metáfora e as camadas de responsabilidade refletem diretamente a linguagem onipresente, já as demais: não necessariamente.
1 – Metáfora
Esse conceito veio diretamente da metodologia XP. Ela considera que o software pode ser complexo, mas a comunicação com o usuário não. Por vezes, elementos complexos são compreendidos pela natureza do negócio, mas em outras situações pode ficar complicado. Usar termos metafóricos podem facilitar esse processo.
Vamos a alguns exemplo óbvios: um firewall (porta corta-fogo) evita que ameaças cheguem até a organização; Camadas separam estruturas; Núcleo é a parte central de algo; e assim por diante. Um software é um emaranhado de lógicas de uns 100 ~ 200 instruções essenciais escritas em assembly que são rearranjadas muitas vezes para produzir grandes sistemas. Essas metáforas amortecem essa complexidade.
Riscos do uso da metáfora
Entretanto há um risco: metáforas podem induzir a erros. Isto não chega a ser gritante, mas é comum usarmos em português o conceito de portas lógicas ou porta USB. Mas veja que o termo original do inglês é port e não door. Port é porto, ou o lugar onde se atraca e não algo que se abre e fecha.
Ao construir um software é possível fazer metáforas, seja com os próprios story cards, seja com estruturas como ponte, subterrâneo, conexão, etc. Eric traz também o conceito de metáfora ingênua, que é quando ela é sintética demais e faz com que o usuário dê inputs incorretos pala compreensão errada.
Agora, vale destacar que nem todo projeto precisa ser baseado em metáforas, mas elas podem auxiliar no seu uso em larga escala.
2 – Camadas de Responsabilidade
Seguindo a metáfora temos o conceito de camadas de responsabilidade, que — por acaso —, é outra metáfora. Esse modelo é um dos mais comuns na forma de organizar coisas. Estou falando em organizar estruturas, contextos, domínios, etc. Essas coisas podem ser estruturadas seguindo um conjunto de responsabilidades particulares.
Quem está familiarizado com BPMN conhece a divisão de pools e lanes, que organizam responsabilidades. Esse modelo, claro, pode ser utilizado na maneira em que se dão os domínios.
Para o Eric, as camadas devem ter suas responsabilidades muito claras e suas camadas inferiores não podem depender de camadas superiores. Nesse caso as superiores exercem força sobre as inferiores e as inferiores são independentes das superiores. Veja que esse modelo conta uma história que ajuda a tornar mais fácil a compreensão do domínio, negócio, código, etc.
Práticas ao estruturar as camadas de responsabilidade
Temos, então camadas que sempre estão imersas em 3 grandes conceitos:
- Storytelling: as camadas naturalmente contam uma histórica;
- Dependência conceitual: é mais fácil entender o fato de C estar dependente de B e de A, necessariamente, facilitando decisões;
- Contornos Conceituais: camadas em herança estabelecem conceitos com clareza.
Além disso, o autor comenta no livro que há 4 grupos de referência sobre as camadas. Ele não restringe mas vê nesses grupos uma forma que facilita o consumo:
- Decisão
- Mecanismo analítico
- Pouco estado e pouco mudança
- Análise de gerenciamento, otimização, redução de tempo
- Todos dependem desse nível.
- Política
- Estratégias e grandes restrições (objetivos e restrições de negócios)
- ADRs
- Mudança de estado lenta
- Prioridade de produtos, geração de receita
- Depende da camada de decisão
- Operação
- Estado que reflete a realidade direta dos negócios
- Mudança de estado rápida
- Lida com inventário e fatos
- Depende da camada de política
- Potencial
- Estado que reflete a realidade dos negócios
- Ritmo moderado de mudança de estado
- Visão das expectativas de futuro
- Capacidades de recursos, processos e afins
- Depende da camada de operação
3 – Ordem de evolução
Quando temos um grande sistema para desenvolver muitas vezes lidamos com contextos diferentes, domínios diferentes e relações com posições de poder diferentes. Alguns desses representam setores de negócio ou times de TI distintos. Portanto estou falando de algo realmente grande. Nesse caso temos a seguinte questão: por onde começar?
Do ponto de vista do Eric, não faz muita diferença. É verdade que há caminhos melhores do que outros mas isso não será observável no início. A questão é que é fundamental que se faça destilações e refatorações constantes, de modo que os próximos caminhos sejam melhores, numa melhoria contínua.
Então temos um outro conceito: Ordem de evolução. Esse conceito indica que a próxima coisa a ser desenvolvida pode ainda não estar definida. A medida que o software avança a estrutura do software pode melhorar de modo a saber suportar o que está por vir. Temos, então, dois lados distintos: (1) um onde a flexibilidade do software é a maior possível, mas que pode ser difícil de entender; (2) e outra onde o sistema é muito bem definido, rígido e difícil de manter.
Um software deve começar com o foco na flexibilidade e a medida que evolui destilações devem ocorrer até que ele fique rígido naquilo que deve ser rígido. Começar pelo rígido é fatal atrapalhando completamente o software, mas por outro lado, continuar eternamente no flexível pode complexificar o trabalho com novas estruturas. Assim ele comenta que liberdade exagerada pode gerar um sistema que pode não fazer sentido para ninguém. Como já disse em outras portunidades, fuja da otimização prematura.
4 – Nível de Conhecimento
Esse padrão levantado no livro é um dos mais complexos. Bom, devemos ter em mente é que o termo ‘Nível de Conhecimento’ é uma tradução literal é pouco explicativa para o português.
Vamos lá, primeiro o Eric pegou esse termo de um livro de Analysis Patterns do Martin Fowler, que ainda não tive oportunidade de ler. Ele também se inspirou no livro (POSA) Patterns Oriented Software Architecture do Buschmann, que trata do mesmo com outros nomes.
Segundo, o termo ‘Nível de conhecimento’ é, de certo modo, análogo ao termo reflection. Veja que na reflexão há o código escrito e o código interpretado on-the-fly. Ele chama o código escrito de base ou nível de operação. E o interpretado em meta ou nível de conhecimento. Apenas para melhor compreensão veja um código escrito em C# que usa Reflection.
using System;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Carrega um assembly e obtém o tipo HttpRequester
Type httpRequesterType = Assembly.LoadFrom("C:\\Temp\\MeuPlugin.dll")
.GetType("Namespace.HttpRequester");
// Cria uma instância de HttpRequester e obtém o método MakeRequest
var requester = Activator.CreateInstance(httpRequesterType);
MethodInfo makeRequestMethod = httpRequesterType.GetMethod("MakeRequest");
// Invoca o método MakeRequest com os parâmetros apropriados
object httpMethodGet = Enum.Parse(typeof(HttpMethod), "Get");
object[] parameters = new object[] { httpMethodGet, "https://www.anselme.com" };
Task<string> resultTask = (Task<string>)makeRequestMethod.Invoke(requester, parameters);
string result = await resultTask;
// Exibe o resultado
Console.WriteLine(result);
}
}
Nível de Conhecimento e Conceitos ocultos
Mas no livro o autor demonstra que não se trata necessariamente de uma questão em nível de código. Então poderiamos pensar em estruturas de alvo nível em que algo abstrato cria estruturas concretas ou coisa do tipo. Então, veja que há uma relação do código reflexivo com o código de execução e vice-versa. Assim, quem já trabalhou com isso sabe que mesmo se a linguagem for compilada e fortemente tipada, erros just-in-time ganham protagonismo com esse padrão.
Por isso, para o autor, em algumas situações, conceitos ocultos só aparecem se o Nível de Conhecimento for utilizado: há uma estrutura abstrata fundamental que dinamicamente cria a concreta, de uso pratico. Mas, não confunda com camadas. Há uma comunicação em 2 vias entre o nível de conhecimento (meta) e o nível de operação (base).
5 – Estrutura de componentes plugáveis
Essa é a quinta estrutura, a mais rígida e que, de certo modo, a mais complexa. Ela deve ser utilizada quando as estruturas estão muito destiladas e o negócio está extremamente bem estabelecido em código. Assim, como costumo dizer, fuja da otimização prematura; e como o Eric diz, procure o minimalismo e busque a refatoração até o bom design.
Entretanto, para não ter confusão com o que chamo de rígido, veja que essa estrutura suportará vários componentes, dando grande flexibilidade do ponto de vista do negócio. Entretanto, todo o modelo dependerá dessa estrutura. Alterações nela impactam todos os componentes plugados e, portanto, a macro-estrutura é rígida. Portanto, é disso que estou falando.
Conclusão de Estrutura em Larga Escala com DDD
Na conclusão do artigo Estrutura em Larga Escala com DDD, vale destacar a importância de uma abordagem cuidadosa ao projetar sistemas de software complexos. Então, as estruturas propostas por Eric Evans oferecem um guia para arquitetos e desenvolvedores, permitindo a criação de sistemas flexíveis e adaptáveis.
Assim, é bom compreender que não há uma abordagem única ou definitiva para projetar sistemas em larga escala. Desse modo, a flexibilidade e a capacidade de adaptação ao longo do tempo são essenciais: As estruturas apresentadas, como metáforas, camadas de responsabilidade, ordem de evolução, nível de conhecimento e estrutura de componentes plugáveis, fornecem um ponto de partida sólido.
Ele atua/atuou como Dev Full Stack C# .NET / Angular / Kubernetes e afins. Ele possui certificações Microsoft MCTS (6x), MCPD em Web, ITIL v3 e CKAD (Kubernetes) . Thiago é apaixonado por tecnologia, entusiasta de TI desde a infância bem como amante de aprendizado contínuo.