Refatoração: um pouco além do código (parte II)
No primeiro post deste assunto, abordamos sobre o que é a refatoração e o que nos leva a refatorar.
Neste post gostaria de expor um pouco sobre como lidamos com a refatoração, desde a escolha do que refatorar até alguns cuidados que levamos sempre em consideração.
Como escolhemos as batalhas que queremos lutar?
Diante do volume de processamento e dados que temos, um dos desafios é manter um ritmo constante de Refatoração, enquanto mantemos tudo funcionando e entregamos novas funcionalidades.
Para nos auxiliar nas escolhas, o primeiro passo é dar visibilidade aos problemas. Os trechos que precisam de Refatoração são catalogados como dívida técnica de forma que todo o time tenha fácil acesso a essa informação.
O termo “dívida técnica” foi cunhado por Ward Cunningham e mesmo não tendo um valor monetário explícito, traz a dimensão do quão prejudicial o acúmulo de dívidas técnicas pode ser para um projeto. Ainda assim, com prudência é até possível contrair uma dívida de forma consciente. O grande Wagner Fusca fez uma ótima talk no TDC-SP sobre isso (slides aqui).
Idealmente o melhor momento para propor que o time “pague” uma dívida técnica é na fase de discovery, isto porque neste momento estamos focados em análises, descobertas e provas de conceito, além de termos a visão de todo o time. Embora seja comum descobrirmos algumas refatorações durante o delivery, já que é o momento em que estamos mais próximos do código e temos maior clareza da implementação.
Antes de “pagarmos” determinada dívida, nos fazemos alguns questionamentos importantes, como:
- Realmente temos um problema?
- Está atrapalhando o nosso dia a dia?
- É o melhor momento para atacarmos esta dívida?
- Temos orçamento para isso?
- Por que esta refatoração agora e não outra?
- Temos conhecimento do contexto?
Questionamentos como estes nos ajudam a minimizar a carga emocional na decisão de escolher a dívida que iremos pagar, em uma tentativa de reduzir a subjetividade da escolha.
Isto porque temos muitas variáveis no contexto, por exemplo um determinado acoplamento pode ser extremamente ofensivo para uma pessoa e completamente aceitável para outra. Enquanto a atualização de uma biblioteca pode destravar o desenvolvimento de uma funcionalidade que já estava na fila.
Como refatoramos?
Uma vez decidido o que vamos refatorar, aplicamos o ciclo do TDD para nos auxiliar durante a refatoração em si.
Fazendo intervenções cirúrgicas e com ciclos rápidos de feedback, nos permite identificar rapidamente o ponto de falha caso os testes quebrem.
A metáfora dos dois chapéus (Kent Beck) exemplifica bem o ciclo de refatoração:
Quando estamos com o chapéu de código novo, nosso foco é adicionar o novo comportamento/funcionalidade. Neste momento não executamos qualquer refatoração. Então escrevemos os testes, fazemos os testes passarem e não alteramos código já existente.
Quando estamos com o chapéu de refatoração, nosso foco é reestruturar o código. Neste momento não adicionamos novos comportamentos/funcionalidades. Então refatoramos o código, mantemos os testes passando e não adicionamos novas funcionalidades.
Esta troca de chapéus é algo que acontece com certa frequência ao longo do dia e respeitando cada chapéu nos ajuda a manter o foco na linha de raciocínio que estamos seguindo.
Alguns cuidados ao refatorar:
- Utilizamos ferramentas de apoio a identificação de Bad Smells, como Rubocop, por exemplo.
- Praticamos TDD, mas, mesmo para aqueles que preferem escrever testes após o desenvolvimento, o mais importante de tudo é que o trecho que está sob refatoração deve estar coberto por testes.
- Baby Steps: mesmo uma grande refatoração é feita de várias pequenas refatorações. Então alterar pequenos trechos de código seguindo o rápido feedback é essencial para manter o ritmo das refatorações.
- Intervenções cirúrgicas: aliado ao baby steps, manter-se a pouquíssimas alterações de distância do código que passava nos testes nos ajuda a identificar rapidamente algum efeito colateral da refatoração.
E por fim, de nada adianta termos o time envolvido 6 meses em refatorações e nossos clientes não terem seus problemas resolvidos. Balancear entre entregas do produto e refatorações é um desafio constante e um acordo entre o time. O autor do livro Refactoring to Patterns, Joshua Kerievsky, tem uma frase que exemplifica bem esta preocupação:
Negócios são bem servidos via refatoração contínua, ainda assim, as práticas de refatoração devem coexistir harmoniosamente com as prioridades do negócio.
Aqui em nosso time temos uma reserva média de 20% do delivery para dedicação à refatorações. Por exemplo, de 5 cards trafegando no board, 1 deles trata de refatoração.
Para leitura aprofundada, recomendo os livros:
- Refactoring: Improving the Design of Existing Code, de Martin Fowler.
- Refactoring to Patterns, de Joshua Kerievsky.
Além do catálogo de refatorações e de um excelente artigo sobre os tipos de dívidas técnicas.
E vocês, como escolhem as dívidas técnicas que irão pagar? E como lidam com o investimento em refatorações?