BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Artigos 10 anos de Domain-Driven Design com Eric Evans

10 anos de Domain-Driven Design com Eric Evans

[Esta é uma tradução de entrevista publicada na emag Architectures you always Wondered About do InfoQ.com, realizada pelo arquiteto e consultor alemão Eberhard Wolff]

Dez anos após o lançamento do livro Domain-Driven Design: Tackling Complexity in Software. Eric Evans fala sobre o que mudaria no seu livro e como o DDD mudou a maneira de construir sistemas.

InfoQ: A entrevista será sobre Domain-Driven Design, faz dez anos que surgiu essa ideia. Alguns dos leitores podem não estar familiarizados com o domain-driven design, sendo assim, Evans pode nos dar uma breve introdução sobre domain-driven design, o que é, e como isso é especial?

Em sua essência, o domain-driven design é uma maneira de usar modelos para criar software, especialmente a parte do software que trata regras de negócio complexas em forma de comportamento.

O que focamos particularmente no domain-driven design é uma linguagem que possa descrever sucintamente qualquer situação no domínio e descrever o que faremos para resolver ou que tipos de cálculos precisamos realizar. Essa linguagem pode ser compartilhada entre pessoas do negócio, especialistas de domínio, assim como os programadores que irão escrever o software, e isso chamamos de linguagem ubíqua, porque é a mesma linguagem utilizada durante todo o processo.

Não fazemos como a maioria dos projetos fazem. Não falamos com um conjunto de pessoas do negócio em seus termos e então temos conversas técnicas separadas sobre como o software funcionará. Tentamos fazer essas conversas em conjunto para criar este modelo conceitual com uma linguagem muito clara. E isso é uma coisa muito difícil de fazer, não pode ser feita de maneira global. Não é possível apresentar um único modelo para uma organização inteira. Tentar realizar isso é muito improdutivo.

Assim, o outro ingrediente é o que chamamos de contexto limitado. Dessa maneira, tenho um limite claro, talvez uma aplicação em particular que estamos trabalhando. Dentro deste limite, dizemos "isso é o que minhas palavras dizem, esse é o relacionamento entre os conceitos. Tudo é claro e tentamos trabalhar duro para torná-los claro". Mas em seguida, fora desse limite, todos tipos de regras diferentes se aplicam em alguma parte do sistema, talvez nenhuma regra se aplique realmente.

O domain-driven design trata um contexto maior, mas essa é na verdade a essência de tudo. É uma maneira particular de lidar com as partes complexas dos sistemas.

InfoQ: Acho que é também por isso que tantas pessoas estão interessadas neste assunto, porque isso é realmente o que vários engenheiros de software fazem. É possível dar um exemplo de um contexto limitado e como os modelos podem ser diferentes nele? Porque acho que essa é uma das partes mais interessantes do DDD, ao menos para mim.

Posso te dar alguns exemplos. Uma coisa comum é que diferentes partes de uma empresa podem lidar com um mesmo domínio de uma maneira bem diferente. E pode até ser um software, provavelmente já é um software que lida com essas diferentes partes.

Pegue como exemplo alguma empresa que faz e-commerce. Existe uma parte do software que estamos recebendo pedidos. Portanto estamos muito focados em que tipo de itens tem no estoque e quanto eles custam e como colocamos estes itens juntos em algum tipo de carrinho de compras? E então, eventualmente o pedido é criado e então tem o pagamento e todas essas preocupações.

Mas, então na área de envio, talvez eles não estejam realmente interessados na maioria dessas questões. O que estão preocupados sobre o item é que tipo de caixa será necessário, quanto pesa, que tipo de entrega precisa pagar, e então enviamos tudo em uma caixa, ou não tem algum item no estoque e enviamos os itens que temos e depois enviamos os faltantes, e como rastrear um pedido que foi parcialmente enviado e que tem parte pendente?

Embora na teoria seja possível criar um modelo simples que representaria todos estes diferentes aspectos, na prática não é isso que as pessoas fazem normalmente, e funciona melhor separar os dois contextos e dizer, bem, basicamente temos um sistema de envios e um sistema pedidos e talvez outras coisas também. Não estou dizendo que seriam apenas os dois. É possível criar conceitos tão gerais e versáteis que seria possível manipular todos esses casos.

Mas geralmente somos melhores com modelos mais especializados: um modelo que lida muito bem com a ideia de um pedido como um conjunto de objetos físicos que cabem em certos tipos de caixas e que podem ou não estar disponíveis no momento; e outra pessoa diz, bem, aqui estão os itens que foram escolhidos e aqui temos itens similares, são apenas questões diferentes.

InfoQ: Achei essa introdução ao DDD muito boa, e em particular os contextos delimitados. Penso que é uma das coisas realmente interessantes aqui, que poderia ser completamente diferente, digo, perspectivas sobre itens que se está trabalhando, entregando ou fazendo pedidos. Então, olhando para trás nesses dez anos de DDD, qual é o impacto do DDD em sua opinião?

Bem, para mim é muito difícil ver isso. Tenho o senso de que causou impacto e as vezes pessoas me dizem que o DDD teve uma grande influência. Acho que as coisas que me fazem sentir melhor são ocasionalmente quando alguém diz que voltou a se divertir desenvolvendo ou os fez realmente desfrutar desenvolvendo software novamente. É muito difícil julgar todo esse impacto. Realmente não sei.

