Estrangulando a complexidade do domínio

Augusto Mesquita
LazyDev
Published in
10 min readJul 7, 2021
Foto por JESHOOTS.COM no Unsplash

Recentemente resolvi reler uma grande obra do saudoso Eric Evans, livro este tido por muitos — incluindo Martin Fowler — como conteúdo essencial da área de desenvolvimento de software, o famoso “DDD — Domain-Driven Design”.

Confesso que fiquei surpreso com as coisas que consegui enxergar nesta releitura. Talvez isso tenha acontecido por ter prestado mais atenção ou simplesmente por ter mais experiência na área quando comparado com a primeira leitura feita há cinco anos.

Uma das partes que foi um divisor de águas para meu novo entendimento sobre o livro estava logo ali, nas primeiras páginas, onde é apresentado um conceito que permeia por praticamente todos os outros assuntos apresentados posteriormente: a linguagem onipresente ou ubiquitous language.

Na primeira leitura, confesso que não havia dado tanta importância para essa parte, pois me parecia perca de tempo… “Linguagem onipresente? Desenvolvedor e especialista do negócio devem usar a mesma linguagem? Certo, já entendi… próximo capítulo!”.

E lá se foi a oportunidade de aprender um dos conceitos mais importante, se não o mais importante, de todo o livro.

Mas desta vez me redimi deste pecado, e como de costume, venho aqui no blog para expressar minhas ideias e entendimentos sempre que possível como forma de assimilar e armazenar os conceitos e conhecimentos adquiridos de forma mais clara e objetiva.

O objetivo deste artigo é apresentar de maneira introdutória, portanto, com eventuais simplificações de alguns pontos que achei interessante no decorrer da leitura, o que evidentemente não substitui a leitura do livro. É uma obra bastante densa, porém com muitas informações preciosas sobre software, concentrado em uma parte que poucas pessoas dão o devido valor: o domínio.

Espero que após a leitura do presente artigo, o subtítulo do livro (“Atacando as complexidades no coração do software”) faça mais sentido para você, assim como fez para mim. Então, vamos lá!

Domínio

Foto por Renee Fisher no Unsplash

Foi-se o tempo onde o domínio não era tão importante para o desenvolvimento de um software. Se pararmos para analisar o mundo da programação no início dos anos 2000, vamos perceber que grande parte das vezes a construção de um aplicativo se dava de forma parecida com o seguinte exemplo:

Um desenvolvedor conversava apenas com o cliente (dono de uma concessionária) para entender quais relatórios este precisaria que estivesse presente no sistema que seria criado, e quais campos ele julgava como obrigatório no momento de preencher algum formulário.

O cliente, inocente sobre os impactos de tal informação, dizia que seria bom ter campos como RG, CPF, nome do pai, nome da mãe, endereço, telefone e por aí vai.

Após isso, com base no conhecimento obtido, o programador já tinha tudo que precisava e começava a modelar o banco de dados e a criar as telas de cadastro para inserir dados nesta tabela e posteriormente gerar relatórios desses dados cadastrados.

O resultado disso era um sistema em que o funcionário que trabalhava na concessionária tinha vergonha de utilizar, pois para um simples cadastro de perfil de usuário era necessário praticamente fazer um interrogatório com o cliente. Para evitar tal constrangimento, ele simplesmente pedia algumas informações básicas que eram realmente necessária para este tipo de alteração e as marcava no papel. Posteriormente ele fazia a transferência desses dados para o sistema, preenchendo o restante dos dados tidos como obrigatórios com algumas informações aleatórias apenas para passar pelo processo de validação.

Cenários como esse eram bem comuns naquela época, mas a comunidade de desenvolvimento já estava percebendo que havia algo de errado nesse processo de construção de sistema.

Começaram alguns estudos sobre qual seria o problema, e uma atenção maior sobre o real entendimento do negócio e suas operações começou a ser dada, porém ainda de forma discreta.

Mas foi com o advento dos smartphones que esse movimento ganhou muito mais força e destaque. Agora já não era mais aceitável termos formulários gigantes de cadastro, pois como eles seriam apresentados de maneira elegante em um celular? E todo mundo começou a perceber que na verdade ninguém paga pelo menu cadastro. O valor real de um software está na sua capacidade de resolver um problema do domínio, de forma com que suas operações reflitam o que realmente acontece no negócio.

É preciso dar ênfase nessa última frase. Perceba que estamos falando do que realmente acontece. Isso significa que não é o que deveria acontecer, nem como gostaríamos que acontecesse (como no exemplo com o dono da concessionária), mas sim o que de fato acontece.

