Como desenvolvedores, às vezes somos apresentados à tarefa potencialmente desagradável de retornar ao código realmente antigo (ou pior, como consultores, visitá-lo pela primeira vez). Neste artigo, dou uma olhada em alguns projetos e discuto algumas das técnicas usadas para começar a funcionar rapidamente.

Escavando Código Antigo

Comecei a escrever código como estudante/hobbysta em 1980 e profissionalmente em 1990. Durante grande parte da minha carreira, a noção de trabalhar em código antigo era relativa. Se eu trabalhar em outra coisa por três meses e depois voltar, isso é velho, certo? Eu sabia que havia sistemas de mainframe por aí que eram mais antigos do que eu, mas eu não tinha visto nenhum em primeira mão.

Meu início profissional centrou-se no Visual Basic 3.0 e, eventualmente, HTML, JavaScript e ASP. A tecnologia da Web era nova, e mudando tão rápido naquela época, que o conceito de código antigo nem estava em nosso radar.

No início dos anos 2000, a Microsoft anunciou simultaneamente o fim iminente do VB “Clássico” e anunciou a chegada do VB.NET e do C#. Eu entrei nessa onda, felizmente me esquivando da bala de “código antigo”, porque naquela época, não havia código .NET herdado. Agora, aqui estamos e o .NET tem 15 anos. Há código antigo em todos os lugares que você olha. Na verdade, o próprio .NET agora está tão atolado com lixo herdado que a Microsoft está efetivamente começando de novo (novamente) com o .NET Core.

Na verdade, o próprio .NET agora está tão atolado com lixo herdado que a Microsoft está efetivamente começando de novo (novamente) com o .NET Core.

Uma peça de cada vez

Há uma ótima música de Johnny Cash sobre um operário de fábrica que constrói carros Cadillac. Ele realmente quer um dos seus, mas não pode pagar, então ele contrabandeia uma parte a cada semana por anos. Quando finalmente chega a hora de montar o carro, sem surpresa, nenhuma das peças se encaixa muito bem.

Esse carro foi esse projeto que estou prestes a exumar. Claro, funcionou - principalmente - mas a manutenção foi um pesadelo.

Este projeto Web ASP.NET relativamente pequeno já existia há alguns anos e tinha sido tocado por MUITAS pessoas diferentes. Você podia praticamente ver as impressões digitais distintas de cada pessoa, na forma de estilo de codificação e escolhas arquitetônicas.

Quando o herdei, havia pelo menos quatro maneiras diferentes de fazer operações CRUD no código. Um cara acreditava muito em Stored Procedures e outro preferia SQL embutido. Outra pessoa queria tudo em uma camada de dados que ele mesmo escreveu, e outra preferiu usar a Enterprise Library.

Dependendo da sua tarefa, você pode não ter tempo para consertar tudo o que achar horrivelmente, horrivelmente errado, não importa o quanto você queira.

 'Case In Point

If Not IsNothing(obj) = False Then
...
End If

Se você está caçando um problema, às vezes você tem que quebrar coisas (temporariamente) para corrigir outras coisas. Se você não tem certeza do que algo faz, desligue-o (comente-o) e veja o que quebra. Se você estragar algo e não conseguir encontrar o caminho de volta, sempre há controle de origem.

Estou fazendo uma suposição aqui, então se você não tem controle do código-fonte, pare o que está fazendo e coloque o projeto no controle do código-fonte AGORA, ou faça um backup ou o que quer que você tenha que fazer. Se você está rindo, estou supondo que é porque você já está dolorosamente ciente de quantas vezes isso acontece no mundo real.

Dependendo da sua tarefa, você pode não ter tempo para consertar tudo o que achar horrivelmente, horrivelmente errado, não importa o quanto você queira.

Se você não está lá para corrigir um bug, é lógico que você deve estar tentando adicionar algo novo. A arquitetura existente pode tornar a adição de coisas novas um processo doloroso.

“Bolt-On Features” são muitas vezes considerados como ruins, mas às vezes são uma necessidade inevitável nesta linha de trabalho. Em um aplicativo legado como este (contendo uma mistura arquitetônica), não há uma única abordagem certa além de uma reescrita total. Sua melhor aposta é ir com o estilo que mais combina com o seu, ou seguir as escolhas arquitetônicas com as quais você se sente mais confortável. Se você tiver sorte, esta será a mais nova tecnologia, mas não conte com ela.

Há momentos em que não há problema em mostrar sua individualidade e brilhantismo, mas este provavelmente não é um deles. Adicionar mais caos à pilha pode introduzir problemas imprevistos, tornar mais difícil para você manter mais tarde e, quase certamente, tornar mais difícil para a próxima pessoa aparecer. Como dizem: “Quando estiver em Roma, faça como os romanos”.

Cavando fundo

O próximo projeto que vou discutir é um dos meus. Estou trabalhando em um pequeno jogo de RPG (chamado “Heroic Adventure!” ou “HA!” para abreviar) desde 2003, off and on. Tenho explosões periódicas de produtividade, pontuadas por anos de inatividade.

Toda vez que revisito depois de uma longa pausa, percebo o quanto aprendi desde a última vez. Infelizmente, isso significa que começo a me distrair com todas as coisas que quero corrigir ou refatorar, em vez de me concentrar no motivo pelo qual estou de volta ao código em primeiro lugar. A menos que seja o seu objetivo pretendido, você deve evitar a tentação de refatorar apenas porque você sabe um caminho melhor agora.