InfoQ: É sempre bom poder voltar a se divertir no trabalho. Para mim o impacto do livro é imenso. Eu diria um movimento, um movimento DDD. Concorda com isso? Chamaria isso de movimento é algo diferente do seu ponto de vista?

Acho que provavelmente essa era minha intenção, tinha a sensação de que queria começar um movimento, talvez um movimento muito difundido, mas seria bom pensar que tem um pouco de qualidade nisso.

Uma das coisas que realmente enfatizo, e esta parte tem uma qualidade cruzada, que quando estamos trabalhando em software, precisamos manter um foco muito nítido no domínio básico do negócio. E não devemos olhar para nossos trabalhos apenas como tecnólogos, mas realmente em nosso trabalho (e isso é um trabalho difícil) como uma pessoa que pode penetrar na complexidade e confusão destes domínios e começar a analisar de uma forma que permita escrever um bom software. E as vezes quando isso é feito realmente bem, o problema torna-se significativamente mais fácil em nível técnico.

InfoQ: Sim. Então, acho que é sobre digamos, modelo de mineração ou extração de conhecimento que é uma parte muito grande do nosso trabalho.

Sim.

InfoQ: Qual foi o impacto do seu livro e o movimento, foi diferente do que era esperado? Muitas surpresas?

Bem, uma surpresa agradável é que ele não é apenas mais um. A maioria dos livros tem um ciclo de vida curto, eles tornam-se populares por três ou quatro anos e então acabam esquecidos. E o DDD permaneceu um tema muito relevante por um longo tempo, 11 anos desde o seu lançamento. Isso realmente me surpreendeu, obviamente de uma forma boa.

InfoQ: Concordo. Para mim foi criado algo atemporal. Que parte do movimento DDD mais lhe rendeu conhecimento? O que lhe deu o maior progresso em seu próprio conhecimento e habilidades?

Acho que isto está intimamente relacionado com o motivo que as pessoas ainda prestam atenção ao DDD, o DDD não esteve estático, mas conceitos fundamentais tem sido bastante estáveis, digamos que posso expressá-los melhor agora. Mas as pessoas que estão realmente fazendo isso, tem havido uma série de grandes mudanças na forma como as pessoas tendem a construir esses sistemas.

Assim, o primeiro grande evento foi quando o event sourcing e o CQRS entraram em cena, e a maneira de realizar a concepção e a construção de um sistema DDD mudou muito. Quando isso aconteceu? Talvez em 2007. De qualquer maneira, após alguns anos, e pode ser que com o tempo isso teria sido o ciclo natural do que é novo, o DDD como um tipo de grande renovação. Aprendi muitas coisas com Greg Young, Udi Dahan e outras pessoas que vieram atrás do CQRS.

A maneira como penso sobre as coisas mudou bastante e acho que a maioria das pessoas pensam significativamente diferente devido ao DDD. Houveram algumas outras coisas, mas certamente essa foi a primeira.

InfoQ: Em alguma circunstância a abordagem DDD poderia falhar? E como lidar com isso ou o DDD é algo que pode ser aplicado em qualquer projeto?

Existem alguns aspectos para isso. Essa é uma questão interessante, pois certamente projetos DDD falham todo o tempo. Isso não é comum. Claro que alguns são tão difíceis de falhar que nem preocupamos com isso. Acho que o DDD é difícil. Assim, o que faria um projeto DDD mais suscetível a falha? Acho que uma das coisas mais comuns é a tendência ao perfeccionismo: sempre que as pessoas são críticas sobre modelagem e design, começam a deslizar em direção ao perfeccionismo. Outras pessoas começam a deslizar em direção a um escopo muito amplo: modelaremos tudo, mesmo se tivermos cinco contextos limitados diferentes. Mas modelaremos cada um com grande elegância e todos ao mesmo tempo.

Alguns projetos falham porque ficam muito ambiciosos. Não andam antes de correr. Alguns deles devido à estratégia da empresa não ser muito clara. Deixe me explicar, o maior valor de DDD vem quando se está muito alinhado com o que é estrategicamente importante dentro da empresa. É quando compensa mais. É necessário um certo grau de complexidade, senão não faz sentido. Mas também, é necessário estar envolvido em algo estrategicamente relevante. Mas junto com isso vai uma certa quantidade de confusão da política das organizações. Algumas organizações mudam suas estratégias.

Já vi todas essas coisas acontecendo antes. Há todos os tipos de outras coisas. Claro que, às vezes, as habilidades da equipe são o problema. Assim é possível ter uma situação na qual o início vai muito bem e a execução não tão bem assim. Claro, uma má programação vai minar qualquer abordagem de software. Ultimamente, o código tem que ser bom, competente. Isto prejudica uma série de projetos.

Desde que mencionei o contexto limitado anteriormente e quero destacar o quão fundamental é e isso não é uma tarefa fácil. Se estabelecemos que entregar contexto e ordem para obter o contexto que está separado e então criamos um limite os separando, temos um tipo de camada de tradução aqui. Mas o programador precisa de alguma parte dos dados para entregar o contexto. Agora, o que fazemos, simplesmente dizemos "Bem, posso escrever uma query para acessar o banco de dados. Isso só levará 15 minutos. Ou posso conversar com a pessoa sobre como estamos melhorando a interface e a tradução entre os dois contextos e então como este pedaço de informação será modelado dentro de nosso contexto, e então continuarei a construir minha funcionalidade".