Isso afetou até mesmo a forma de se enxergar software, principalmente em orientação a objetos, onde passamos a ter termos como “modelo anêmico” para representar classe/objeto que funcionam apenas como CRUD, ou seja, não possuem comportamentos de negócio que justifiquem sua existência.

Essa mudança de paradigma ofereceu um grande avanço para a área de desenvolvimento de software, pois deste momento em diante o nosso foco passa a estar no domínio, ou seja, no “coração do software”.

Complexidade

Foto por Ross Sneddon no Unsplash

Em qualquer projeto de software, há 3 tipos de complexidade, sendo elas: técnica, legado e domínio.

Sobre a complexidade técnica, estamos falando sobre os frameworks que serão usados no projeto, a linguagem de programação, sistemas de mensageria e coisas do tipo.

Quando falamos sobre a complexidade do legado, estamos fazendo referência a sistemas ou partes de sistemas, que recebemos de outras pessoas ou de nós mesmos.

Já a complexidade de domínio basicamente diz respeito a complexidade do problema que queremos resolver, o business.

As duas primeiras complexidades citadas são tidas como acidentais, já que de alguma forma, nós escolhemos ter elas ou não. No âmbito da técnica você pode optar por utilizar a tecnologia “X” ou o padrão de projeto “Y”. A respeito do legado, nós temos a escolha de manter sua continuidade ou optarmos por seu fim.

Porém, a única complexidade da qual não temos poder de escolha é a do domínio. E se pensarmos um pouco, esta é a única, das três complexidades, pela qual um negócio está disposto a pagar no fim das contas. Não faz sentido um software existir sem uma complexidade de domínio, e por este motivo ela é tida como essencial.

Quanto mais complexo o domínio, mais difícil a construção do sistema, e consequentemente mais pessoas talentosas e capacitadas serão necessárias para fazer isso acontecer.

A grande sacada de Evans com o DDD, foi justamente concentrar-se no domínio, tentando, através da apresentação de boas práticas, regras e padrões, mitigar ao máximo sua complexidade.

“… tentando, através da apresentação de boas práticas, regras e padrões, mitigar ao máximo sua complexidade.”

Através do estudo sobre DDD, percebemos que é extremamente conveniente que os desenvolvedores envolvidos em um projeto passem a "viver” o domínio, incorporando-o sempre que possível no seu dia a dia. Se isso não for possível, que no mínimo eles estejam interessados sobre ele. Veremos à seguir algumas vantagens ao tomar essa ação.

Aprofundando no domínio

Foto por Amy Lister no Unsplash

É interessante observar que as refatorações mais significativas que resultam em grandes mudanças e que de fato fazem um software evoluir geralmente se iniciam com uma visão mais aprofundada de algum desenvolvedor ou arquiteto sobre o domínio (processo conhecido no DDD como destilação) — inclusive Vaughn Vernon escreveu um livro bastante interessante chamado Domain-Driven Design Distilled, cujo título faz uma analogia com o termo.

Precisamos estar cientes que muitas das vezes, melhorias realizadas sem essa visão mais aprofundada ou sem um objetivo muito claro, tendem a resultar em economia de centavos e perda de dólares. Quero deixar claro que sou a favor da diminuição de custos, porém o foco maior deve ser em aumentar a receita, e a forma mais eficiente de se alcançar isso é através do entendimento cada vez maior do domínio.

A questão é que grande parte dos desenvolvedores não tem interesse em mergulhar a fundo sobre um domínio específico em que estejam trabalhando, pois isso exigiria muitos outros novos conhecimentos, como: aprimoramento da capacidade de modelagem, design de domínios, entre outros.

Essas atividades, em um primeiro olhar, não parecem agregar muito para as capacidades de um cientista da computação e acaba sendo mais cômodo deixar elas a cargo de outras pessoas. Porém ao decidirmos abrir mão disso, estamos perdendo uma grande chance de enfrentarmos a complexidade existente no coração do software, e qualquer tentativa de se fazer o contrário é arriscar a irrelevância…

Linguagem onipresente

Foto por Mimi Thian no Unsplash

Na foto acima podemos imaginar que a moça com o notebook é uma arquiteta / desenvolvedora que está colhendo informações de uma especialista de negócio.

Esse tipo de situação é bastante comum na vida dos programadores. Talvez a figura de especialista possa ser substituída por um cliente, product owner ou gerente. Porém, uma coisa é constante nesses contextos: estamos sempre tentando absorver informações de negócio ou tentando entender algum requisito.

