Alterei uma assinatura de método e agora tenho mais de 25.000 erros. E agora?

166

Eu iniciei um novo trabalho recentemente, onde estou trabalhando em um aplicativo muito grande (15 M loc). No meu trabalho anterior, tínhamos um aplicativo similarmente grande, mas (para o melhor ou para o pior) usamos o OSGi, o que significava que o aplicativo era dividido em muitos microsserviços que poderiam ser alterados, compilados e implantados independentemente. O novo aplicativo é apenas uma grande base de código, com talvez alguns .dlls.

Então eu preciso mudar a interface dessa classe, porque é o que meu chefe me pediu para fazer. Inicialmente eles escreveram com algumas suposições que não generalizaram muito bem, e por um tempo eles têm evitado o problema da refatoração porque ela é tão strongmente acoplada. Eu mudei a interface e agora existem mais de 25.000 erros. Alguns dos erros estão em classes com nomes importantes, como "XYZPriceCalculator", que reaaally não deve quebrar. Mas não consigo iniciar o aplicativo para verificar se está funcionando até que todos os erros sejam resolvidos. E muitos dos testes de unidade fazem referência direta a essa interface ou são acoplados a classes base que fazem referência a essa interface, portanto, apenas corrigi-las é uma tarefa bastante grande por si só. Além disso, eu realmente não sei como todas essas peças se encaixam, então mesmo que eu pudesse começar, eu realmente não sei como seria se as coisas fossem quebradas.

Eu nunca enfrentei um problema como esse no meu último trabalho. O que eu faço?

    
por user788497 04.11.2016 / 03:01
fonte

9 respostas

349

25000 erros basicamente significam "não toque nisso". Mude de volta. Crie uma nova classe que tenha a interface desejada e mova lentamente os consumidores da classe para a nova. Dependendo do idioma, você pode marcar a classe antiga como obsoleta, o que pode causar todos os tipos de avisos do compilador, mas não interromperá sua compilação.

Infelizmente, essas coisas acontecem em bases de código mais antigas. Não há muito que você possa fazer a respeito, exceto, lentamente, melhorar as coisas. Quando você cria as novas classes, certifique-se de testá-las e criá-las corretamente usando os princípios do SOLID, para que sejam mais fáceis de alterar no futuro.

    
por 04.11.2016 / 03:35
fonte
80

Dividir e conquistar com refatorações

Geralmente, dividir a alteração que você precisa fazer em etapas menores pode ajudar, pois é possível executar a maioria das etapas menores de uma maneira que não interrompa o software. As ferramentas de refatoração ajudam muito com essas tarefas.

Divide

Primeiro, identifique as menores mudanças possíveis (em termos de mudanças lógicas, não em termos de LoC alterado) que somam a mudança que você deseja alcançar. Especialmente, tente isolar etapas que são refatorações puras e podem ser executadas por ferramentas.

Conquistar

Para casos complicados como o seu, pode fazer sentido realizar uma pequena refatoração de cada vez e deixar o problema em repouso, para que todos os sistemas de integração contínua possam verificar a alteração e talvez a equipe de testes também. Isso valida as etapas que você faz.

Para realizar uma refatoração específica, você precisa de suporte de ferramenta para um caso em que você tenha 25.000 sites de chamada do método que deseja alterar. Talvez procure-e-substitua funciona também, mas para um caso tão crítico, eu ficaria com medo por isso.

Exemplo

Em C #, por exemplo, é possível usar o Resharper para mude a assinatura de um método. Se a alteração for simples o suficiente, por ex. adicionando um novo parâmetro, , você pode especificar qual valor deve ser usado em sites de chamada que, de outra forma, teriam um erro de compilação.

Você está imediatamente em uma base de código livre de erros e pode executar todos os testes de unidade, que serão aprovados, porque era apenas uma refatoração.

