Domain Driven Design - Quando o gavião come a barata?

Há algum tempo (mais ou menos 4 anos) venho estudando e aplicando Domain Driven Design em diversos projetos. Normalmente meu trabalho nos projetos é planejar e construir a arquitetura dos sistemas ou avaliar e corrigir arquiteturas criadas por outras pessoas. Não precisa nem dizer qual dos dois eu prefiro né?

Para que eu possa expressar melhor o motivo que me levou a especialização em Domain Driven Design preciso voltar ao meu primeiro curso de Orientação a Objetos. Lá estava eu (há 7,5 anos atrás) com experiência em linguagens como C, Pascal, Object Pascal (Delphi), mas sem nenhuma noção do que era um “objeto”. Após uma breve explicação dos conceitos, vieram os exemplos de meu professor:

Lê-se: “Gavião é uma Ave que é um Vertebrado que é um Animal” e “Barata é um Inseto que é um Invertebrado que é um Animal”.

Quando eu comecei a entender essas relações eu imediatamente comecei a pensar nas diversas interações entre esses objetos. E comecei a pensar em como expressar as situações utilizando esses objetos. Como exemplo, pense na seguinte situação:

“O Gavião normalmente come a Barata.”

Uma forma de expressar isso em orientação a objetos seria:

Que resultaria em :

Pronto… código muito simples e de fácil compreensão. Isso não passa de orientação a objetos. O importante é entender a quantidade de práticas envolvidas neste exemplo e que só pude perceber depois que comecei a estudar Domain Driven Design.

O processo

Implementar Domain Driven Design implica modificar a cultura de desenvolvimento de software que hoje está impregnada nas maioria das empresas. Domain Driven Design significa desenhar software de acordo com o domínio (conjunto de informações e situações) relacionado ao problema que o software se propõe a resolver.

Esse domínio deve ser definido já no começo do projeto, pelo menos de forma superficial, para que você saiba o objetivo do software. Depois disso começa o aprofundamento no domínio. É importante lembrar que sua arquitetura e seu ambiente de desenvolvimento deve preparado para evolução, protegido por integração contínua e TDD para garantir a evolução do domain. Práticas de desenvolvimento ágil são muito úteis para isso.

Em algum momento na caminhada iremos começar a desenvolver software e consequentemente trabalhar com o domain, aprofundando o conhecimento da equipe. Existem algumas dicas para obtenção do conhecimento, exploração de conceitos ocultos e implicitos, para garantir que o domain reflita a situação em um nível aceitável.

O fator fundamental é dialogar muito com os domain experts (pessoas que possuem experiência no processo de negócio do qual o domain trata). Sem os domain experts não é possível realizar domain driven design (Alguém ve alguma semelhança com agile?) São eles que vão determinar quais são as informações e situações que o domain deve tratar. Isso exige postura por parte de quem desenvolve, já que a pessoa que desenvolve deve ser a mesma que irá obter o conhecimento.

Voltando ao nosso exemplo, a frase “O Gavião normalmente come a Barata.” representa uma explicação ou definição do domain expert e portanto deve fazer parte do domain. Essa situação de negócio pode ser expressada graficamente da seguinte forma:

Esse é um exemplo simples, mas com esse tipo de notação pode-se expressar processos de negócio complexos, o que ajuda muito na visualização do domain. É importante observar que nesta notação bem simples, temos todos os conceitos explicitos. Isso nos dá o gancho para o próximo item que é a criação de uma linguagem comum para o time.

Ubiquitous Language

Um importante conceito do Domain Driven Design é a criação e manutenção de uma linguagem comum, tanto para o cliente quanto para o time de desenvolvimento. A premissa diz que ambos devem expressar o negócio da mesma forma e isso visa melhorar a comunicação e o entendimento entre as partes.

Essa linguagem comum deve estar presente no dia-a-dia da equipe incluindo a obrigação de ser expressada em documentos e no código também. No nosso exemplo o código expressa exatamente o conceito antes comunicado pelo Domain Expert (a frase “O Gavião normalmente come a Barata.” ), comunicada pelo diagrama:

image

Isso é conseguido através de algumas técnicas de Supple Design (um dos mais interessantes conceitos de Domain Driven Design) e é facilitado com a aplicação da técnica de Fluent Interface.

Refactoring

Pensando na situação do exemplo, “O Gavião normalmente come a Barata” nos deixa com muitas dúvidas sobre esse contexto. De onde veio a barata? De onde veio o gavião? O que acontece quando o gavião come a barata? O que o domain expert quer dizer com “normalmente”? Onde está o wally?

Podemos aprofundar nosso conhecimento a partir do momento que o domain expert responder essas perguntas. Mas essas perguntas podem gerar novas perguntas e consequentemente, mais conhecimento a ser expressado. Continuando no exemplo:

Pergunta de desenvolvedor:

- Por que você (o domain expert) diz que “O Gavião NORMALMNETE come a Barata”? O que quer dizer “normalmente”?

Resposta do Domain Expert:

- O Gavião normalmente come a barata, mas tem vezes em que a barata consegue escapar do gavião.

Pergunta de desenvolvedor:

- Então a barata luta para não ser comida?

Resposta do Domain Expert:

- Sim. A barata tenta se esconder na hora em que o gavião começa a sobrevoa-la. Se a barata escapa então o gavião procura outra presa. Se a barata não consegue então o gavião come a barata. Mas isso é tão obvio que eu nem falei antes.

Nesse momento nosso conhecimento sobre o processo de negócio é mais profundo. Isso exige um refactoring em nossa ubiquitous language. Devemos modificar os documentos, a forma de falar, os diagramas e o código. Vejamos como ficaria nesse caso:

Nesse pequeno exemplo pudemos identificar a variação entre um conceito solto do processo e um pequeno detalhe “óbvio” que o domain expert não mencionou porque era obvio. Quantos problemas você já enfrentou porque deixou passar algum “detalhe óbvio”? Agora que temos o processo de negócio refatorado podemos partir para a implementação do código:

Percebam que na hora de implementar o código, vários detalhes aparecem (as ações gaviao.comeu?() e gaviao.caçar()). Por isso é fundamental que o dialogo com os domain experts sejam constantes. O conhecimento evolui e nossa imaginação pode dar direções diferentes para uma situação, por isso validar o conhecimento com o domain expert é muito importante. Além disso podemos melhorar a implementação desse código (técnicamente falando) de várias formas. Talvez o do…while não seja a melhor opção para expressar este caso. Isso deve sempre ser realizado em inspeções de código, trazendo uma visão de fora para verificar a clareza e eficiência do código. Alguém se dispõe a otimizar esse algorítimo?

Conclusão

Praticar Domain Driven Design é algo deve ser feito em equipe, com foco em negócio e nas situações do ponto de vista dos domain experts. O DDD foca em expressar negócio em forma de software para que possamos minimizar complexidade desnecessária e consequentemente custos de produção e manutenção. A orientação a objetos, apesar de um conceito isolado ao DDD, vem para ajudar na implementação de um bom design orientado a domínio. O DDD por outro lado oferece um processo que facilita muito a aplicação de Orientação a Objetos na forma mais pura e por isso eu costumo dizer que Domain Driven Design oferece a nós desenvolvedores um caminho de volta à orientação a objetos. Confiram em breve mais artigos sobre DDD e sua práticas aqui no blog. ;-)

Uma questão de percepção

Nesta semana, comecei a questionar a qualidade do serviço que presto a meus clientes. A primeira coisa que me veio à cabeça foi questionar a cultura das empresas que me contratam, com o objetivo de justificar a não utilização de conceitos que julgo de extrema importância, por exemplo Scrum e XP (meus processos favoritos) ou mesmo DDD (Domain Driven Design). Cheguei a seguinte conclusão:

Gerentes de projeto muito apegados e acomodados em seus cargos tem dificuldade de inovar e permitir que seus projetos fluam por vertentes mais produtivas. A cultura tradicional embutida na forma de desenvolver software está presente na maioria das empresas. E na maioria dos casos está fora de nossas mãos resolver essa situação.

Falta na maioria das empresas a iniciativa de busca por constante atualização e incentivo ao aprimoramento de seus profissionais. O profissional de informática tem por natureza o desejo de trabalhar sempre com tecnologias novas e conceitos revolucionários. Isso gera certo desconforto para os desenvolvedores, que são “obrigados” a enfrentar dificuldades desnecessárias no dia-a-dia, fruto do uso de tecnologias defasadas ou mesmo arcaicas.

Se por um lado isso é ruim, por outro é completamente compreensível, pois imagine a si mesmo como o responsável por um sistema crítico que movimento informações vitais para o negócio em questão. A confiabilidade exigida da tecnologia a ser utilizada é de extrema importância. Outro fator a ser ponderado é o dead-line do projeto. Prazos curtos inviabilizam a adoção de novidades devido à curva de aprendizado exigida.

Vejo isso como constante causa de insatisfação no relacionamento cliente/fornecedor (contratado / contratante), pois a expectativa do cliente não foi compreendida pelo fornecedor.

Na opinião do Dr. PhD Daivd H. Maister, uma das maiores autoridades sobre administração de empresas de serviços no mundo e autor de livros como “Managing the Professional Service Firm” e “True Professionalism” diz que a satisfação de um cliente pode ser medida através do que ele chama de “A Primeira Lei do Serviço”, expressa através da seguinte fórmula: “SATISFAÇÃO = PERCEPÇÃO – EXPECTATIVA”.

Entendo dessa forma que a satisfação de nossos clientes e empregadores é resultado da percepção que conseguimos estimular menos a expectativa (pode-se entender também como objetivo) sob a qual fomos contratados.

Para desenvolver software com qualidade, é necessário entender a real necessidade e principalmente a expectativa do cliente. De nada nos adianta sermos bons no que fazemos ou mesmo empregar muito bem os novos conceitos e tecnologias se não tivermos sempre em mente o objetivo do sistema e a expectativa em torno dele. A velha premissa de que o cliente tem sempre razão continua valendo mesmo para caso onde o tradicionalismo é mais forte que a inovação.

Uma boa notícia é que dispomos das metodologias ágeis que nos oferecem uma forma mais próxima para entender o cliente e assim conseguir atingir a satisfação mais facilmente. Mas como fazer o cliente entender os benefícios de uma metodologia ágil? Aí é uma outra questão. Acredito que uma conversa focada em satisfação, com flexibilidade e mentes abertas como sugerido neste artigo possa ser de grande valia nesse sentido.

Outro ponto importantíssimo para estimular a percepção do cliente é uso de “Software Visualization”, que consiste em uma imagem geral do sistema. Como um mapa da complexidade do sistema e como ele se comporta em relação ao negócio (domain) do cliente. Podemos assim demonstrar mais facilmente como foi implementado o que o cliente pediu e também mostrar benefícios antes ocultos aos olhos do cliente, como detalhes de flexibilidade na arquitetura. Isso é estimular a percepção do cliente.

Mas e quando se trata de uma migração ou mesmo de uma pequena alteração no sistema? Bom nesse caso o conceito de Software Visualization também se aplica, mas na forma de arqueologia arquitetural, levantando toda a arquitetura do sistema antes de implementar as alterações, possibilitando a participação do cliente na tomada de decisão sobre como o serviço deverá ser realizado.

Em resumo, devemos partir sempre da premissa de que “Um bom trabalho executado, não significa um bom serviço prestado.” E nós, como fornecedores ou como clientes, como contratados ou mesmo contratantes devemos sempre lembrar dessa premissa, para que possamos executar serviços cada vez com maior qualidade, mas também poder avaliar de forma justa e eficaz os serviços que nos são prestados.

Conflito entre conceitos