Manter esse limite demanda um certo nível de disciplina. E quando o limite acaba, os dois modelos começam a se colidir e tudo vai por água abaixo muito rapidamente. Outra variação acontece quando se tem uma série de sistemas legados e se está tentando fazer algum trabalho. O ideal é isolar a nova demanda dentro de contextos limitados e manter a conversa com o sistema legado por meio de algum tipo de tradutor.

De qualquer maneira, é possível seguir em frente, mas não é surpresa que alguns deles falham.

InfoQ: Concordo, como dito, acredito que o DDD só faz sentido se existe uma certa complexidade e com isso, o risco, mas também pelo potencial valor do software. O que achei interessante sobre o que foi dito é que as pessoas têm uma ambição muito grande em certos pontos e tentam alcançar um estado perfeito. Isto é natural para uma série de pessoas técnicas. Gostaria de saber se existe alguma técnica secreta para manter em foco a ambição de partes do sistema que são realmente importantes, e viver sem tanta qualidade em outras partes, e parar com a ambição? Existe alguma dica para isso?

Acredito que sua pergunta resume tudo muito bem. Isso é necessário e devemos fazer para ter os limites entre os dois. Há um pouco no DDD sobre - parte da estratégia de design é decidir quais partes pertencem ao que: como uma categoria geral de subdomínios genéricos que dizemos, bem, não tem nada de especial aqui. Não estamos criando algo aqui que queremos inovar, queremos fazer isso do jeito padrão. De fato, a solução aqui seria nem mesmo escrever qualquer software, vamos ver se podemos encontrar algum de prateleira.

Então há muitas coisas que apenas mantém as luzes acesas, que mesmo se uma ideia brilhante surgir não irá mudar muito de maneira geral. E então há aqueles pontos de alavancagem. Isso é algo geral, porém muito difícil, porque primeiro de tudo, é difícil de saber. Frequentemente será tomado o caminho errado, escolhido um tópico que vai dar em outro e não terá muita relação com o valor estratégico do negócio. Mas ainda acredito que existe muito valor em tentar.

Outra coisa é o perfeccionismo, porque, mesmo se concentrado em uma determinada parte que era estrategicamente valiosa, o perfeccionismo ainda pode te matar. É preciso fazer as entregas rapidamente. Na verdade, o DDD depende da iteração. Assumimos que se não houver o entendimento do problema logo no inicio, e primeira interação será errada. E é essencial fazer a primeira interação rápido e certo, e então ir para a segunda interação e fazê-la rapidamente também, porque senão provavelmente estará errada também. E então ir para a terceira que provavelmente fará as mesmas coisas que as anteriores e esta terceira pode ser feita relativamente bem. E se quiser fazer isso rapidamente, haverá tempo para a quarta interação, que será realmente elegante.

E isto é sério. Acredito que isto é um paradoxo estranho, mas o perfeccionismo impede que as pessoas criem design realmente elegantes, porque deixa as iterações iniciais lentas e depois as iterações não são suficientes. Múltiplas iterações, iterações como repetir as mesmas coisas, não o tipo de iteração como quando as pessoas estão realmente falando sobre melhorias. Digo, fazer o mesmo conjunto de funcionalidades e então refazê-las com um design melhor, com uma nova visão do que significa. Essa é a solução: mudar rapidamente.

InfoQ: Soa muito interessante focar no número de reiterações ao invés de procurar a solução perfeita logo no início. Uma coisa que realmente gostaria de saber é se está planejado alguma atualização no livro, existe alguma coisa que gostaria de mudar no livro?

Estou certo que não atualizarei o livro. Posso escrever algo novo em algum ponto. Mas de nenhuma maneira penso em mudar o livro. Mas se fiz ou melhor, se fosse para tentar explicar melhor DDD, certamente uma coisa que percebi há muito tempo é que o conceito de contexto limitado é apresentado muito tarde no livro. É necessário ficar voltando para visualizar todo material estratégico. Tratei-o em um tópico avançado. Há alguma lógica para isso, mas o problema é que é tão longe que a maioria das pessoas nunca visualizem realmente. Desse modo, gostaria de ter abordado isto logo nos primeiros capítulos. A linguagem ubíqua está no capítulo 2, então tudo bem. Mas deveria ter abordado o contexto limitado no capítulo 2 ou 3.

Outra coisa que poderia fazer é tentar mudar a apresentação dos blocos de construções. Os blocos de construções são como entities, value objects, eventos da camada de domínio e coisas assim. São coisas importantes, mas há uma grande concentração delas perto do meio do livro. A maioria das pessoas não volta a ler esses blocos construções e acabam pensando que isso é realmente o núcleo do DDD, o que na verdade não é. Essa é uma parte importante porque ajuda as pessoas a construir a ponte da modelagem conceitual do DDD para a necessidade de ter um programa. Mas realmente penso que a maneira que organizei o livro dá as pessoas uma ênfase errada. Assim essa é a grande parte a qual rearranjaria as coisas.