Uma vez que a assinatura do método parece boa, você pode ir e substituir os valores que o Resharper adicionou como argumentos para o parâmetro introduzido recentemente. Isso não é mais uma refatoração, mas você tem uma base de código livre de erros e pode executar os testes depois de cada linha que você muda.

Às vezes isso não funciona

Esta é uma abordagem muito útil para casos como o seu, onde você tem muitos sites de chamadas. E você tem software funcionando agora, então pode ser possível fazer pequenos passos de refatoração para mudar um pouco a assinatura, depois fazer outra.

Infelizmente, isso não funcionará se a alteração da assinatura for muito complexa e não puder ser dividida em alterações menores. Mas isso é raro; dividir o problema em problemas menores geralmente mostra que é possível.

    
por 04.11.2016 / 08:37
fonte
36

Esclareça sua tarefa com seu chefe para ajudá-lo a entender o problema e suas necessidades como desenvolvedor profissional de software.

Se você faz parte de uma equipe, procure o desenvolvedor líder e peça conselho.

Boa sorte.

    
por 04.11.2016 / 08:53
fonte
28

Não toque nele. Não cometa nada.

Em vez disso, sente-se na sua cadeira e grite "Heeeeelp !!!!!" tão alto quanto você puder.

Bem, não exatamente assim, mas peça conselhos a qualquer um de seus colegas sêniores. Se você tiver 25.000 erros, não corrigirá os erros, corrigirá o que causou os erros. E um colega sênior deve ser capaz de aconselhá-lo sobre como fazer a mudança que seu chefe quer sem os 25.000 erros envolvidos. Existem várias maneiras de fazer isso, mas o que é um bom caminho depende da sua situação específica.

E pode ser que o chefe tenha dito a seus colegas mais antigos que fizessem a mesma mudança e eles disseram "não". Porque eles sabiam o que aconteceria. É por isso que você recebeu o emprego.

    
por 04.11.2016 / 10:02
fonte
22

As APIs entrincheiradas não podem ser simplesmente alteradas. Se você realmente precisar alterá-las, anote e / ou as documente como obsoletas (por qualquer meio que a linguagem permitir) e documente qual API deve ser usada. A API antiga pode ser eliminada lentamente ... talvez muito lentamente, dependendo do seu orçamento de tempo para refatoração.

    
por 04.11.2016 / 03:29
fonte
10

Avaliar

Avalie se essa alteração é necessária ou se você pode adicionar um novo método e desaprovar o outro.

Encaminhar

Se a mudança for necessária; então um plano de migração é necessário.

O primeiro passo é introduzir o novo método e fazer com que o método antigo massageie seus argumentos para que ele possa chamar o novo. Isso pode exigir codificação rígida de algumas coisas; tudo bem.

Este é um ponto de confirmação: verifique se todos os testes foram aprovados, confirmados, enviados.

Migrar

O trabalho ocupado está migrando todos os chamadores do método antigo para o novo. Felizmente isso pode ser feito gradualmente graças ao forwarder.

Então vá em frente; não hesite em usar ferramentas para ajudar ( sed é o mais básico, existem outros).

Marque o método antigo como obsoleto (com uma sugestão de mudar para o novo método); ele ajudará você a identificar se esqueceu alguma coisa e ajudará se um colega de trabalho apresentar uma chamada para o método antigo enquanto você estiver trabalhando nisso.

Este é um ponto de commit (ou talvez vários commit points): verifique se todos os testes foram aprovados, commit, push.

Remover

Após algum tempo (talvez um dia), basta remover o método antigo.

    
por 04.11.2016 / 10:46
fonte
8

Se a alteração na assinatura do método for meramente uma alteração de nome, a solução simples é usar ferramentas para automatizar a alteração nas 25.000 classes que fazem referência ao método em questão.