Where are we missing the way?
Em termos de desenvolvimento de software, sempre emcontramos divergências entre os paradigmas e soluções. Para resolver problemas no processo, recomendamos metodologias ágeis que, quando não bem interpretados, dão a entender que basta pegar algumas idéias e sair codificando. Para resolver problemas com o design, flexibilidade escalabilidade, sugerimos planejamento prévio e alguma documentação.

Para a equipe é importante possuir documentação, quando iniciar o desenvolvimento e, a rotatividade de profissionais em caso de projetos grandes, obriga que exista ao menos documentação técnica, definida com padrões e diretrizes a serem seguidas.

Então, como obter o melhor dos dois mundos? Como conciliar as duas abordagens?

Arquitetos de software e desenvolvedores são seres esquisitos e muito ocupados, que geralmente não tem vida social e pouquissímo senso de necessidade. Isso os leva a separar aquilo que deveria ser feito do que será feito. Frases como “Eu sei que aqui deveríamos fazer dessa forma, mas não dá tempo!” ou “Isso aqui foi feito assim, mas nós vamos refatorar isso pra que fique do jeito certo!”, nos passam a idéia de urgência. “Temos que entregar o sistema logo, senão cabeças vão rolar!”.

O que é urgente?
A palavra urgência derivada do latim urgentia, representa a qualidade do que é urgente. Algo que tem pressa, necessidade imediata. Também está relacionada com o voerbo urgir, que significa apertar, impelir, comprimir, não permitir delongas. Dessa forma, aquilo que é urgente na verdade é algo inadiável, que urge, que não admite delongas e que é necessário fazer-se rapidamente.

Imagine essa definição num contexto de desenvolvimento de softwares. Não sei para vocês, mas para mim soa como um mal cheiro no processo. Tudo aquilo que é urgente nos impele a agir de forma mecânica, sem pensar muito. Quando somos pressionados a fazer coisas às pressas, deixamos de lado boas práticas e abandonamos conceitos importantes, tudo por causa de algumas horas de impaciência de algum gerente de projeto. Isso não seria problema se fosse ocasional, mas o fato é que a maioria dos projetos sofre de urgência desde o início.

As consequências disso são catastróficas para o projeto. Código mal escrito, workarounds (pra não falar gambiarras mesmo!) e vários “Bad Smells” distribuidos pela aplicação. Porém a pior das consequências vem na parte de Design do software. O arquiteto fica sempre ocupado ajudando os desenvolvedores a resolver coisas urgentes que acaba deixando de trabalhar no design da arquitetura, seja para criar um design uniforme, ou memso para refatorar o design existente.

O que é importante?
Desenvolver software é uma arte e, como todo tipo de arte e, depende de um trabalho meticuloso para atingir um ponto satisfatório. Definir a arquitetura de um software, envolve diversas questões a serem respondidas e demandam tempo. Em geral, os arquitetos deixam de lado a simplicidade do modelo e se preocupam mais com questões de infrestrutura, segurança e afins e esquecem do design. Não digo que essas questões não sejam importantes, mas sei que o design merece uma atenção especial. Conceber um modelo de objetos para um determinado tipo de negócio é de extrema importância, e deve ser trado como tal.

Então o que há de errado com o que é importante? Nada! Porém o que é importante sempre é minimizado em prol do que é urgente. As equipes de desenvolvimento de software e arquitetura de systemas devem assumir que sempre o que é importante é prioritário, mesmo em relação ao que é urgente. Estamos falando de uma quebra radical de paradigma, que pode trazer divergências junto aos stakeholders do projeto. Sobre essa questão, sugiro a leitura do meu artigo “Uma questão de percepção” disponível no blog.fratech.net .

Away from OO
Após definir o que realmente é importante em seu projeto de software, a equipe deve preparar-se para utilização de boas práticas de desenvolvimento. O principal erro é criar modelos carregados de máquinas, de forma desordenada e nada similar à realidade.

É comum encontrarmos classes com nomes estranhos, como, PasswordValidator, PersonUnificator, UserIndentificator ou coisas desse tipo. Na verdade estamos realizando programação orientada a prestadores de serviço, sem nenhuma abstração do mundo real.

