Quem já trabalhou em empresas com dezenas de sistemas desenvolvidos e mantidos internamente já se deparou com a decisão tentadora de reescrever um sistema como solução de seus problemas. Considerada a complexidade e os altos custos envolvidos no desenvolvimento de software, pode-se dizer que é irresponsável tomar tal decisão sem o devido cuidado e consideração. A seguir, são descritos alguns conceitos e opiniões sobre a decisão entre reescrever ou refatorar.
Reescrever é mais agradável
Desenvolvedores costumam detestar código existente. Em algumas situações, chegam ao extremo de não gostar de seu próprio trabalho feito no passado.
Para muitos desenvolvedores, nada é mais agradável a um desenvolvedor do que um arquivo em branco a espera de código-fonte. E não há nenhuma surpresa nesse comportamento: se você fosse um pintor, preferiria terminar um quadro de alguém ou fazer o próprio? Quando esse efeito natural do "quadro em branco" se soma a uma base de código mal escrita é inevitável não sugerir a famigerada reescrita.
Vários são os problemas originados da falta de cuidado e domínio na escrita de código mas, no contexto deste artigo, destacam-se dois: o "esforço cognitivo" e a "não-manuseabilidade".
O esforço cognitivo
Começa-se a entender um sistema "de fora para dentro" (ou de cima para baixo se preferir). Primeiro detecta-se as partes, quais são elas, suas funções e como interagem entre si. Depois, parte-se para entender os mecanismos que estão por baixo e fazer o todo funcionar. Em outras palavras, primeiro entende-se "o quê" para só então entender o "como".
Uma forma de destacar as partes umas das outras é através da organização do código, seja em diretórios, classes ou módulos. A separação do código não só deve ter o intuito da reusabilidade como também do entendimento.
Por mais imersos que estejamos em nossa profissão, a daquele que produz código, o natural do ser humano é transmitir ideias através da linguagem "de conversação", e não da linguagem de programação. Nada melhor do que entender a arquitetura de um sistema através de um texto escrito para um ser humano. É nessa hora que lamentamos a falta de documentação.
Através da organização do código e de uma documentação, o profissional consegue obter entendimento do que de fato o sistema faz. Quando a documentação não está presente, a alternativa, claro, é ler o código-fonte para inferir essas abstrações. O esforço cognitivo em fazer o primeiro é bem menor que o necessário para o segundo.
A não-manuseabilidade
Depois de entendida a arquitetura, procuramos utilizá-la. Uma arquitetura se provará digna ou não de ser seguida quando uma alteração brusca for necessária no sistema.
Mais uma vez, dois são os pilares a serem notados. O primeiro é quanto o código precisa ser manipulado para comportar tais alterações. É necessário alterar a arquitetura do sistema ou apenas seguí-la? O segundo é o efeito colateral destas mudanças. Independente da profundidade da alteração, é previsível seu efeito colateral nas outras partes?
Tomando a decisão
Grande parte das decisões em desenvolvimento de software se resumem em analisar as vantagens e desvantagens de cada abordagem. Sugere-se ao leitor, diante da escolha entre refatorar e refazer, comparar as duas escolhas nos seguintes critérios:
- Nenhuma funcionalidade nova: "Qual o esforço e impacto da manutenção do que o sistema já faz? Qual o impacto da reescrita?"
- Mudança nas funcionalidades existentes: "Qual o esforço e impacto das adaptações no que já existe?"
- Introdução de funcionalidades inteiramente novas: "Qual o esforço e impacto da introdução de novas partes no sistema?"
A maneira mais saudável de tomar essa decisão é reunir os envolvidos em torno de um quadro branco sumarizando e discutindo os pontos um a um, fazendo com que a combinação das opiniões emitidas resulte em uma decisão.
Módulo, módulo e módulo
"Sabe como se faz um grande sistema? Não se faz um grande sistema, faz-se vários sistemas pequenos."
Código volumoso é uma maldição. A tendência é que o esforço cognitivo e a não-manuseabilidade aumentem proporcionalmente ao volume do código, tendência essa conhecida como entropia (do software).
Uma forma de confinar essa entropia é através da divisão do sistema em módulos (ou pacotes). Todos nós em algum ponto de nossas carreiras aprendemos a "dividir para conquistar" mas muitas vezes não colocamos o ensinamento em prática.
Quem nunca se deparou com um algoritmo mal escrito para leitura de um arquivo CSV, que provavelmente não trata casos excepcionais como a presença do caractere de aspas, ao invés do uso de uma biblioteca mais robusta e bem mantida? Ou então o chamado "Ctrl+C Ctrl+V" de código na desserialização de dados oriundos de uma integração ou, pior ainda, de uma regra de negócio?
É comum no mundo corporativo que os desenvolvedores não modularizem o suficiente. Mas pode-se muito bem pecar pelo exagero e não pela falta. Um exemplo recente é a retirada do módulo left-pad do npm, um módulo extremamente simples que acabou quebrando inúmeros pacotes JavaScript. Tome cuidado para não ir de um extremo a outro.
Lição aprendida?
Se puder guardar uma ideia deste artigo, guarde este: "Ao tomar a decisão de reescrita, pergunte a si mesmo: por que dessa vez será diferente?"
Exemplos de projetos que deram errado não faltam, como o desastre que foi lançamento do site HealthCare.gov (programa do governo americano conhecido como Obamacare) ou qualquer um dos vários exemplos compilados pelo Jeff Atwood em seu blog.
Diante desta triste realidade, alguns seguem a irresponsável tática da tentativa e erro. Se um projeto não dá certo, simplesmente tentamos executá-lo novamente (com o mesmo cenário e as mesmas práticas) e esperamos que este agora dê certo.
Uma das piores culturas do desenvolvimento de software é a inanição diante das falhas em nossos projetos. O ideal é iterar um trabalho ao invés de jogá-lo fora e começar de novo. Deveríamos ter a coragem de dizer que dominamos a fera.
Sobre o autor
Talles Lasmar é um arquiteto de sistemas que "fugiu" do mundo acadêmico e foi para a indústria. É experiente com .NET, eterno interessado por concorrência, professor de git e admirador das soluções que são simples por natureza.