InfoQ: Acho que faz sentido. Concordo que o design estratégico é realmente importante e uma das coisas que muitas pessoas não pensam sobre quando ouvem o termo DDD. Recentemente, temos visto uma tendência para arquiteturas microservices e já tivemos algumas discussões sobre microservices. Então, como os microservices se encaixam no mundo DDD? Existe uma erudição?

Estou bastante entusiasmado com os microservices. Acho que pode ajudar um pouco as pessoas que querem fazer DDD. E acredito que certos aspectos do DDD podem ajudar as pessoas a fazerem microservices melhores. Assim, quando digo que isso ajuda as pessoas a fazerem DDD, já falei sobre contextos limitados e o quão importante são. Se pensar sobre como as pessoas fazem os microservices da maneira correta, verá que a implementação interior dos microservices é bastante isolada. Supõe-se que tudo acontece por meio de uma interface. Qualquer tipo de dado que o microservice contém é exclusivamente controlado. Existe realmente um limite forte e é isso que é necessário.

O contexto limitado é um conceito mais conhecido em arquiteturas mais tradicionais, não existem maneiras muito boas de implementar o conceito para realmente estabelecer o limite. Parece que os microservices trouxeram uma maneira prática e popular de definir e aderir esses limites. E essa é a sacada, e a ênfase no micro, bem, alguém me perguntou uma vez "Qual é a diferença entre microservices e os antigos serviços SOA" e respondi, "Bem, acho que parte disso é micro". Estes serviços são pequenos. Claro que isso é somente uma convenção, mas uma importante convenção. A ideia que uma parte muito pequena de um software poderia ser muito isolada e fazer suas próprias coisas. Se pensarmos sobre meu exemplo do pedido versus a entrega, claro que ambos são grandes demais para serem um único microservice. Provavelmente seriam um pequeno conjunto de cada. Mas essa noção de que poderíamos separá-los viria de forma natural com a arquitetura de microservices. Então esse é um caminho, o grande caminho, no qual vejo que ajuda o DDD.

InfoQ: Ao dizer que entregar um pedido seria um conjunto de microservices, significa que um contexto limitado seria um conjunto de microservices? É isso mesmo?

É exatamente isso que estou dizendo. E este, por sinal, é um ponto no qual acho que o DDD pode ser útil para microservices, porque eles têm o mesmo problema que o SOA teve, no sentido de que há uma indefinição sobre quem pode entender a interface de um serviço.

Então dentro de um contexto limitado, digamos o interior de um microservice, existem coisas que são claras, ou ao menos deveriam existir. Então, digamos que declaramos um destes microservices para ser um contexto e cada conceito está bem consistente. No inicio dissemos que um item de um pedido significa isso, e que tem certas propriedades e regras sobre como combinar com outros itens de pedidos, todas essas coisas são muito claras em termos de linguagem e regras.

Agora vamos para a interface do serviço. E então poderíamos ter certas linguagens, a menos que a view de um serviço trate somente a entrada e saída de strings e números. Mas não é dessa maneira que as pessoas veem e constroem serviços bem projetados. Serviços bem projetados tem um tipo de linguagem sobre como fazer e possuem um contrato.

Então se dissermos, que quando enviamos um pedido para o microservice, é isso que significa. E não estou apenas dizendo que são somente os atributos. Estou falando do conceito disto. Agora, se olharmos um pouco melhor, veremos que as pessoas tipicamente possuem alguns conjuntos de microservices que essencialmente falam a mesma língua.

Assim se a equipe está trabalhando no sistema de pedidos, temos um modelo e podemos dizer que temos cinco microservices e eles falam a mesma língua e trabalhamos duro para tornar essa linguagem clara. E então aqui dizemos, bem, estamos realmente trabalhando com conjuntos diferentes de problemas. Estes microservices não falam a mesma língua. Se um pedido for realizado aqui, pode ser um pouco diferente. E mesmo se tentarmos diferenciar com nomes mais longos, nunca fazemos isso da maneira certa.

Sendo assim, o melhor a dizer é que não falam a mesma língua. E isso significa que se uma mensagem é enviada de um microservice dentro de um conjunto para outro, algo que deve ser realmente fácil, mas se a mensagem vai de um desses conjuntos para outro, pode ser que tenhamos que usar outro componente para traduzir. Portanto, esta é um modo que ao olhar para vários microservices, precisamos pensar "fazer conjuntos em diferentes contextos limitados?".

Existe também a questão do interior e exterior. O exterior destes microservices são o que estou falando na verdade, o exterior de um microservice pode falar uma língua diferente da interior. Sabemos que podemos passar um pedido para o microservice ou passar um stream de pedidos para este microservice. Dentro dele vai existir um modelo que vê os pedidos de uma forma estatística, digamos assim, e vem com algumas recomendações ou algo assim.

O interior então usa um modelo um pouco diferente. O interior de um microservice tem um contexto limitado diferente. Mas como disse, todo o conjunto está falando a mesma língua. Dessa forma temos um intercâmbio nesse contexto que decidimos o que as mensagens significam, assim como mudamos os contextos entre os serviços e então temos o contexto interior de cada serviço.