Domain Driven Design – What is this?
Anecessidade de se desenvolver um software é intimamente relacionada a solução de um problema, ou à evolução de um serviço. A orientação a objetos tem por objetivo facilitar a representação virtual do mundo real e, por isso, ao modelar um software, devemos ter em mente a realidade da situação que desejamos atender. Isso é denominado Domain Model.

Domain significa entre outras coisas “a esfera de conhecimento, inlfuencia e atividade”, por isso o domain de um negócio é a esfera de conhecimento, influência e atividades do negócio.

Domain Driven Design representa uma mudança no paradigma de desenvolvimento, rebuscando princípios da orientação a objetos, com o objetivo de melhorar a simplicidade e objetividade do sistema, facilitando a comunicação e utilização dos artefatos gerados no processo.

Orientar o desenvolvimento ao domínio do negócio nos obriga a investigar quais são os objetos que compõe o domínio do negócio. Por experiência, a melhor forma de se entender o domain de um negócio específico é conversando com os domain experts. Pessoas que conhecem profundamente as regras e detalhes sbre o negócio em questão e, não estamos falando aqui de analistas funcionais, mas sim, de pessoas que vivem o dia-a-dia da situação.

O Processo de Design
Desenhar um sistema utilizando Domain Driven Design ou qualquer outra técnica, devemos dedicar um esforço de tempo necessário. Nem pouco tempo, nem muito tempo. Normalmente se inicia o estudo sem muita idéia de qual é a real complexidade do negócio e dando menos importância aos requisitos não funcionais, como segurança e infraestrutura. Dedicar um tempo apenas para modelar os objetos de domain é fundamental para um bom design de qualquer sistema.

Mas como fazer isso quando o processo é baseado em uma metodologia ágil?

A impressão que as metodologias ágeis deixam é que não há tempo para perder com planejamento. Precisamos implementar as funcionalidades de acordo com o que o cliente pede primeiro. Em uma abordagem como essa, corremos o risco de acabar em um projeto extremamente bagunçado e sem estruturação em termos de design.

É fundamental que ao iniciar a implementação de um sistema, os desenvolvedores tenham uma referência sobre como o projeto deve se parecer. Entender o contexto da situação que envolve o sistema e, principalmente saber onde e como os metodos devem ser dispostos.

O design deve ser tratado como uma outra tarefa qualquer dentro do processo. Criar uma design macro da arquitetura e exemplificar como implementar algumas situações devem fazer parte do backlog do projeto. O modelo deve ser flexível e oferecer a possibilidade de evolução incremental, sendo incrementado sempre que uma tarefa específica exigir. Modificações mais abrangentes e de maior impacto devem ser tratadas como uma tarefa a parte e, ser acompanhado de perto pela equipe inteira.

Ao utilizar Domain Driven Design para modelar um software, estamos assumindo a premissa de que o modelo do software é um retrado apurado do negócio, portanto só deve ser alterado se o negócio como um todo sofrer alguma alteração. Nesse caso é imprescindível a participação do Product Owner e tamém dos Domain Experts, para assegurar que o novo modelo é coeso com a evolução do negócio.

The Language
Através do conceito de Ubiquitous Language (Linguagem Difundida) a utilização do Domain Driven Design também contribui para um outro aspecto do processo. A comunicação entre a equipe e o cliente. O cliente pode não saber nada sobre desenvolvimento de software e também não é obrigado a estudar um modelo incoeso, porém conhece profundamente o negócio para o qual o software está sendo desenvolvido. Quando os objetos e os nomes dos metodos são coesos com a realidade, fica fácil conversar com o cliente, auxiliando na visualização do software e, aumentando a percepção do cliente para o que está sendo feito.

Permanecer sempre alinhado ao negócio sempre é uma boa prática que traz produtividade e dinamismo ao desenvolvimento, porém é importante oferecer esforço e dedicação para que isso acontece. Na balança do que é válido, isso é sempre viável.

Abraços a todos!