quinta-feira, 1 de outubro de 2009

Persistir ou jogar tudo fora?

Apesar de ser fã do Fred Brooks e suas leis do desenvolvimento de software, bacanas mesmo são as leis de Lehman sobre a evolução de software:

  1. Lei da mutação contínua: um sistema em uso deve sofrer modificações constantes ou degradar em sua eficácia;
  2. Lei da complexidade crescente: um programa de computador que é modificado se torna cada vez menos estruturado; as mudanças aumentam a entropia e complexidade do programa.
A justificativa da primeira lei é brilhante. Um sistema de computação é desenvolvido para resolver um problema existente no mundo real. No entanto, quando o sistema é colocado em operação, ele muda o mundo real, pois agora está inserido nele. Como o mundo real mudou, os problemas que o sistema foi criado para resolver também mudam, exigindo que o sistema seja modificado para atender à nova realidade. Quando o sistema modificado entra no ar, ele muda o mundo real... e assim por diante.

A segunda lei é mais difícil de se justificar, porém fácil de se observar na prática. Todo desenvolvedor já viu código que começou bem, mas com o tempo foi virando uma macarronada difícil de acompanhar. Existem técnicas como a refatoração que visam reduzir a entropia introduzida por mudanças. Refatorar ajuda a diminuir o ritmo da degradação sim, mas não resolve. Um dia você olha e simplesmente não dá mais pra fazer aquela mudança aparentemente simples que te pediram pra fazer.
 
As duas leis são antagônicas: a primeira diz que você precisa evoluir o seu software, ou ele se torna menos útil; a segunda diz que se você evoluir o software, ele se torna pior.

O que fazer? Em geral as pessoas priorizam a primeira lei. Tem mudanças que precisam ser feitas, e pronto. A prioridade continua valendo até que alguém dá um basta, pois simplesmente não dá mais pra se fazer mudança nenhuma.

Faz pouquíssimo tempo eu mesmo participei de um esforço desses - reescrevemos um sistema gigante que já estava insustentável. Todo mundo reclamava do código todos os dias. Os adjetivos usados não podem ser reproduzidos aqui em um blog que é lido por menores de idade.

No final do esforço, que foi imenso, todo mundo feliz, satisfeito com um código novinho em folha que usa tecnologias modernas e todas as boas práticas de desenvolvimento que a gente conseguiu descobrir, e mais algumas. Lindo mesmo, extensível, testável, modificável...  e enquanto reescreviamos, a primeira lei ficou em segundo plano e o sistema, que não evoluiu durante meses, se tornou cada vez menos útil.

E o pior: dou quatro anos pra começarem a usar os mesmos adjetivos pra se referirem à gente que a gente usava pra se referir a "eles," os autores do código original. Em quatro anos vai estar uma bela porcaria de novo, lento, impossível de consertar uma coisa sem quebrar outra. Lehman já dizia isso em 1974, trinta e cinco anos atrás, e nada mudou desde então. E o ciclo se repetirá.

O que fazer, então? Como evitar que se tenha de gastar centenas de milhares de dólares daqui a quatro anos, fazendo tudo de novo?

A resposta: não priorize a primeira lei, nem a segunda. Explicando melhor: faça apenas as mudanças que você antecipou e guarde as outras pra depois. 

Quando você escreve seu sistema, você antecipa inúmeros pontos de extensão e deixa no código os ganchos para as funções que você sabe (ou suspeita) que virão a ser necessárias. Enquanto as mudanças que você precisa fazer se encaixam bem nos pontos de extensão do sistema, tudo bem, lindo, seu código evolui graciosamente.

O problema é quando chega a primeira necessidade de mudança que você não antecipou e que exige uma adaptação na sua arquitetura. Fazer essa mudança vai degradar seu código. Cada mudança desse tipo vai piorando a sua situação até ela ficar insustentável.

Resista a essas mudanças. Guarde-as no seu caderninho e vá acumulando todos os requisitos que exigem mudanças arquiteturais o máximo que você conseguir. Quando estiver ficando insustentável e a primeira lei estiver te avisando que a utilidade do sistema está ficando baixa demais, é hora de projetar a próxima versão do sistema, de começar tudo de novo e reescrever o sistema do zero. Só que dessa vez você vai construir uma arquitetura que comporte tudo que o sistema atual faz e mais aqueles requisitos que você guardou no seu caderninho.

Assim, você atende em parte às necessidades da primeira lei: atualiza os requisitos, desde que não sejam necessárias mudanças arquiteturais. Também mantém a segunda lei sob controle: faz apenas mudanças que não degradam o código.

Quando for começar a reescrever, seu código ainda não vai estar degradado. Parte da equipe pode continuar atualizando a versão existente enquanto outra parte cria a nova versão. 
Talvez a diferença entre o sistema atual e o novo seja pequena o suficiente pra você conseguir aproveitar grande parte do sistema atual (que ainda está bom!) e construir a nova versão rapidamente. Talvez não. O importante é aceitar o fato de que você vai ter de reescrever tudo um dia. Esperar até a situação ficar insustentável e jogar tudo fora não é uma boa idéia. Assim que o código começar a cheirar mal, essa é a hora.

Nenhum comentário:

Postar um comentário