InfoQ: Faz muito sentido. O que gostaria de saber é se um contexto limitado é geralmente um conjunto de microservices? Tem alguma maneira de pensar ou dizer se certas funcionalidades devem ser implementadas em um microservice ou só ser uma parte de outro microservice? Obviamente porque se existe um conjunto que é um contexto limitado, não somente um contexto limitado em um microservice, é um conjunto de microservices. Então gostaria de saber se existe uma regra que daria uma ideia se devemos quebrar essa funcionalidade em microservices adicionais e um contexto limitado parece não o fazer.

Primeiro de tudo, sim, se um conjunto de microservices é um contexto, ou seja, do exterior, a mensagem entre os mesmos poderia ser um microservice, e dentro de cada um temos um contexto limitado, e então dentro de cada um temos outro contexto limitado. Mas agora a dúvida, bem supomos que temos novas funcionalidades que precisam ser colocadas em algum lugar, devo colocá-las como outro microservice neste conjunto?

Acredito que está é basicamente o mesmo tipo de questão que sempre temos que responder quando estamos projetando coisas. Esse pedaço de funcionalidade pode ser parte de uma estrutura já existente? Ou isso está distorcendo a estrutura de uma boa modelagem? E se sim, em que lugar podemos colocá-la? Acredito que os fatores que envolvem isso, e não estou sendo original aqui, é como acoplar isto em outras funcionalidades dentro do conjunto? Assim como existe a necessidade de existir um relacionamento com três componentes diferentes no conjunto, parece muito provável que vamos querer mantê-lo nesse conjunto.

Outro fator seria a expressividade desse conjunto. A expressividade de uma particular linguagem de contexto limitado - Se expressa bem esse conceito? Posso estender essa linguagem para expressar bem esse conceito? Se sim, então isso pode ser bom. Se não, qual o preço a ser pago na proliferação de diferentes contextos limitados? Sabemos que existem os prós e os contras, claro.

Não existe uma resposta aqui. Parece que teremos que fazer um bom trabalho como designers.

InfoQ: E esta é provavelmente a parte difícil.

Uma pequena introdução e o manual de erros também. Essa é outra razão para não ser tão perfeccionista. De qualquer maneira não sairá certo e será economizado tempo para iteração. Volte e faça novamente.

InfoQ: Sim, faça melhor da próxima vez. Ok, já foi mencionado o termo CQRS. Pode explicá-lo?

Me lembro de tentar entender isso alguns anos atrás. Event sourcing e CQRS vieram quase ao mesmo tempo, as pessoas da comunidade que estavam trabalhando neles estavam muito interligados, e as duas coisas não estavam delimitadas claramente, não ao mesmo tempo. Mas penso que existem dois conceitos arquiteturais distintos aqui. Normalmente funcionam bem juntos, mas é usual pensar neles separados. O que imediatamente fez sentido para mim foi o event sourcing. O CQRS foi um pouco menos óbvio para mim. Mas acredito que seja uma boa técnica. Na essência, CQRS diz que é preciso quebrar o sistema em componentes que são somente leitura ou que são atualizações de processos.

Então voltando ao exemplo de pedido. Quando um novo pedido chega, no CQRS colocamos ele na forma de um command. Um command significa o C no CQRS. E o command poderia ser "insira o pedido" ou algo do tipo. Agora, em algum microservice, vamos imaginar qual job deve cuidar desse tipo de command e o que pode ser feito; como dizer "Oh, não é possível realizar esse pedido, já não vendemos esse item".

Logo usando commands, segundo a definição no CQRS, é possível dizer não, ou então dizer ok, vamos processar o pedido e reduzir o inventário e iniciar o processo de entrega e enviar uma mensagem sobre isso. Alguns eventos saem, alguns eventos que estão dizendo algo como "o inventário foi reduzido" e outros eventos que dizem "existe um novo pedido à ser enviados". Esta é a responsabilidade de uma parte do processamento do command.

Agora a query, que é o "Q". As vezes dizemos, bem, um usuário pode querer olhar para o catálogo, decidir o que quer e pedir. O usuário pode querer ver o status do pedido, "Meu pedido já foi enviado?", coisas do tipo. Essa é a parte Q. Gostaria de ver o status do pedido. E a ideia é que essa parte do sistema poderia ser mantida muito simples. Seria uma parte do sistema que deveria saber como enviar um pedido. Mas uma vez enviado, o status deve ser atualizado por meio de uma query que diria que um pedido foi enviado.

As queries podem escalar de maneira diferente do processamento do command. E em um sistema que temos muito a fazer, se este sistema for um e-commerce com milhares de pedidos por minuto para serem manipulados, mas talvez estejamos manipulando mais queries, mas pode ser escalado independentemente. Podemos reconhecer que talvez as queries consumam menos processamento, desde que não existam mudanças acontecendo, não precisamos nos preocupar com as regras de consistência.

Dessa maneira é muito fácil escalar a parte da query. A parte do command é a qual temos que lidar com todas estas questões, bem, o que acontece se um command cancelar um pedido que já foi enviado, quais são as regras para isso? O command ainda deve ser processado? Vai ser processado estando cancelado? E por aí vai. Todas essas regras devem ser atendidas, para descobrir como responder a um command.

