Refatoração durante a programação

9

Quando coloco um problema, principalmente quando é de natureza complicada, tento dedicar algum tempo para pensar sobre a abordagem que vou adotar para resolver o problema. Apesar disso, o que acontece com frequência é que, ao programar a solução, começo a pensar nos detalhes do problema que perdi e ajusto o código de acordo.

O que resulta é uma bagunça de código que precisa ser refatorada.

Quero "refatorar a medida que for", mas, embora pareça fácil o suficiente, tenho muita dificuldade em fazê-lo. Quando os detalhes que eu perdi são pequenos, é tentador fazer uma pequena atualização no meu design, em vez de apagar o que já escrevi e escrevê-lo da maneira que deveria ser.

Parece uma pergunta com uma resposta óbvia, mas existem técnicas a serem usadas para melhor "refatorar conforme você avança"? Sei que esse é um bom princípio, mas falho repetidamente.

Kirby
fonte

Respostas:

17

Provavelmente, a observação fundamental no livro Refatoração de Fowler é que é muito melhor separar as mudanças que afetam o comportamento do código das mudanças que não o fazem. Aqueles na última categoria, chamamos de "refatoração". Se você misturar essas alterações, estraga tudo - então não faça. Você pode alternar entre os modos de codificação e refatoração, mas não faça as duas coisas ao mesmo tempo. Porque se você tentar, não saberá o que fez de errado.

Se você tentar introduzir uma mudança de modificação de comportamento, e o comportamento não for modificado: você fez algo errado; revise-o e corrija-o. Talvez apenas reverta.

Se você tentar introduzir uma refatoração, e o comportamento for modificado: você fez algo errado; revise-o e corrija-o. Talvez apenas reverta.

Você não pode fazer essa avaliação simples se tentar as duas alterações ao mesmo tempo. Nem você, se você não tiver testes de unidade. Escreva-os. E faça uma coisa de cada vez.

Carl Manaster
fonte
1
Conselho interessante ... Embora, como todos os conselhos, não 100%. Acho que esse conselho funciona bem se você fizer uma refatoração relativamente pequena de um código grande. Mas às vezes refatorações radicais, como reescrita quase completa, também são acompanhadas de novos recursos - e é eficiente fazer as duas coisas ao mesmo tempo.
Tomas
3
@ Tomas: A pergunta era claramente sobre "refatoração à medida que você avança", assim como a resposta de Carl (+1 de mim). Uma "reescrita quase completa" não é refatoração ... é, bem, uma reescrita.
Amos M. Carpenter
1
Não apenas misturar codificação com refatoração vai atrapalhar as coisas, mas também fazer refatorações diferentes ao mesmo tempo .
Rangi Lin
6

Aqui está o que eu costumo fazer: deixe suas anotações como comentários ou mesmo como código comentado. Quando o código estiver funcionando, você poderá reorganizá-lo facilmente.

Além disso, não há nada inerentemente errado com a refatoração à medida que avança, apenas verifique se há maneiras de testar se seu código refatorado não introduz novos erros antes de prosseguir.

Luke Dennis
fonte
acordado. Muitas vezes, é mais fácil refinar código de trabalho feio em código bonito do que tentar fazê-lo do zero. Você só precisa ser honesto e ter tempo para limpar sua solução quando ela estiver funcionando.
fácil
2
Porém, cuidado com o excesso de códigos comentados; caso contrário, tudo ficará confuso. Em geral, se você substituiu o código incorreto, exclua-o. Além disso, se for um projeto de grupo, seus colegas programadores geralmente não gostam de você por cometer código comentado sem uma excelente razão.
user24795
1
Minha abordagem: se você não tiver certeza do que está fazendo, comente o código antigo. Inclua suas iniciais e a data . Se você encontrar coisas que não parecem mais relevantes para uma data antiga, exclua-a, principalmente se houver suas iniciais. Se você reativar o código antigo e não souber por que ele foi desativado, adicione uma explicação completa para que, quando alguém (você, talvez) mais tarde quiser colocá-lo de volta do jeito que era, saberá que está em um loop infinito de desenvolvimento e saber como sair disso.
RalphChapin
5

Outra boa regra geral é que todo método deve fazer apenas uma coisa.

Se você dividir o processamento do que você está tentando implementar em pequenas etapas discretas e codificá-las como métodos, quando chegar a hora de re-fatorar, você descobrirá que a única refatoração que faz algum sentido é alterar o ordem para que os métodos sejam chamados ou que deixem alguns métodos fora do caminho de execução.

Além disso, como seus métodos são discretos, você é livre para redimensionar qualquer método único, desde que o valor retornado seja o que deveria ser, nenhum dos outros códigos será o mais sábio que uma alteração foi feita.

Isso define o cenário para você executar melhorias incrementais no seu código ao longo do tempo, simplesmente otimizando um método aqui e ali. A lógica geral não muda, apenas os detalhes de uma etapa específica.

Se você seguir esse método de métodos para classes, onde nas suas classes representa ou representa apenas um único objeto, você descobrirá que, assim como nos métodos, sua refatoração se torna mais apenas uma reorganização da ordem em que suas classes são construídas e usadas e menos sobre realmente alterar a lógica de detalhes.

Você sabe que atingiu o ponto ideal quando a especificação do programa muda drasticamente e repentinamente, mas você pode acomodar quase todas as alterações necessárias simplesmente modificando os relacionamentos entre seus objetos - sem alterar sua implementação interna! Parece que você de repente adquire o nirvana!

Boa sorte e que todo o seu código esteja livre de bugs!

Rodney

rpbarbati
fonte
3

O teste de unidade do código pode ajudar.

Edson Medina
fonte
2

É possível que você esteja escrevendo interfaces como se estivesse adotando uma abordagem de cima para baixo para resolver um problema, mas depois implementando de baixo para cima? Nesse caso, acho que essa é a incompatibilidade lógica que está causando problemas.

Com base no que você está descrevendo, pode ser melhor resolver o problema para que você possa pensar em pelo menos uma coisa que precisa fazer e implementar exatamente isso. Pense em outra coisa que você precisa fazer e implemente exatamente isso. Continue desenvolvendo sua solução para escrever primeiro os fundamentos absolutos, depois os blocos de construção que ficam sobre eles e assim sucessivamente até que você tenha a solução real. Costumo achar que a solução completa, mesmo para problemas difíceis, tende a surgir de você e de repente saltar ao seguir esse tipo de abordagem.

Se você mantiver os blocos de construção intermediários logicamente focados e deliberadamente manter cada segmento de código fechado e limitado, a quantidade de refatoração necessária será sempre pequena e isolada.

Tommy
fonte
É isso que estou fazendo, acho. Costumo escrever o esboço do que quero fazer - como no padrão de design do método de modelo, por exemplo. Então eu implemento esses métodos. Quando chego aos detalhes, às vezes descubro que algo não estava certo no modelo original.
Kirby
1

... é tentador fazer uma pequena atualização no meu design, em vez de apagar o que já escrevi e escrevê-lo da maneira que deveria ser .

Nada é suposto. A única coisa suposta é que:

  1. você pode fazer qualquer coisa que você quer
  2. sua vida útil / tempo de trabalho é limitada e você só pode alcançar um número limitado de coisas.

O que você quer? Um deles terminou um projeto absolutamente perfeito de super-duper-excelente-código-limpo, ou três projetos finalizados, apenas 70% de elegibilidade de código em comparação com o anterior, mas três vezes 95% do ponto de vista do usuário? O que será mais útil para o mundo, para o seu povo, para a sua missão?

O que você quer?

Obviamente, a longo prazo, pode valer a pena refatorar (reduz o tempo de montagem etc.), mas apenas em muito tempo. Nós, programadores, muitas vezes somos tentados a refatorar e otimizar muito antes do necessário. Costumamos refatorar um código que não é mais desenvolvido, o que significa perda de tempo.

Eu uso minha própria regra de ouro de 2-3. No primeiro uso de um código específico, eu simplesmente o atrevo o mais rápido possível. Quase nunca vale a pena pensar em um uso mais geral, porque você ainda não tem informações suficientes sobre quais casos de uso podem surgir. E também, essa parte do código pode nunca ser usada novamente. Quando o código é necessário na segunda vez, tento tornar o primeiro código mais geral para aplicar a esse caso também, ou opto por copiá-lo (mas não gosto disso). Com o terceiro uso, sinto que tenho informações suficientes para refatorar e, como essa parte do código parece ser realmente usada, sinto que vale a pena.

Tomas
fonte
0

O que resulta é uma bagunça de código que precisa ser refatorada.

Apenas explique o problema até entender. Em seguida, faça uma implementação nova e correta depois de conhecer sua forma.

Para responder à sua pergunta em termos mais gerais: Lembre-se de que as alterações necessárias geralmente causam menos ondulações / novos testes se feitas mais cedo ou mais tarde.

justin
fonte