Há alguns meses, voltei ao código depois de cerca de dois anos longe dele. Havia alguns bugs conhecidos que eu queria corrigir, e alguns novos recursos que eu queria adicionar. Infelizmente, eu não escrevia VB.NET de produção há algum tempo, tendo trabalhado principalmente em C#, e o fato de que este projeto foi iniciado no VB.NET 1.1, e atualizado para 2.0 (anos atrás) não ajudou.

A menos que seja o seu objetivo pretendido, você deve evitar a tentação de refatorar apenas porque você sabe um caminho melhor agora.

Metade das coisas que tentei não existiam no .NET 2.0, então tive que atualizar o projeto para 4.x. Felizmente, não quebrou nada (nem deveria ter), mas isso pode e acontece.

Eu também passei muito tempo folheando o código em um esforço para lembrar como ele funcionava, ou por que eu o escrevi dessa maneira. Muitas pessoas não percebem que F5 e Ctrl-F5 (depurar e executar sem depurar, respectivamente) não são suas únicas opções para iniciar seu código. Você também pode usar F10 e F11 (passo a passo e passo a, respectivamente), que são especialmente úteis se você não tiver certeza de onde exatamente na base de código seu aplicativo começa.

Uma coisa que não recomendo é o uso excessivo do atributo ‘<DebuggerStepThrough()>’’. Tudo bem para métodos relativamente curtos que você tem que passar com frequência, mas há poucas coisas mais frustrantes do que passar por um código que você mal se lembra (ou nunca viu) e pular de um desses. Você provavelmente vai se ver querendo arrancar todas as instâncias que encontrar. Se não, quem vier depois de você quase certamente o fará.

 'Case In Point

'This is ok:
<DebuggerStepThrough()>
Function SimpleMethod() As Integer
    Return RND.Next(1, cap)
End Function

'This is not ok:
<DebuggerStepThrough()>
Function ComplexMethod() As Integer
' ...
' 380 lines of complex code
' ...
End Function

Se você não estiver familiarizado com ele, esse atributo essencialmente diz ao depurador “tudo está bem aqui, nada para ver, siga em frente” e, como resultado, mesmo que você esteja entrando em todos os seus métodos linha por linha com F11, isso se comporta como se você apertasse F10 e simplesmente executasse o código sem entrar nele.

Você quer que eu faça o quê?

Neste último exemplo, adquiri a responsabilidade por uma coleção de aplicativos de formulários do Microsoft Access 2010. Como muitos aplicativos do Access, além de serem códigos muito antigos, eles foram inicialmente escritos por um não desenvolvedor, passaram por algumas mãos e depois para o meu. Para piorar, partes do código foram escritas em albanês, o que definitivamente não estava listado no meu currículo. Eu também não tinha instalado o Access no meu computador desenvolvedor em provavelmente 10 anos ou mais.

Quando abri o primeiro, não tinha ideia do que o aplicativo deveria fazer, como funcionava ou o que qualquer um dos inúmeros botões fazia. Então, meu primeiro passo foi inserir pontos de interrupção em cada método que servia como um manipulador de eventos e começar a clicar em botões para que eu pudesse mapear tudo.

Depois que eu tive uma boa ideia do que os botões mapeavam, o próximo passo foi realmente cavar a carne do código. Neste exemplo, eu não estava lá para adicionar novos recursos a nenhum dos aplicativos, mas simplesmente para fazê-los funcionar em um novo ambiente. Acontece que, ao vasculhar o código, descobri que havia muitas coisas que nunca funcionaram em primeiro lugar (botões que não levavam a lugar nenhum, falta de verificação nula em vários controles, métodos incompletos, etc.).

Fiz uma lista de tudo o que encontrei: coisas ambientais (como IDs de usuário codificados e caminhos de rede), coisas quebradas, coisas inacabadas ou órfãs, problemas de desempenho, etc. Uma vez que a lista foi feita, a equipe priorizou o que abordar primeiro, o que pesquisar mais e o que adiar “indefinidamente”.

Meu primeiro passo foi inserir pontos de interrupção em cada método que servia como um manipulador de eventos e começar a clicar em botões para que eu pudesse mapear tudo.

Enquanto explorava, eu continuava me deparando com recursos que eram restritos pelo ID do usuário. Cada um desses recursos (havia muitos) tinha uma lista codificada de IDs em uma instrução If que encapsulava todo o código na função. Em vez de adicionar meu ID a cada lista, o que teria sido demorado e temporário, coloquei um ponto de interrupção em cada instrução If e, em seguida, arrastei o ponto de execução para a ramificação “True”, ignorando a segurança e permitindo que eu continuasse meu caminho.

 'Case In Point
Private Sub cmdDoStuff_Click()
If (ID = "uuuuu"
 Or ID = "vvvvv"
 Or ID = "wwwww"
 Or ID = "yyyyy"
 Or ID = "zzzzz") Then
DoCmd.OpenForm "frmDoStuff", 0
Else
    MsgBox "Access denied."
End If
End Sub

Aliás, o Google Tradutor fez um trabalho bastante decente no albanês (exceto os que foram submetidos à Notação Húngara), mas ainda levei um pouco para enrolar minha cabeça em torno de alguns dos nomes de variáveis e funções.

Conclusão

Espero que você tenha encontrado algumas dicas úteis neste artigo e possa fazer uso de algumas ou todas elas na próxima vez que tiver que mergulhar em algum código antigo ou desconhecido, ou melhor ainda, que você nunca fique preso trabalhando no código antigo de outra pessoa. Boa sorte.


  • Por Chris Williams
  • Publicado em: CODE Magazine: 2017 - novembro/dezembro
  • Última atualização: 11 de maio de 2021

Artigo Original