InfoQ: Então provavelmente devemos explicar que CQRS é Command Query Responsability Segregation certo?

Sim

InfoQ: Já foi dito que existe uma relação com event sourcing. Isso parece a parte C, os commands. É essa a relação?

Bom, penso que podemos ter um sistema baseado em event sourcing que não é um CQRS. Por exemplo, é possível ter um módulo que responde à queries e também pode processar commands, neste caso não está sendo praticado o CQRS porque não é possível separá-los. Mas outra coisa em event sourcing, digamos que temos um objeto pedido. A maneira tradicional de fazer isso é que o objeto pedido pode ter um pedido enviado. No event sourcing dizemos, bem, não tenha nenhum atributo ou algo do tipo. O que temos é uma série de eventos e quando o pedido é enviado é criado um evento "enviado".

O que queremos saber é o status de um pedido, simplesmente procuramos os eventos relevantes. O exemplo clássico pode ser -- bem, vou usar o exemplo que ouvi pela primeira vez de Greg Young explicando esse ponto.

Então, digamos que é preciso fazer algum tipo de aplicativo de negociação de ações. Alguém diz "vendi 10.000 ações da IBM acima de um determinado preço." Então a ordem é realizada. São 10.000. E agora temos uma questão, "quantas ações restam à serem vendidas?" Desta vez executamos essa ordem, digamos que vendemos 1.000, e em uma transação separada mais 2.000. Aqui temos dois eventos, na verdade três. Um que vende 10.000, e outros dois que dizem, vendemos 1.000, vendemos 2.000. Agora a questão é, quantos restam para serem vendidos? Quantas ações da IBM devemos vender nesse preço? No momento da query, podemos buscar os eventos visíveis e calculá-los.

Antigamente, tínhamos esse objeto e poderíamos ter 10.000 e então a primeira venda subtrairia 1.000. Então teríamos 9.000 e então vendemos outros 2.000 e então teríamos 7.000. Em sistemas baseados em event sourcing não temos esse atributo. Ou se tivermos, esse é um atributo imutável que expressa o pedido original de venda de 10.000 e então temos um objeto completamente separado, um event object, que diz, vendemos 1.000 e outro que diz, vendemos 2.000. Se quisermos saber, podemos descobrir isso. Se olharmos para estes eventos, veremos, 10.000 menos 1.000 menos 2.000.

InfoQ: E qual é o conceito básico de event sourcing. O que gostaria de saber é qual é o relacionamento entre o DDD, CQRS e event sourcing?

Penso que o event sourcing é mais fácil de ilustrar devido a técnica de modelagem. Estamos falando sobre como representaríamos o domínio. Se olharmos antes disso com ênfase nas entidades e valores, isso é dar ênfase em um lugar um pouco diferente. Certas coisas acontecem no domínio. No domínio temos a execução dos pedidos e isso deve ser explicitamente modelado.

Isso é realmente tornar o modelo mais explícito sobre as mudanças. Se pegarmos os sistemas no estilo OO antigo, no qual as coisas mudam e os objetos representam a maneira que as coisas estão na nossa visão, o que também é tipicamente uma abordagem de um banco de dados relacional, porém não mostrando o que aconteceu. Somente mostram como as coisas estão no momento. Ao passo que o event sourcing se destaca e diz "vamos modelar a mudança de estado ao invés do estado". E podemos derivar o estado da mudança de estado.

Então, digamos agora que executamos uma ordem, é isso que gravamos. Executamos uma ordem novamente e gravamos. Se quisermos ter esse outro ponto de vista, é apenas uma agregação destas ordens. Isso é realmente uma técnica de modelagem que emergiu da tentativa de aplicar o DDD em certos tipos de problemas que eram centrados a eventos e também tinham que manipular um alto volume. Com isso, é possível escalar as atualizações porque se as atualizações são muito frequentes e a leitura menos frequente, por exemplo, é possível inserir eventos no sistema sem ter que atualizar um objeto toda vez.

Todos os objetos se tornam imutáveis, o que tem certos benefícios técnicos, especialmente se estivermos tentando escalar ou paralelizar coisas. Então penso que o DDD pode ser aplicado naturalmente, é realmente uma reformulação dos blocos de construção, é uma maneira de olhar, mas é um pouco mais radical do que isso.

InfoQ: Uma coisa que gostaria de saber é se ao olhar o DDD e particularmente na parte da model, isso realmente parece com uma abordagem orientada a objetos, acho que porque são entidades como valores e todos estes tipos de coisas. É bastante fácil pensar sobre como isso seria implementado usando técnicas orientadas a objetos. Nos últimos anos tem havido uma mudança para a programação funcional. Acho que o DDD pode ser aplicado na programação funcional também, apesar de ter sido originalmente expresso em termos orientado a objetos?

Sim, essa é uma das grandes coisas que aconteceram nos últimos 11 anos. A razão de tudo ser expressado em forma de objetos é devido aos objetos terem sido os reis em 2003, 2004, e o que mais poderia ter descrito como? Pessoas que querem resolver domínios complexos queriam tentar desenvolver um modelo de domínio para ajudá-los a lidar com essa complexidade, então usaram objetos. E os blocos de construção foram uma tentativa de descrever certas coisas que ajudam esses tipos de modelos a realmente terem sucesso.