Nessas conversas, várias armadilhas podem acontecer e que podem trazer grandes problemas para a evolução de um produto. Só para citar apenas algumas delas, temos:

  • Desenvolvedor(a) pensando em complexidade técnica ao invés de estar tentando entender de fato o domínio do problema que está sendo apresentado.
  • Especialista de negócio tentando falar a linguagem do(a) desenvolvedor(a), como por exemplo colunas na tabela do banco de dados, tipos de atributos necessários, etc. Algumas vezes o domínio já é complexo o suficiente para impedi-lo de se expressar e explicar com facilidade, imagine ao mesmo tempo tentar adaptar isso para a linguagem de programação? Sem chance.
  • Utilização de mais de um termo para representar a mesma coisa, ou um mesmo termo representando mais de uma coisa.

Dessas poucas que citei, a última é a mais nociva entre elas. Ela geralmente carrega um potencial grande de gerar ou iniciar o processo de geração de produtos/features que simplesmente não resolvem o problema apresentado. Isso geralmente acontece porque durante as reuniões os envolvidos pensavam que estavam falando sobre uma mesma coisa, enquanto que na realidade não estavam.

O uso da linguagem onipresente ajuda a resolver essa questão, pois seu objetivo é fazer com que os desenvolvedores entendam de fato as terminologias do negócio usados pelos especialistas e passem a também utilizá-los exaustivamente em conversas com seus pares sobre o domínio. Observe que isso não significa utilizar o todas as terminologias, mas somentes as necessárias para o domínio da solução, e não do problema. Após isso, essa linguagem deverá ser introduzida a nível de código.

Fazendo isso, teremos como resultado a mesma linguagem sendo utilizada por todas as partes, desde conversas com especialistas e desenvolvedores, até o próprio código do sistema (por exemplo, através da nomeação de métodos ou entidades, representando processos ou modelos do negócio).

O uso contínuo da linguagem onipresente expulsa / força a expulsão das fraquezas de um modelo.

Contextos delimitados

Foto por Annie Spratt on Unsplash

Não vou aprofundar muito sobre a ideia de contextos delimitados, porém vale ressaltar que, caso conversas com especialistas de negócio diferentes resultem na utilização de termos distintos representando a mesma coisa ou um mesmo termo representando coisas diferentes, é um forte indicativo da presença de mais de um contexto delimitado ou bounded context.

Apenas para exemplificar isso, imagine que você está em um hospital, e um enfermeiro chegue e fale para você:
- Bom dia, cliente!

Você acha um pouco estranho, mas depois segue para a área de gestão comercial hospitalar e a secretária diz:
- Bom dia, paciente!

Isso seria no mínimo bizarro! Você não quer que os dados da sua consulta estejam disponíveis para pessoas da área comercial, não é mesmo? Lá você é cliente! E no caso da enfermaria, você gostaria de ser tratado como paciente!

O mesmo vale no momento de representar isso através do software. Por exemplo, não faria sentido você utilizar um único modelo para representar uma pessoa e utilizá-lo tanto pela parte comercial quanto pela área de enfermaria, pois são contextos delimitados distintos.

Dados como consultas, estado de saúde, entre outras coisas que dizem respeito apenas a paciente, não podem ou ao menos não deveriam, estarem disponíveis em um modelo utilizado pela ala comercial. E mesmo que a nível de código você tenha um controle para evitar isso, adicionará complexidade desnecessária, sem contar o fato que abrirá brecha para uma possível falha de segurança.

Existem inúmeras outras coisas que gostaria de falar sobre design orientado a domínio, porém não vou estender mais o artigo para explicar técnicas e padrões apresentados no livro, mas pretendo em um futuro próximo iniciar uma série sobre DDD aqui no blog, passando por cada capítulo do livro, condensando todas as partes que achei mais interessantes.

Para finalizar, queria comentar sobre aquela máxima que várias pessoas gostam de falar: “O papel do desenvolvedor é resolver problemas”. Isso já foi reformulado há muito tempo.

Nos dias de hoje não basta apenas “resolver problemas”, mas sim ter a capacidade de identificar os problemas que realmente valem a pena serem resolvidos. Nesse momento, o conhecimento do domínio acaba sendo peça fundamental para facilitar essa identificação.

Espero que essas ideias tenham contribuído de alguma forma. Nos vemos em breve!

--

--

Augusto Mesquita
LazyDev
Writer for

Um simples amante da programação e fã de Game of Thrones! Instagram:@augustomesquitasrs