Meu CRUD é melhor que o seu - DDD e melhores práticas de programação
Antes de qualquer coisa, me perdoe pelo título clickbait.
Depois de algum tempo desenvolvendo e com a experiência que compartilharei neste post, passei a acreditar que não pode existir algo como best practices absolutas em um contexto repleto de trade-offs, como é o desenvolvimento de software.
Este post é sobre o que me levou a ter essa crença e também sobre os benefícios que ela me trouxe como desenvolvedor.
Tarefa: desenvolva uma aplicação financeira simples
A minha epifania começou com um desafio de programação do qual participei recentemente, cuja tarefa era desenvolver uma aplicação financeira com os seguintes requisitos mínimos: CRUD de contas bancárias e operações financeiras entre elas.
O enunciado era verdadeiramente bem aberto. Era obrigatório o uso de algumas bibliotecas e ferramentas, mas o que você quisesse construir em cima da ideia central de aplicação financeira ficava ao seu critério.
Minha abordagem sobre o problema, no entanto, foi conservadora, sendo a única adição à minha entrega um sistema de autenticação simples para identificar os donos das contas bancárias. Porém, queria usar o desafio como uma oportunidade de aplicar o que estava estudando no momento: o Domain-Driven Design (DDD).
Ainda assim, fui conservador. Sei que aplicar rigorosamente todas as práticas do DDD é custoso, então me contentei em aplicá-lo de maneira mais estratégica, definindo uma linguagem ubíqua, contextos delimitados (implementados na forma de módulos) e domínio rico, porém sem agregados complexos, eventos de domínio no código ou mesmo serviços de domínio.
A ausência de algumas práticas se dá até pela simplicidade da aplicação. DDD não é bem aplicável ou mesmo um diferencial para tão pouca complexidade. O domínio, nesse caso, era muito simples.
O resultado foi um back-end bem estruturado, robusto e desacoplado, com domínio bem definido, módulos independentes a nível de domínio (contextos delimitados) e código testável.
Evite complexidade desnecessária, ou sofra com a burocracia criada
O problema começa quando de fato começo a programar.
Foi necessário fazer o módulo de autenticação e o módulo de contas bancárias para perceber que o código que eu havia escrito, por mais que seguisse as chamadas "melhores práticas", estava me cansando.
A verdade é que aplicar todas as melhores práticas de programação, em todas as instâncias possíveis, gera complexidade, que por sua vez gera burocracia, com a qual tive que lidar para finalizar o back-end com o módulo de transações.
Otimização prematura é a raiz de todo mal
Essa frase, creditada a Donald Knuth, vem de outro contexto, mas faz total sentido aqui também.
Ao tentar elaborar um software otimizado do ponto de vista de design e arquitetura, gastei muito tempo pensando em coisas irrelevantes para a entrega do desafio, que tinha um prazo apertado.
Simples é melhor que complexo
O pessoal do Python está certo nessa.
Essa frase, que faz parte do Zen of Python, conversa muito com princípios de design de software como o KISS (Keep It Simple, Stupid) e o YAGNI (You ain't gonna need it), e acredito que deveria ser o mantra de todo desenvolvedor.
Se meu objetivo fosse unicamente ganhar o desafio, não deveria ter focado em práticas tão trabalhosas de serem implementadas, mesmo em uma aplicação de tamanha simplicidade.
E, apesar de aplicar o DDD ter sido minha intenção desde o início, mesmo que de maneira simplificada, meu atrito com a burocracia que eu mesmo criei me mostrou que nem sempre é a melhor escolha aderir às melhores práticas.
Meu CRUD NÃO é melhor que o seu
Essa é a verdade. Principalmente se tratando de CRUD (risadas programáticas).
O usuário não liga para os patterns que você aplicou no seu código, ou sobre o quão desacoplado é o seu sistema. Contanto que seu sistema reaja da forma que o usuário espera, você ou sua empresa estarão no verde.
Código bom é código que compila
Calma lá, não é bem assim.
Não é porque não se deve aplicar o máximo de melhores práticas possível sempre que é para fazer código ilegível, que não escala, ou que seja impossível de manter.
O usuário liga para o seu código se ele não escalar, só que indiretamente.
Um código mal escrito aparece para o usuário na forma de:
- Funcionalidades adiadas
- Baixa responsividade ou latência
- Pouca ou nenhuma confiabilidade
- Fragilidade
- Entre outras coisas bem chatas
Mas às vezes é só de um código que compila que você vai precisar, por exemplo: quando se trata de uma prova de conceito ou em um contexto ágil (com ressalvas) ou de entrega contínua.
Trade-offs, trade-offs, trade-offs
Como desenvolvedor e aspirante a arquiteto de software, essa é a lição mais importante que aprendi até agora. E isso não serve somente para código, mas para os negócios e até para a vida.
Se você, como desenvolvedor, está preocupado com a IA tomando o seu emprego, não se desespere se você faz o que só um humano pode fazer: tomar decisões (sejam elas boas ou ruins).
Arquitetura é o que você não consegue pesquisar no Google
- Mark Richards, em Fundamentos da Arquitetura de Software
E complemento: é o que você não consegue terceirizar para a IA.
Isso porque tomar uma decisão sobre arquitetura envolve conhecer um contexto, ou múltiplos contextos, que não cabem em um prompt.
Além disso, voltando ao tópico do post, para analisar trade-offs é necessário buscar pela alternativa menos pior para os cenários em que seu software, sua empresa e seus clientes se encontram. A melhor alternativa simplesmente não existe, ou, se existe, mal pode ser encontrada.
Não existe resposta certa nem errada na arquitetura, apenas trade-offs
- Neal Ford, em Fundamentos de Arquitetura de Software
Todas as decisões possuem pontos positivos e negativos atrelados a elas; precisamos conhecer ambos e tomar uma decisão, maximizando os pontos positivos e minimizando os negativos.
E é por isso que no fim, se tratando de trade-offs, "depende" costuma ser a única resposta correta mesmo.
Se liberte das amarras do purismo de software
Absorver essas ideias que compartilhei neste post foi essencial pra mim.
Como eu disse, foi uma epifania que tive ao participar de um desafio de programação.
Eu fiquei em segundo lugar no desafio, que me ensinou um pouco mais sobre o que falei neste post, por exemplo sobre como acelerar o desenvolvimento usando ferramentas baseadas em modelos de linguagem.
Mas essas lições vão ficar pra sempre.
Purismo de software é isso, focar demais em supostas melhores práticas em vez de focar na resolução dos problemas reais que estão na sua frente. É criar complexidade desnecessária, que em pouco tempo vira um problema, criado por você mesmo.
Estou há 2 semanas limpo do purismo de software.
Considerações finais
Antes da entrega, eu refiz o back-end da aplicação com o intuito de me livrar de burocracias desnecessárias e o resultado me deixou bastante satisfeito.
Clique aqui para ver o repositório da minha entrega, se ficou curioso.
Pode ser um recurso interessante para você caso seja iniciante, mas não prometo nada para quem for calejado em tudo que compartilhei neste post.
Este post não nasceu aqui. Ele faz parte do meu blog que comecei com o propósito de expor minhas opiniões e aprendizados, técnicos e nem tanto. Dá uma olhada lá: http://blog.joevtap.com.