Agora, se olharmos isso do ponto de vista funcional, então o modelo será um pouco diferente, ou melhor, a implementação será um pouco diferente. Acho que o event sourcing na verdade pode ser bom, porque se aplicado completamente, os objetos são imutáveis, que é um começo para a perspectiva funcional, porque em vez de ter objetos que mudam, temos algum tipo de estrutura de dados que usamos na função para obter uma outra estrutura de dados.

Imagine um sistema baseado em event sourcing com alguns microservices. Temos um microservice, passamos alguns eventos para ele e processamos o resultado e passamos para ou fluxo de eventos que diz "como consequência disso, isso é o que acontece." Então, passamos "executamos uma ordem para 2.000 e executamos uma ordem para 1.000" e recebemos um evento que diz "a ordem foi reduzida para 7.000", tanto faz.

Na verdade, é muito fácil imaginar a implementação disso como uma função. Talvez mais naturalmente que no OO de fato. Obtemos um fluxo de eventos e queremos usar isso para processar outro fluxo de eventos, que realmente clama por uma função para mim.

InfoQ: Sim, absolutamente. Isso soa até mesmo como um Actor model.

Sim. Bem, algumas pessoas na comunidade DDD usam realmente o Actor model. Vaughn Vernon, por exemplo, tem falado bastante sobre o uso do Actor model. Isso parece ser uma boa alternativa. Parece que corresponde praticamente a um dos outros blocos de construção que não falamos ainda. No livro original, fala sobre a construção de blocos chamados aggregate, que era uma espécie de tentar descrever um conjunto de objetos que têm regras acerca da sua consistência interna de dados e de alguma forma seriam autorizados a impor essas regras.

Então as pessoas dizem, bem, se pegarmos a unidade de qualquer coisa que estamos tentando tornar consistente, a qualquer mudança e de dar essa responsabilidade para um único ator, agora imagine um ator recebendo events ou commands, e tendo que saber se precisa manter o estado consistente, mudando de um estado para outro de uma forma que respeita a invariância desse aggregate. E então essa aplicação baseada no Actor model usando um pouco dos antigos aggregates além de events e commands. Muita coisa acontece quando começamos a falar sobre isso. A maneira que as pessoas constroem isso é muito diferente.

InfoQ: Provavelmente devemos dizer algumas palavras sobre Actor. Bem, um Actor é algo que recebe events de fora e os executa sequencialmente. É um modelo para computação paralela no qual existem muitos Actors trocando eventos e cada um deles funciona sequencialmente. Mas o sistema como um todo é paralelo porque todos estes Actors trabalham paralelamente em seus próprios fluxos de eventos. Basicamente está é a ideia e parece se encaixar bem aos aggregates do DDD.

Certo. Essa descrição é um ótimo resumo das propriedades técnicas. E se tentarmos descrever porque isso é tão útil quando temos todos estes modelos de domínio conceituais e tentamos construir um software que respeite estes conceitos e os expresse.

Logo, existe uma grande variedade de estados dentro de um sistema grande e um aggregate diz, bem, uma das coisas que nos mantém em direção ao paralelismo, como feito com Actor, é que não temos limite no qual podemos dizer que o resultado deste processamento não afeta imediatamente outras partes, e que podemos lidar com isso de forma assíncrona. E isso é exatamente o que aggregates fazem. Definem um subconjunto de estados que tem regras sobre como mudar o estado. E dizemos que quaisquer tipos de mudanças resultantes em outros lugares serão tratadas de forma assíncrona.

É isso que um aggregate faz. E está relacionado ao domínio porque temos que olhar para o negócio para saber o que realmente pode ser mudado independentemente, haverá consequências em ter coisas fora de sincronia?

InfoQ: Sim, isso parece ser bom em certos tipos de tecnologia ou abordagem técnica para determinados domínios.

Sim, porque quando estávamos usando inicialmente o aggregate, bem antes do livro, de volta à década de 90 ou menos, era difícil implementar aggregates, não existia um artefato técnico que poderia ser simplesmente usado. Assim, a parte legal do Actor é que nos fornece algo para dizer "decidimos que vamos fazer cada aggregate responsabilidade do Actor". Agora posso realmente dizer para outro programador, ok, este é o aggregate porque fiz um Actor para ele.

Isso realmente ajuda quando é necessário explicitar algo. Isso é porquê, de qualquer maneira, penso que os objetos continuam sendo um conceito de valor. Nos diz que um artefato de software torna explícito algo em nosso modelo conceitual, algo importante no domínio que definimos. Existe um certo estado, regras e comportamentos em torno disso.

Pessoalmente, dei um tempo para o OO alguns anos atrás para refrescar a mente, mas não queremos jogar fora o bebê com a banheira. Tornar as coisas explicitas é bom.

InfoQ: Outra tecnologia que tem crescido nos últimos anos é o NoSQL. Existe alguma relação entre NoSQL e DDD também?

NoSQL, claro, não é como o event sourcing e o CQRS, pessoas que vem com esses conceitos usavam o DDD e estão tentando trazer a melhor maneira de fazer DDD. Não é totalmente verdade com NoSQL, o NoSQL surgiu de um mundo completamente diferente. Estavam muito interessados nas propriedades técnicas do que estavam fazendo e assim por diante, e acima de tudo acredito que a motivação de muitas coisas era a velocidade. Entretanto, acho que é um grande benefício para DDD.

