Boa parte do dinheiro desperdiçado em software nasce de uma ilusão: a de que toda complexidade pode ser eliminada. O grande engenheiro de software Fred Brooks (vencedor do prêmio Turing, o “Nobel” de engenharia de software) publicou, em 1986, um paper icônico chamado (minha tradução livre) “Sem Bala de Prata — Essência e Acidente em Engenharia de Software”. Brooks fez ali a brilhante distinção entre os dois tipos de complexidades de software (essenciais e acidentais), e entender essa distinção não é apenas conversa acadêmica, está na base de como investir corretamente em ações de Quality Assurance em projetos de software; ignorar essa diferença faz times atacarem exatamente o tipo errado de problema.
Toda solução de software resolve um problema no mundo real; esse problema é inerentemente complexo, e essa complexidade não é “redutível” através de arquiteturas ou algoritmos. O que vale dizer que tudo aquilo que tem relação com o domínio (indústria, regras de negócio e funcionalidades) tem uma “baseline” de complexidade que não pode ser removida. Essas são as complexidades essenciais.
Tentar remover essas complexidades é tarefa inglória, pois é impossível. Não há atalho, arquitetura, modelo ou processo que possa fazê-lo: pense, por exemplo, em uma aplicação que suporta o processo de aprovação de crédito de uma instituição financeira: não existe versão “simples” desse processo que ainda seja válida. Há passos e características mínimos inerentes a requisitos regulatórios e de negócio que devem, necessariamente, estar presentes na implementação de software.
Já as complexidades acidentais dizem respeito a complexidades “criadas” pelos próprios engenheiros de software. Aqui entram pontos como implementações lógicas ruins, designs que não são intuitivos, processos de teste que não priorizam funcionalidade, falta de governança no processo de software etc.; em outras palavras, tudo aquilo que faz o software ser mais difícil do que o domínio exige. Essas complexidades são as únicas que podemos atacar, seja através de processos, seja através de ferramentas.
Ter em mente essa distinção é “essencial” (perdão pelo trocadilho) no momento de desenhar o processo de desenvolvimento de software de um projeto. Isso significa entender, de saída, que certas complexidades (atributos do domínio de negócio) vão necessariamente ter que estar presentes na solução, e que não temos saída além de (1) tentar entender tais complexidades o melhor possível e (2) tentar minimizar as complexidades acidentais que surgem quando ocorre a tradução entre domínio e funcionalidade, entre funcionalidade e requisito de software, e entre requisito de software e artefatos.
Ironicamente, esse contexto trazido por Brooks significa que podem existir complexidades acidentais que derivam diretamente do não-entendimento de complexidades essenciais. Em outras palavras, causas-raiz de falhas que são introduzidas justamente porque tentamos criar “atalhos” ou “band-aids” para “superar” problemas de negócio. Aqui nascem os débitos técnicos mais graves, e os bugs mais caros.