Eu suponho que você tenha simplesmente editado o código manualmente, o que deu origem a todos os erros. Eu também suponho que você esteja familiarizado com o Java (ver sua referência ao OSGi), portanto, no Eclipse (não sei qual ambiente de programação você usa, mas outros ambientes têm ferramentas de refatoração semelhantes) você pode usar "Refatoração - > "para atualizar todas as referências ao método, o que deve deixar você sem erros.

Caso você esteja fazendo outras alterações na assinatura do método do que simplesmente renomeando (alterando o número ou os tipos de parâmetros), é possível usar "Refatoração - > Alterar assinatura do método". No entanto, é provável que você tenha que ser mais cuidadoso, como as outras respostas sugerem. Além disso, independentemente do tipo de alteração, ainda pode ser uma tarefa bastante cometer todas essas alterações em uma base de código ocupada.

    
por 04.11.2016 / 10:16
fonte
6

Aqui minha contribuição.

I started a new job recently where I am working on a very large application (15M lines of code).

Você provavelmente não está familiarizado com o projeto e seus "recursos". Antes de digitar uma única linha de código, é importante estar familiarizado com o projeto. Portanto, reverta suas alterações e comece analisando o código . (Pelo menos o afetado)

Entender a solução existente oferece uma perspectiva melhor de onde você está se metendo. Contextualize a solução e sua importância.

Como @Greg apontou, você deve ser capaz de testar o código existente para ter uma referência válida para comparar com (testes de regressão). Sua solução deve ser capaz de gerar os mesmos resultados do que o existente. Neste estágio, você não se importa se os resultados estão certos ou não . O primeiro objetivo é refatorar, não corrigir bugs. Se a solução existente disser "2 + 2 = 42", sua solução também deve. Se não lançar exceções, o seu também não deve. Se ele retorna nulos, o seu deve retornar nulos também. E assim por diante. Caso contrário, você estará comprometendo 25k linhas de código.

Isso é por causa da retro-compatibilidade.

Por quê? Porque agora, é a sua garantia única de um refatorador de sucesso.

And many of the unit tests either directly reference that interface, or are coupled to base classes which reference that interface.

Uma maneira de garantir a retro compatibilidade é urgentemente necessária para você. Então, aqui está seu primeiro desafio. Isole o componente para testes unitários.

Tenha em mente que essas 25 mil linhas de código foram feitas assumindo os possíveis resultados do código existente. Se você não quebrar esta parte do contrato, então você está a meio caminho da solução final. Se você faz, bem: pode a força estar com você

Depois de ter projetado e implementado o novo "contrato", substitua o antigo. Deprecá-lo ou retirá-lo.

Eu sugeri que deixar os bugs sozinhos por causa da refatoração e correção de bugs são tarefas diferentes. Se você tentar levá-los adiante, você pode falhar em ambos. Você pode achar que encontrou bugs, no entanto, eles podem ser "recursos". Então, deixe-os sozinhos (por um minuto).

25 mil linhas de código parecem-me suficientes para me concentrar em apenas uma tarefa.

Quando sua primeira tarefa estiver concluída. Exponha esses erros / recursos ao seu chefe.

Finalmente, como o @Stephen disse:

There's not much you can do about it except slowly make things better. When you create the new classes, make sure you properly test them and create them using SOLID principles so they will be easier to change in the future

    
por 05.11.2016 / 17:22
fonte
5

Teste-o.

Todo mundo está recomendando como refatorar, então há pouco impacto. Mas com muitos erros, mesmo que você consiga refatorar com apenas 10 linhas de código (você provavelmente pode), então você impactou 25.000 fluxos de código , mesmo que você não precise reescrever eles.

Então, a próxima coisa a fazer é garantir que sua suíte de testes de regressão passe com cores vibrantes. E se você não tiver um, então faça um que queira. Adicionar um conjunto abrangente de testes de regressão ao seu projeto monolítico soa chato, mas é uma boa maneira de aumentar a confiança nos candidatos a lançamentos, bem como liberá-los mais rapidamente se o conjunto for bem automatizado.

    
por 04.11.2016 / 22:17
fonte