Mas um dos maiores obstáculos que tivemos por um longo tempo é a obsessão com tudo sendo armazenado em um banco de dados relacional. Os dados em um banco de dados relacional têm que ter uma certa estrutura. Nos dias em que os objetos eram dominantes, o banco de dados relacional ainda contínua dominante. Então usamos mapeadores OR (objeto-relacional). Claro que as pessoas ainda usam isso, como se fosse no passado. E então as pessoas iriam falar sobre a resistência a falhas. Bem o que é resistência a falhas? Simplesmente digo que a estrutura do conceito fundamental de um objeto é diferente de uma tabela relacional ou um conjunto de tabelas. A maneira como se relacionam é diferente.

O problema aqui que acredito ter ouvido o Eric Meyer ressaltar é que quando dizemos NoSQL, devemos fazer o "No" ser apenas um acrônico. Logo devemos dizer NotOnlySQL. E o ponto era que o problema não é o banco de dados relacional que é uma coisa brilhante, uma ferramenta poderosa. Mas quando o usamos para tudo, encontramos dados que não se encaixam bem, e então é necessário torcê-los para se encaixarem. Mas quando se está lidando com um problema que se encaixa, é perfeito, é uma ferramenta fantástica. É difícil achar uma ferramenta que funciona bem para tudo. Acredito que outro problema é que os objetos também eram usados para tudo, e é claro que não são bons para tudo.

Isso se relaciona com o DDD porque estamos tentando tratar estes diferentes conceitos do domínio, e também tentando criar conceitos que são tangíveis no software. Essa forma, que algumas vezes é uma forma natural mais parecida com objetos do que relacional. Se for mais parecida com objetos, talvez se queira representar como objetos, mas então é necessário ajustar em uma tabela relacional com os relacionamentos.

Ao invés disso, talvez se use um armazenamento chave-valor, que é uma forma natural para objetos atualmente. Estrutura de objetos realmente são apenas referências, para referências de referências. É o mesmo tipo de estrutura de árvore que embora boa, tem mais de uma estrutura de árvore. Isso se encaixa melhor para alguns tipos de problemas.

E então o que é agradável sobre NoSQL é que é um mundo relativamente diferente. Existem os bancos de dados orientado a grafos, existem coisas que são modeladas realmente bem como grafos. Se dissermos, "Como modelamos isso" as vezes as pessoas pensam que modelar significa a modelagem OO, desenhar um diagrama UML e então implementá-lo em C# ou Java. Não é isso que modelar significa. Modelar significa criar abstrações que representam aspectos importantes do problema e então colocá-los para funcionar.

As vezes a abstração natural é um grafo. Se dissermos, bem, como essas pessoas se relacionam? Os bancos de dados orientado a grafos como o Neo4j permite escolher uma ferramenta que na realidade resolve o tipo de problema que estamos tentando resolver. Não é necessário ajustar em objetos. Ao invés disso, usamos um banco de dados orientado a grafos e fazemos perguntas ao grafo usando uma linguagem de busca orientada a grafos. Esse é o mundo do NoSQL no qual podemos escolher uma ferramenta que melhor se encaixa para o problema que estamos tentando resolver.

InfoQ: Acredito que este ponto é realmente importante. Obviamente, o que estamos falando é como estes bancos de dados NoSQL dão vantagens na modelagem de dados, enquanto várias pessoas continuam pensando que o NoSQL é somente para escalar e para questões relacionadas a Big Data. Esse é um dos benefícios, mas provavelmente nem mesmo o mais importante. É mais relacionado a flexibilidade, modelagem de forma mais natural e alternativas diferentes para os bancos de dados relacionais.

Sim, acredito que a principal razão das pessoas pensarem primeiramente sobre a técnica de escalar é porque está é a origem, é a motivação principal por traz disso. Provavelmente resolveu a necessidade absoluta das pessoas com o Big Data, o equilíbrio que estávamos tão profundamente enraizados no banco de dados relacional, que levaria a perder algo. Mas não acredito que as grandes oportunidades para o NoSQL estejam nos problemas complexos do mundo, em que as coisas que queremos fazer não se encaixam no modelo relacional. As vezes não se encaixam no modelo OO. Podemos escolher coisas que se encaixam melhor.

InfoQ: Está é realmente uma boa forma de resumir. Muito obrigado pelo seu tempo. Muito obrigado por todas as respostas interessantes e os insights interessantes. Gostei muito.

Obrigado.

O entrevistado

Eric Evans é o autor do "Domain-Driven Design: Tackling Complexity in Software". Eric agora lidera o Domain Language, uma empresa de consultoria que realiza treinamentos para equipes aplicando o DDD, ajudando-os a tornar o desenvolvimento mais produtivo e mais valioso para o negócio.

O entrevistador

Eberhard Wolff trabalha como consultor, arquiteto e professor freelance na Alemanha. Atualmente interessado em Continuous Delivery e tecnologias como NoSQL e Java. É autor de diversos livros e artigos e palestra regularmente em conferências nacionais e internacionais.

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT