Técnicas para re-fatorar o lixo e manter a sanidade? [duplicado]

38

Então eu estou sentado em uma tigela bacana de espaguete c # e preciso adicionar algo ou remover algo ... mas eu tenho desafios em todos os lugares de funções transmitindo argumentos que não fazem sentido, alguém que não entende estruturas de dados que abusam de strings, variáveis redundantes, alguns comentários são audições em vermelho, internacionalização em um nível por toda saída, SQL não usa nenhum tipo de DBAL, conexões de banco de dados são deixadas abertas em todos os lugares ...

Existe alguma ferramenta ou técnica que eu possa usar para pelo menos rastrear a "integridade funcional" do código (ou seja, minhas "melhorias" não o quebram), ou um recurso online com "padrões ruins" comuns que explica uma boa maneira de fazer a transição do código? Estou basicamente procurando um guia sobre como transformar palha em ouro.

Veja alguns exemplos da mesma função de 500 linhas:

protected void DoSave(bool cIsPostBack) {
  //ALWAYS  a cPostBack
  cIsPostBack = true;
  SetPostBack("1");
  string inCreate ="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
  parseValues = new string []{"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""};


  if (!cIsPostBack) { //.......
  //....
  //....
  if (!cIsPostBack) {

  } else {

  }
  //....  
  //....
  strHPhone = StringFormat(s1.Trim());
  s1 = parseValues[18].Replace(encStr," ");
  strWPhone = StringFormat(s1.Trim());
  s1 = parseValues[11].Replace(encStr," ");
  strWExt = StringFormat(s1.Trim());
  s1 = parseValues[21].Replace(encStr," ");
  strMPhone = StringFormat(s1.Trim());
  s1 = parseValues[19].Replace(encStr," ");
  //(hundreds of lines of this)
  //....
  //....
  SQL = "...... lots of SQL .... ";

  SqlCommand curCommand;

  curCommand = new SqlCommand();
  curCommand.Connection = conn1;

  curCommand.CommandText = SQL;
  try {
    curCommand.ExecuteNonQuery(); 
  } catch {}
  //....
}

Eu nunca tive que refatorar algo assim antes, e eu quero saber se há algo como um guia ou uma base de conhecimento sobre como fazer esse tipo de coisa, encontrar padrões ruins comuns e oferecer as melhores soluções para repará-los. Eu não quero apenas tirar isso da órbita,

    
por Incognito 08.04.2011 / 15:54
fonte

11 respostas

30

Existem três livros que eu recomendaria:

Todos esses livros enfatizam a colocação de um "ninho de segurança" antes de se envolver na refatoração quando possível. Isso significa ter testes que garantem que você não quebra a intenção original do código que está refatorando.

E sempre faça uma refatoração de cada vez .

    
por 08.04.2011 / 16:09
fonte
11

Isso é exatamente o que Martin Fowler fala em seu livro Refatorando .

Resumo básico:

  • Testes de unidade! Primeiro, você deseja estabelecer testes para o código existente. Descubra quais são as entradas e saídas esperadas e teste-as. Não teste para o código. Teste para a especificação - você não quer reproduzir erros.
  • Refatorar bits de cada vez, mantendo os testes passando conforme você avança.
  • Lembre-se de que, se você não tiver testes ou para grandes partes do código, uma reescrita poderá ser a escolha mais eficiente.

Esta entrevista com Martin Fowler sobre os tópicos do livro lança muita luz sobre o assunto (em testes unitários, payoffs, encontrar bugs por meio de refatoração, refatoração versus reescrita).

Tenha em mente que padrões ruins são ruins por um motivo - é uma solução ruim para o problema. Isso significa que, mesmo que você tenha visto o mesmo tipo de código ruim, isso não significa que o problema é o mesmo, e a melhor solução provavelmente é diferente para cada caso.

    
por 08.04.2011 / 16:06
fonte
6

Na minha experiência anterior, definir áreas de funcionalidade de forma iterativa e extrair o código relevante em métodos / funções será a maneira mais rápida de começar. Você pode então extrair código, colocar esse código em uma função e depois testar para confirmar que você não quebrou nada. Enxague e repita até que esteja pronto ou até que você tenha que adicionar uma nova funcionalidade. Refatorar iterativamente fornecerá mais flexibilidade, permitindo que você faça pausas ocasionais na refatoração, especialmente se você ainda precisar / quiser adicionar um novo código. Psicologicamente, uma abordagem iterativa proporcionará a satisfação de ver sua base de código mais ordenada, o que facilitará a conclusão dessa tarefa de refatoração.

    
por 15.12.2011 / 17:40
fonte
4

Parece que o que você quer é ter testes de unidade. Adicione casos de teste que cubram o comportamento existente e, ao refatorar, você pode confiar nos seus testes para alertá-lo sobre eventuais falhas. Faça isso em uma nova ramificação no seu controle de origem, para que os acidentes não se tornem catastróficos.

    
por 08.04.2011 / 15:57
fonte
4

Eu faria algo como o seguinte:

  • Envolva o máximo possível do seu código nas turmas, agrupando-o por funcionalidade, mas deixando-o intocado por enquanto. Isso permitirá que você faça uma triagem de seu código.
  • Crie uma camada de banco de dados usando o PDO.
  • Converta seu código para o padrão MVC, tomando cuidado especial para eliminar qualquer código PHP que esteja gerando desnecessariamente HTML e transferindo-o para a exibição. Seus controladores devem determinar qual modelo e qual visualização carregar, e seus modelos devem conter todo o resto.
  • Refatore suas classes restantes, uma por uma. Enfrente as classes mais difundidas primeiro. Procure classes que façam várias coisas e divida-as. Livre-se do código repetido. Faça métodos de responsabilidade única.
  • Adicione testes de unidade à medida que avança. Isso tornará seu código mais estável no longo prazo. Se você precisar refatorar novamente no futuro, você terá um contrato que especifica como o código deve ser executado. PHPUnit é um framework de teste que você pode usar, mas há outros também.
por 15.12.2011 / 18:02
fonte
3

Engenharia reversa controlada pelo teste.

Escreva testes unitários para o "antes".

Refatorar.

Certifique-se de que os testes sejam executados depois.

Escolha pequenos pedaços que possam ser claramente identificados como pertencentes a um único objetivo ou componente conceitual.

    
por 08.04.2011 / 16:07
fonte
3

Eu começaria cobrindo o máximo possível do seu código com testes automatizados. Pode ser entediante e tedioso, mas permite capturar o comportamento atual do seu sistema. Então, conforme você iterativamente limpa as coisas e reescreve / refaz partes de sua base de código, você pode se sentir mais confiante em não introduzir uma tonelada de regressões. Você também poderá introduzir testes mais refinados que antes. Isso sempre me ajudou no passado.

    
por 15.12.2011 / 18:05
fonte
1

O Yous definitivamente deveria começar a escrever testes unitários, como outros já mencionaram. Infelizmente, porém, esse código claramente precisa ser eliminado da existência. Agora, se está funcionando bem do jeito que está, talvez você não precise, mas qualquer manutenção rapidamente se tornará muito cara. Este código parece ser basicamente a definição de inatingível. Mas, com um design melhor, você provavelmente pode passar por uma reescrita muito mais rápido do que a pessoa que tropeçou nela (eu sei que os caubóis podem ser programadores rápidos, mas esse programador não era caubói ... acho que ele poderia literalmente ser uma vaca) .

    
por 08.04.2011 / 16:39
fonte
1

Se for um aplicativo da web, você pode testar a "saída" com um pouco de criatividade - use algo como selênio no lado do navegador para garantir que os bits da interface ainda funcionem e, em seguida, verifique o banco de dados no verso confirme se sua atualização foi aprovada. Sua caixa preta é grande, mas você pode pelo menos sanidade verificar suas alterações automaticamente e repetitivamente.

    
por 08.04.2011 / 16:43
fonte
1

Como outros disseram, sua principal arma aqui é o teste de unidade. Independentemente de qualquer outra coisa que você faça, você precisará disso.

Quanto às ferramentas para ajudar na refatoração, elas existem, mas não farão consertos em grande escala para você. Coisas como Resharper ajudarão a mover métodos, renomear variáveis, extrair interfaces, etc., mas eu suspeito que você terá que fazer uma muita refatoração manual também.

    
por 08.04.2011 / 18:39
fonte
1

Não é isso que refatoração é. A refatoração está quebrando um pedaço de código em suas partes componentes (fatores) de uma maneira que melhora a reutilização e a legibilidade do código.

Para melhorar um código terrível, é reescrito . Então a questão é como você vai reescrever toda uma aplicação de código ruim. A resposta é que você começa do zero. Reescrever aos poucos é muito mais difícil e, a longo prazo, levará mais tempo para ser feito corretamente.

    
por 15.12.2011 / 17:41
fonte