ti-enxame.com

Quando um BIG Reescrever a resposta?

Basta ler o pergunta sobre as Grandes Reescrições e lembrei-me de uma pergunta que eu queria responder.

Eu tenho um projeto horrível passado para mim, escrito em Java antigo, usando o Struts 1.0, tabelas com relacionamentos inconsistentes ou nenhum relacionamento e até mesmo tabelas sem chaves ou campos primários que deveriam ser chaves primárias, mas não são únicas. De alguma forma, a maior parte do aplicativo "simplesmente funciona". A maioria das páginas é reutilizada (código colado e copiado) e codificada. Todo mundo que já trabalhou no projeto o amaldiçoou de uma forma ou de outra.

Agora, há muito que eu pensava em propor à gerência superior uma reescrita total desse aplicativo horrendo. Estou lentamente tentando me divertir, mas realmente sinto que isso merece alguns recursos dedicados para que isso aconteça. Depois de ler os artigos sobre grandes reescritas, estou pensando melhor. E isso não é bom quando quero convencer meus superiores a apoiar minha reescrita. (Eu trabalho em uma empresa bastante pequena para que a proposta tenha a possibilidade de ser aprovada)

TL; DR Quando uma grande reescrita é a resposta e quais argumentos você pode usar para apoiá-la?

288
Jonn

Desculpe, isso vai demorar, mas é baseado na experiência pessoal como arquiteto e desenvolvedor em vários projetos de reescrita.

As seguintes condições devem levar em consideração algum tipo de reescrita. Vou falar sobre como decidir qual fazer depois disso.

  • O tempo de aceleração do desenvolvedor é muito alto. Se demorar mais do que abaixo (por nível de experiência) para acelerar um novo desenvolvedor, o sistema precisará ser reprojetado. Por tempo de aceleração, quero dizer a quantidade de tempo antes que o novo desenvolvedor esteja pronto para fazer seu primeiro commit (em um pequeno recurso)
    • Recém saído da faculdade - 1,5 meses
    • Ainda verde, mas já trabalhou em outros projetos antes - 1 mês
    • Nível médio - 2 semanas
    • Experiente - 1 semana
    • Nível sênior - 1 dia
  • A implantação não pode ser automatizada, devido à complexidade da arquitetura existente
  • Até correções simples de erros demoram muito devido à complexidade do código existente
  • Novos recursos demoram muito e custam muito devido à interdependência da base de código (novos recursos não podem ser isolados e, portanto, afetam os recursos existentes)
  • O ciclo de teste formal leva muito tempo devido à interdependência da base de código existente.
  • Muitos casos de uso são executados em poucas telas. Isso causa problemas de treinamento para usuários e desenvolvedores.
  • A tecnologia em que o sistema atual está exigindo
    • É difícil encontrar desenvolvedores de qualidade com experiência na tecnologia
    • Foi descontinuado (não pode ser atualizado para suportar plataformas/recursos mais recentes)
    • Existe simplesmente uma tecnologia de nível superior muito mais expressiva disponível
    • O custo de manutenção da infraestrutura da tecnologia antiga é muito alto

Essas coisas são bastante evidentes. Quando decidir uma reescrita completa versus uma reconstrução incremental é mais subjetivo e, portanto, mais cobrado politicamente. O que posso dizer com convicção é que afirmar categoricamente que é nunca uma boa ideia está errada.

Se um sistema puder ser reprojetado de forma incremental e você tiver o apoio total do patrocínio do projeto para isso, deverá fazê-lo. Aqui está o problema, no entanto. Muitos sistemas não podem ser redesenhados de forma incremental. Aqui estão algumas das razões que encontrei que impedem isso (tanto técnica quanto política).

  • Técnico
    • O acoplamento dos componentes é tão alto que as alterações em um único componente não podem ser isoladas de outros componentes. A reformulação de um único componente resulta em uma cascata de alterações não apenas nos componentes adjacentes, mas indiretamente em todos os componentes.
    • A pilha de tecnologia é tão complicada que o design do estado futuro exige várias alterações na infraestrutura. Isso também seria necessário em uma reescrita completa, mas se for necessário em um novo design incremental, você perderá essa vantagem.
    • Redesenhar um componente resulta em uma reescrita completa desse componente, porque o design existente é tão fubar que não vale a pena salvar. Novamente, você perde a vantagem se for esse o caso.
  • Político
    • Os patrocinadores não podem entender que um novo design incremental requer um compromisso de longo prazo com o projeto. Inevitavelmente, a maioria das organizações perde o apetite pelo dreno contínuo do orçamento criado por um novo design incremental. Essa perda de apetite também é inevitável para uma reescrita, mas os patrocinadores estarão mais inclinados a continuar, porque não desejam dividir-se entre um novo sistema parcialmente completo e um sistema antigo parcialmente obsoleto.
    • Os usuários do sistema estão muito apegados às suas "telas atuais". Se for esse o caso, você não terá a licença para melhorar uma parte vital do sistema (o front-end). Um novo design permite contornar esse problema, pois eles começam com algo novo. Eles ainda vão insistir em obter "as mesmas telas", mas você tem um pouco mais de munição para empurrar de volta.

Lembre-se de que o custo total da reformulação incremental é sempre maior do que uma reescrita completa, mas o impacto na organização geralmente é menor. Na minha opinião, se você pode justificar uma reescrita e tiver desenvolvedores de superstar, faça-o.

Só faça isso se tiver certeza de que existe vontade política de fazê-lo até o fim. Isso significa a adesão de executivos e usuários finais. Sem ele, você irá falhar. Estou assumindo que é por isso que Joel diz que é uma má ideia. O acesso executivo e ao usuário final parece um unicórnio de duas cabeças para muitos arquitetos. Você precisa vendê-lo de forma agressiva e fazer campanha por sua continuação continuamente até que esteja completo. Isso é difícil, e você está falando em apostar em sua reputação em algo que alguns não desejam que seja bem-sucedido.

Algumas estratégias para o sucesso:

  • Se você, no entanto, não tente converter o código existente. Projete o sistema a partir do zero. Caso contrário, você está perdendo seu tempo. Eu nunca vi ou ouvi falar de um projeto de "conversão" que não acabou miseravelmente.
  • Migre os usuários para o novo sistema, uma equipe por vez. Identifique as equipes que sofrem mais com o sistema existente e migre-as primeiro. Que eles espalhem as boas novas de boca em boca. Dessa forma, seu novo sistema será vendido a partir de dentro.
  • Projete sua estrutura conforme necessário. Não comece com alguma estrutura que eu passei 6 meses construindo - que nunca viu código real.
  • Mantenha sua pilha de tecnologia o menor possível. Não projete demais. Você pode adicionar tecnologias conforme necessário, mas removê-las é difícil. Além disso, quanto mais camadas você tiver, mais trabalho será feito pelos desenvolvedores. Não torne difícil desde o início.
  • Envolva os usuários diretamente no processo de design, mas não permita que eles ditem como para fazer isso. Ganhe sua confiança, mostrando a eles que você pode dar o que eles querem melhor se você seguir os bons princípios de design.
328
Michael Meadows

Eu participei de duas grandes reescritas. Primeiro foi um pequeno projeto. O segundo foi o principal produto de uma empresa de software.

Existem várias armadilhas:

  • reescrições sempre levam mais tempo do que o esperado.
  • reescritas não têm efeitos/benefícios diretos para o cliente.
  • a capacidade dedicada à reescrita não é usada para dar suporte ao cliente.
  • você perderá a funcionalidade com uma reescrita, a menos que tenha 100% de documentação.

Reescritas raramente são a resposta real. Você pode refatorar grande parte do código sem perder nada e sem muito risco.

Reescrever pode ser a resposta se:

  • você está mudando para outro idioma ou plataforma.
  • você está alternando estruturas/componentes externos.
  • a base de código existente não pode mais ser mantida.

Mas eu recomendo fortemente a abordagem lenta usando refatoração. É menos arriscado e você mantém seus clientes felizes.

112
Toon Krijthe

É hora de reescrever quando:

O custo de reescrever o aplicativo + manter o aplicativo reescrito é menor que o custo de manutenção do sistema atual ao longo do tempo.

Alguns fatores que tornam a manutenção da atual mais cara:

  • O idioma é tão antigo que você precisa pagar às pessoas que sabem muito dinheiro para programar nele (COBOL).
  • (por experiência, infelizmente) O sistema está em uma arquitetura de hardware tão antiga que eles precisam vasculhar as peças Ebay e COLLECT para adicionar à máquina em que estão sendo executadas porque não são mais fabricadas. Isso é chamado de "suporte à vida útil do hardware" e é caro porque, à medida que as peças se tornam mais escassas, elas (podem) subir de preço ou acabarão (absolutamente).
  • Tornou-se tão complexo que o //Here be dragons. O comentário está em todo o seu código.
  • Você não pode escrever outros projetos e agregar novo valor à empresa, porque está sempre remendando essa fera feia.
74
Ryan Hayes

Se você precisar de uma alteração fundamental na arquitetura do projeto, é possivelmente hora de começar de novo.

Mesmo com isso, haverá potencialmente grandes faixas de código que ainda valem a pena ser reutilizadas em seu novo projeto.

Preste atenção ao aviso justo. Um projeto atual terá suas regras de negócios testadas e refinadas com inúmeras horas de uso real, algo que não será verdadeiro para um projeto iniciado do zero.

Duvido que um período de tempo ou sensação de intestino seja uma medida apropriada de uma medida tão drástica. Você deve ter claro, defensável e bem entendido razões para participar desse curso de ação.

17
Dan McGrath

Embora eu concorde com a resposta de Kramii e a opinião de Joel, há momentos em que é apropriado reescrever. Em aplicativos de longa duração (estou falando de 10 a 20 anos ou mais), a manutenção se torna cada vez mais cara ao longo do tempo. Isso ocorre porque o código se torna cada vez mais espaguete, já que a arquitetura original é sacrificada por patches de manutenção rápida. Além disso, os desenvolvedores de tecnologias mais antigas se tornam mais raros e mais caros. Finalmente, o hardware começa a envelhecer e fica cada vez mais difícil encontrar novos hardwares, sistemas operacionais, estruturas etc. para executar o aplicativo antigo. Além disso, as empresas evoluem e, muito provavelmente, um sistema antigo não atenderá às necessidades de negócios da organização, assim como um sistema totalmente novo.

Portanto, é necessário ponderar todo o custo de manutenção em andamento, bem como os benefícios potenciais de um novo sistema para os negócios, contra o custo de reescrever a coisa do zero. Seja muito pessimista em suas estimativas sobre o custo de uma reescrita. Quase sempre custa mais e leva mais tempo do que você imagina.

12
RationalGeek

Pare! Reescrever é quase nunca a resposta. Mais frequentemente, refatorar é uma aposta melhor.


Obviamente, existem momentos em que uma reescrita é justificada:

  • Você está mudando para uma nova plataforma na qual as ferramentas de migração não existem (ou não podem ser gravadas de maneira barata).
  • O aplicativo a ser reescrito é trivial.
  • O código-fonte do aplicativo original é perdido e a recuperação é mais cara que a reescrita.
  • A grande maioria das regras de negócios encapsuladas pelo aplicativo existente não se aplica mais.
  • Existem poucos usuários ativos do código existente.
  • Você tem o recurso (tempo, talento e ferramentas) para realizar a reescrita.
  • O aplicativo existente não pode ser executado em um ambiente de produção, por razões legais ou práticas.

Para entender por que recomendo refatorar em vez de reescrever, considere o que está envolvido em uma reescrita. Você deve:

  1. Entenda as nuances do que o aplicativo existente faz. Isso geralmente não é trivial quando você leva em consideração todas as regras sutis de negócios que ele encapsula, o ambiente (humano e técnico) em que opera e as vantagens e desvantagens da solução atual. Na maioria das vezes, o único local em que essas informações existem (se houver) é o código-fonte do aplicativo existente. É lamentável que uma das principais razões para a reescrita seja a dificuldade de entender e manter o código existente.

  2. Reproduza essa funcionalidade (ou uma versão atualizada dela) em um novo aplicativo testado e confiável. O código existente pode não ser entendido pelos desenvolvedores, mas geralmente é bem entendido pelos usuários. Pode não atender às necessidades atuais dos negócios, mas eles podem pelo menos dizer o que o aplicativo faz em várias circunstâncias.

As grandes vantagens da refatoração são as seguintes:

  • Você pode levar as coisas um pedacinho de cada vez.
  • Quaisquer alterações podem ser testadas no contexto do aplicativo em funcionamento existente.
  • Hipóteses sobre o funcionamento do código existente podem ser testadas fazendo pequenas alterações e observando o que acontece.
  • As alterações geralmente podem ser entregues aos usuários em fases, e não todas de uma vez.
  • Aprender nos estágios iniciais da refatoração pode informar os estágios posteriores da refatoração.
  • Se você abandonar o processo no meio do caminho, ainda haverá benefícios em termos de uma base de código mais limpa (em oposição a uma reescrita que deve ser concluída para oferecer quaisquer benefícios ao usuário ou desenvolvedores).

Lembre-se também de que, se você reescrever, é garantido que você introduzirá muitos novos bugs e bagunça na nova base de código.

11
Kramii

Este gráfico pode ajudar, é uma função da qualidade da base de código e do valor comercial do aplicativo:

enter image description here

O gráfico pretende ser um guia sobre quando uma reengenharia de software legado é justificada e quando não é. Por exemplo, se o software tiver alto valor comercial e a qualidade do código for ruim, uma reengenharia será justificada.

10
Tulains Córdova

Acho que estou na única situação na minha carreira em que a grande reescrita é a resposta:

Fusão da empresa, enorme sobreposição na funcionalidade dos sistemas. Muitos, muitos sistemas foram mesclados e aposentados, e outros ainda estão em processo.

Eu herdei um sistema da outra empresa que ainda vive. Ele possui uma enorme base de códigos, que costumava suportar vários departamentos muito semelhantes aos nossos, mas com um design e estruturas completamente diferentes. Resta apenas um setor comercial, que ganha dinheiro suficiente para manter essa coisa viva em um estado de zumbi. Toda a antiga experiência se foi, não há documentação. A carga de suporte é alta, com falhas a cada semana. Ele não foi incorporado aos sistemas de nossas empresas, porque nossa empresa nunca deu suporte a esse setor específico dos negócios, portanto, não temos a funcionalidade ou o conhecimento.

Parece que este é o único caso em que a reescrita é necessária. Parece que vou ter que descobrir esse gigante, extrair os bits de funcionalidade dedicados a esse negócio e reescrever as partes que precisam ser adicionadas aos nossos sistemas existentes. Feito isso, nossos sistemas existentes podem apoiar esse novo setor, e essa fera pode ser eliminada de sua miséria. Caso contrário, vou perder minha sanidade.

8
Jay

Trabalhei para uma pequena empresa de software que tinha alguns aplicativos do DOS que foram atualizados para lidar com o Y2K, reescritos como um aplicativo de 16 bits do Windows e depois totalmente reescritos como um aplicativo de 32 bits com um recurso 'pequeno' adicional (utilizado apenas por um cliente) que impactou toda a estrutura.

Mover o código de 16 bits para 32 poderia ter sido feito em um mês por uma pessoa, mas NOOOOOOOOO, tivemos que reescrevê-lo para tornar o Sooooooooo muito melhor. Essa coisa poderia ser adaptada para outras indústrias, teria especificações completas e código psuedo antes mesmo de começar. As especificações foram criadas, mas demorou tanto tempo que nem houve tempo para escrever o código real. Foi lançado tarde, com mais bugs do que o de 16 bits 'iniciado' (foi na v.3.0 e, finalmente, ao ponto em que quase chegamos a uma semana sem que alguém relatasse um novo bug).

Você pensaria que reescrever o mesmo aplicativo de 3 a 4 vezes traria algumas melhorias, mas não acho que um front-end da GUI possa ser justificado tanto assim.

Este foi meu primeiro trabalho em TI como chefe de suporte técnico. Eu deveria escrever um livro sobre como não desenvolver software para distribuição. Obviamente, cometemos muitos erros, mas o fato de continuarmos reescrevendo aplicativos aumentou a incompetência.

7
JeffO

Eu tive um caso muito parecido com o seu, mas o código nem estava usando Struts. Em vez disso, o que fiz foi direcionar as áreas que eram particularmente ruins e causar muitos problemas. Essa abordagem direcionada nos permitiu melhorar cada vez mais.

Durante um período de 2 anos, trabalhamos na refatoração de pedaços e peças juntamente com o trabalho de aprimoramento. Sempre trabalhamos uma tarefa de 'proteção' em um plano de projeto. Ao focar nas áreas específicas que não funcionaram bem, obtivemos o máximo de retorno. O material que funcionou deixamos em paz. Também crítico é que este trabalho foi realizado no curso do desenvolvimento normal e lançado. O problema de uma grande reescrita é que você sai por um ano ou mais e, quando volta, tudo muda de qualquer maneira, e alguns dos erros desagradáveis ​​são suavizados e você perde seu ROI.

Nós nunca reescrevemos a coisa toda. No entanto, paramos de usar essa plataforma para novos trabalhos e lançamos uma nova plataforma para um grande projeto novo. Isso foi aprovado e entregamos um ótimo produto em um período de tempo razoável.

5
Bill Leeper

Então, aqui estou eu sentado na minha mesa, comecei a reescrever o código para essa bagunça absoluta de um grande arquivo aspx, o banco de dados por trás dele, e a substituição da interface do MS Access para o MsSQL.

Este programa asp está cheio de coisas como

  • include(close.aspx) que possui uma linha de código que fecha a última conexão de banco de dados aberta.
  • Código legado comentado aleatoriamente
  • Sem consideração pela segurança
  • Código de espaguete, milhares de linhas. Tudo em um arquivo.
  • Funções e variáveis ​​sem significado claro por trás de seus nomes

Se precisarmos fazer uma pequena alteração, é como jogar cinco jogos simultâneos de kal-toh no modo pesadelo.

Fui contratado para replicar a funcionalidade e criar um produto que pudesse ser personalizável e vendável para outras pessoas na indústria. O problema é que essa coisa foi escrita nos últimos 10 anos para preencher todas as necessidades de negócios (bem, eu diria cerca de cinco ou seis sigma delas).

Se não quiséssemos vender o produto, eles provavelmente não precisariam ser reescritos, pois fazem a maior parte do que desejam - talvez não com elegância, mas não era prudente gastar o dinheiro em fazer o código Nice 'fazer a mesma coisa'.

5
Incognito

A solução existente não é dimensionada.

Estou olhando para você, MS Access.

4
user21007

Joel Spolsky tem um excelente artigo sobre isso: Coisas que você nunca deve fazer, parte I

Do título que você pode dizer, é meio unilateral (ele fala sobre por que você nunca deve lançar código) IMO, há muita verdade, recentemente vi um vídeo do canal9 no 25º aniversário do Excel em que alguns desenvolvedores disseram como ainda hoje, se você visse a fonte, verificaria a revisão e acabaria voltando ao código usado pelo Excel que foi escrito há 20 anos.

Você não pode ter 100% de certeza (quando até o Netscape comete erros (do artigo de Joels)), [~ # ~] i [~ # ~] parecia que o artigo de Joel foi enviado por Deus, porque eu posso ser pessimista e adorar jogar código pensando que sempre posso escrever melhor uma segunda vez, mas só agora percebi que isso apenas custa um lote .

Para dar uma resposta concreta, eu diria apenas que você precisa fazer uma análise completa do custo versus valor .

Meu mundo real: um aplicativo silverlight que estou desenvolvendo a v0.6 até agora tem uma bagunça de chamadas assíncronas que tornam o código tão complicado. Desde que descobri Extensões reativas nesta semana, eu realmente quero reescrever a maior parte do código, mas agora o que digo ao meu cliente? O programa funciona perfeitamente bem (com alguns vazamentos de memória), mas eles não se importam? Não posso dizer a eles: Oh, estou demorando mais 2-3 semanas porque quero refazer alguma coisa. No entanto, estou indo ramificar o código e reescrever /brincar com ele no meu grátis hora.

Apenas meus 2 centavos ok !?

4
gideon

Existe a piada clássica sobre "se eu estivesse indo para o X, não começaria daqui".

Peguei um emprego uma vez, onde a principal motivação do empregador era trazer talentos a bordo para lançar uma reescrita há muito esperada de um aplicativo crítico para os negócios. A pergunta que não fiz foi: por que você acabou nessa situação em primeiro lugar? Deveria ter sido uma bandeira vermelha, se a causa foi

  • muita pressão para adicionar funcionalidade para manter e refatorar gradualmente a fera,

  • pouca capacidade no departamento,

  • muito pouco comprometimento dos clientes ou da gerência para trabalho incremental,

ou seja o que for, e isso causa apodrecimento até o problema atingir um nível intolerável.

Então, eu vou concordar com Joel no sentido de que uma reescrita maciça é provavelmente uma péssima idéia - a menos que você tenha evidências firmes de que todas as razões subjacentes às quais uma reescrita principal parece tão necessária foram tratadas , é provável que você repita o problema no devido tempo.

2
Julia Hayward

É a resposta quando a reescrita permite que a organização busque uma estratégia que ofereça uma vantagem competitiva ou que atenda melhor seus clientes de uma maneira que a arquitetura atual não pode acomodar.

Em vez disso, as reescritas geralmente acontecem para aliviar as preocupações de gerenciamento:

  • tudo deve estar no .NET,
  • nossos desenvolvedores dizem que nosso código é péssimo,
  • estamos ficando para trás tecnicamente,
  • não conseguiremos encontrar recursos para dar suporte ao nosso sistema ou, muitas vezes,
  • faz dez anos, então é hora.

A maioria dessas preocupações não se concretiza e, se o fizessem, poderiam ser tratadas. Esse último, no entanto, é o pior. É essencialmente: não temos um motivo.

Sim, como o carro, um sistema começará a mostrar sinais de desgaste. Isso pode ser aliviado pela manutenção de rotina. Você sabe o que eles dizem sobre como um pouco de manutenção preventiva é muito útil. Como investimento, a manutenção de rotina (ou seja, refatoração e padronização) quase sempre tem um custo menor do que uma reescrita.

No entanto, precisamos antecipar que uma reescrita será necessária. Defina datas e planeje-o provisoriamente, mas à medida que a data se aproxima mais, é possível realizar outras metas estratégicas até que você tenha um motivo convincente como ...

Nos últimos anos, perdemos a oportunidade de ganhar grandes contas, porque não podíamos acomodar suas necessidades em tempo hábil ou caro. Nosso sistema será reescrito usando uma arquitetura extensível que permita que as personalizações sejam conectadas (e não codificadas como fazemos atualmente). Isso diminuirá drasticamente o tempo e o custo de acomodar clientes com necessidades especiais. Ganharemos mais contas e atenderemos melhor às necessidades de nossos clientes atuais.

2
Mario T. Lanza

Eu acho que o principal motivo que justifica as reescritas são as mudanças na plataforma. Por exemplo, se você tiver um aplicativo GUI da área de trabalho do Windows e o proprietário da empresa decidir que deseja que a próxima versão seja um aplicativo baseado na Web. Embora nem sempre, na minha experiência na maioria das vezes, isso exigirá uma reescrita, a menos que os desenvolvedores originais escrevam código muito modular e reutilizável (dificilmente acontece).

2
Craig

De acordo com Joel, grandes reescritas são o pior erro estratégico único que uma empresa pode cometer:

Coisas que você nunca deve fazer, parte I

... É importante lembrar que, quando você começa do zero, não há absolutamente nenhuma razão para acreditar que fará um trabalho melhor do que o fez a primeira vez. Primeiro de tudo, você provavelmente nem tem a mesma equipe de programação que trabalhou na versão um, então na verdade você não tem "mais experiência". Você apenas cometerá a maioria dos erros antigos novamente e apresentará alguns problemas novos que não estavam na versão original.

O mantra antigo construa um para jogar fora é perigoso quando aplicado a aplicações comerciais em larga escala. Se você estiver escrevendo código experimentalmente, convém criar a função que você escreveu na semana passada, quando pensar em um algoritmo melhor. Isso é bom. Você pode refatorar uma classe para facilitar o uso. Tudo bem também. Mas jogar fora todo o programa é uma loucura perigosa, e se a Netscape realmente tivesse alguma supervisão de um adulto com experiência na indústria de software, eles talvez não tivessem atingido tanto o pé.

2
user3287

Nunca, refatorar sempre - a verdade é que se o código foi escrito por você - você não poderá fazer melhor.

A menos que você queira mudar a tecnologia, o código não possui nenhuma estrutura (eu o vi há muito tempo em alguns sites PHP, o autor apenas copia/cola spahgetti em vez de include/class/function) ou você assumiu algo de outra pessoa que está muito mal escrita.

Tudo deve ser projetado como uma caixa preta. API simples e modular, o que há dentro ... isso é menos importante :) Se você tem espaguete, talvez seja possível fechá-lo dentro de uma caixa preta, para que não contamine um bom código.

2
Slawek

Ao mudar para uma tecnologia completamente nova, é necessário fornecer a funcionalidade desejada.

"Completamente novo": se você planeja reescrever, mas usa a mesma plataforma, a refatoração e a reestruturação criteriosa são quase certamente a melhor solução. "Plataforma", como usada aqui, é um tanto vaga - considere incluir linguagem e talvez o sistema operacional (estendendo-se do Linux ao Windows ou vice-versa), mas provavelmente não a estrutura (por exemplo, substituindo o Struts pelo Spring).

"Necessário para fornecer a funcionalidade desejada": por volta de 2000, iniciei um projeto para reescrever um componente principal do servidor em Java do C++ para ativar o encadeamento pronto para uso, um cache de objetos, e transações controladas pelo cliente.Na época, havia várias bibliotecas de encadeamento para C++ que precisaríamos oferecer suporte, e a ativação do encadeamento de grande parte do código do banco de dados exigiria uma reescrita quase total. .. não vai acontecer com a arquitetura antiga.

Mesmo assim, não tenho certeza de que teria reescrito, exceto que tinha conhecimento detalhado do comportamento do sistema atual e era um código relativamente limpo que não havia desenvolvido muitas verrugas em seus 11 anos de vida.

1
Anon

Bem, eu posso imaginar cenários hipotéticos em que eu poderia simplesmente jogar fora a base de código existente (situações hipotéticas em que as bolas de bucky têm peso e volume zero, onde ninguém se importa se perdermos semanas ou meses de produtividade enquanto lutamos para adicionar recursos e erros negligenciados corrige o sistema, e onde o sistema é tão trivial e odiado por uma organização que eu posso substituir a coisa toda e o exército de servidores pelo bloco de notas ++ e um netbook em dez minutos e aumentar a produtividade e a moral de todos.)

Para quase qualquer cenário do mundo real, eu recomendaria apenas a refatoração. ^ _ ^. Há muitos custos ocultos e imprevistos para reescrever quando os requisitos legais e comerciais não documentados começam a aparecer e o último minuto de hackers juntos no último minuto começa a acontecer.

== Refatoração no local para maior bem e outras coisas ==

Refatorando o código legado com a abordagem incremental antiga regular

  1. Se você tiver a chance de converter para UML e documentar a pouca arquitetura que existe.
  2. Se você estiver no controle de versão, procure gerar alguns relatórios de rotatividade de código e descobrir quais arquivos e seções de arquivo foram alterados com mais frequência. Tome nota disso, pois provavelmente serão as áreas com as quais você deseja lidar primeiro.
  3. Antes de alterar qualquer código, tente sempre adicionar alguma cobertura de teste (até mesmo os funcionais feios pacotes funcionais). Se você estiver lidando com uma lógica de extração de código processual grande e confusa, pretende mudar para algum método ou função com nome razoável e, se possível, adicione alguns casos de teste que verifiquem seu novo método. faça qualquer truque horrível que você precise e, se possível, paramatize a alteração, se for algo geralmente ajustado como largura da margem ou título, para que seja um pouco mais fácil atualizar a próxima vez.
  4. Use o padrão do adaptador e trabalhe para ocultar os bits mais difíceis do código legado sob um tapete de classes e métodos nomeados logicamente, para que, nas tarefas mais comuns que você e os outros desenvolvedores realizem, não precise se preocupar com os bits assustadores que estão por trás suas costas por trás dos métodos e classes agradáveis ​​e pequenos que você escondeu por trás desse código legado - como aquelas famílias que mantêm deformados ex-zumbis assassinos em celeiros para que não estraguem o dia-a-dia do Fazenda . . . normalmente.
  5. Enquanto você continua a limpar e limpar, as seções do código continuam a aumentar sua cobertura de teste. Agora você pode se aprofundar ainda mais e "reescrever" ainda mais o código quando necessário/desejado com uma confiança cada vez maior.
  6. Repita ou aplique abordagens de refatoração adicionais para continuar melhorando sua base de código.

Ramificação por abstração

  1. Defina o ponto do problema no código que você deseja remover (a camada de persistência, o gerador de pdf, o mecanismo de registro de faturas, o gerador de widget etc.).
  2. execute (escreva se necessário) alguns casos de teste funcionais (automatizados ou manuais, mas você sabe automatizados) na base de código que tem como alvo essa funcionalidade, juntamente com o comportamento geral.
  3. Extraia a lógica relacionada a esse componente da base de origem existente para uma classe com alguma interface razoável.
  4. Agora, verifique se todo o código está usando a nova interface para executar a atividade X, que antes era dispersa aleatoriamente por todo o código (cumpra a base de códigos, adicione um rastreio à nova classe e verifique as páginas que deveriam estar chamando, etc.) e que você pode controlar qual implementação será usada modificando um único arquivo. (registro de objeto, classe de fábrica, qualquer que seja IActivityXClass = Settings.AcitivtyXImplementer ();)
  5. execute novamente os casos de teste funcional que verificam que tudo ainda está funcionando com toda a Atividade X lançada em sua nova classe.
  6. Escreva testes de unidade sempre que possível em torno da nova classe de atividade X wrapper.
  7. implemente uma nova classe com lógica espaguete menos insana do que a implementação herdada que adere à mesma interface que a classe herdada.
  8. verifique se a nova classe passa nos testes de unidade que você escreveu para a classe herdada.
  9. atualize seu código alterando o registro/factorymethod/o que quer que seja para usar a nova classe em vez da antiga.
  10. verifique se seus testes funcionais ainda passam.

Princípio fechado aberto e uma camada comum de lógica/persistência de negócios

Até certo ponto, talvez você consiga se livrar da camada de apresentação, negócios e persistência e escrevendo um novo aplicativo totalmente compatível com a solução herdada ou, no mínimo, ainda possa lidar com os dados inseridos pela solução herdada. Provavelmente, eu não recomendaria essa abordagem, mas às vezes é um comprometimento razoável de tempo/cronograma/recursos/nova funcionalidade necessária.

  • Separe, no mínimo, a camada de apresentação das camadas de negócios e persistência.
  • implemente uma nova interface do usuário e uma melhor camada de apresentação que use a mesma camada comum de negócios e persistência.
  • Verifique se os dados criados com a nova interface do usuário não quebram a interface do usuário antiga. (você estará em água quente se os usuários da nova ferramenta interromperem os usuários da ferramenta antiga). Se você deseja obter compatibilidade total com versões anteriores, salve tudo nas mesmas camadas de persistência. Se você deseja apenas compatibilidade direta com a nova ferramenta, use um novo banco de dados e novas tabelas ou tabelas de extensão para rastrear dados que não estão no sistema legado.
  • Para novas funcionalidades e camada de persistência, adicione novas tabelas e métodos, não altere a lógica herdada existente nem adicione colunas, restrições às tabelas existentes. por exemplo. se você precisar começar a rastrear o contato de emergência dos empregadores e alguns outros campos não modificarem a tabela de funcionários existente (não temos idéia de quais suposições os dados herdados fazem sobre essa tabela), adicione uma tabela de extensão employee_ext id, employee_id, emergency_contact_id, etc_id.
  • Migre lentamente os usuários para o novo sistema. se possível, coloque o sistema legado no modo somente leitura ou adicione algum aviso informando aos usuários que ele não estará mais disponível após a data X.
  • implementar qualquer funcionalidade perdida de alta prioridade ou requisitos de negócios na nova interface do usuário
  • rolar sobre a base de usuários.
  • continue limpando a lógica de negócios e os usuários da camada de persistência, outras metodologias de refatoração.
0
Keith Brings

Eu diria que existe uma terceira categoria no espaço Refactor vs Rewrite ... E isso está atualizando suas versões de idioma, compiladores e bibliotecas ... Às vezes, apenas a adoção de técnicas modernas de codificação traz um grande benefício.

Pegue o C #, por exemplo, o código v7 escreve muito mais limpo, mais seguro e mais conciso que o v2. Coisas como o Elvis e o operador coalescente nulo ajudam muito.

Alternar compiladores também pode dar vida nova a códigos mais antigos. Assim como as novas bibliotecas que podem facilitar as coisas para trabalhar e implementar ... A rede é um ótimo exemplo de um espectro de dificuldades de implementação.

Também - sistemas linux embutidos ... Pense em instalar novas ferramentas - mude para o git a partir do svn. ou adicione o Vi ao seu sistema, etc.

Nem sempre precisa ser um refator versus uma reescrita. Sua arquitetura provavelmente está precisando de melhorias, mas funciona ... talvez você só precise pensar em como seu código está escrito etc.

0
visc

Para decidir o ponto em que você deve recomeçar, você precisa descobrir onde o valor de continuar em seu projeto atual fica aquém do valor em recomeçar.

A razão pela qual isso é tão difícil é que você faça uma estimativa precisa da velocidade de desenvolvimento da equipe no novo projeto até que você realmente o inicie. Dito isto, se, usando uma estimativa MUITO conservadora de sua velocidade de desenvolvimento no novo projeto, estima-se que o projeto ofereça um retorno sobre o investimento valioso, você terá um caso de negócios para começar de novo.

0
Nobody

Com minha métrica, você precisa atender a duas condições para justificar uma reescrita:

  1. Após a reescrita, os novos recursos ficarão mais fáceis/rápidos/com menos erros de gravação
  2. A reescrita levará um tempo menor ou igual ao adicionar o novo recurso atual.

Mesmo assim, você deseja limitar o escopo de sua reescrita. Por exemplo, tínhamos algum software legado em uma empresa que foi escrita em C++ com a mentalidade de um programador de C que não conhecia modularidade. O resultado final foi o código speghetti na forma de uma máquina de estados finitos que abrangia várias classes e DLLs. Tínhamos um novo requisito que era muito diferente das suposições embutidas no código e faria parte do valor agregado patenteado da empresa para seus clientes.

Depois de passar um tempo com o código implementando outros recursos, tive uma idéia muito boa de quanto tempo levaria para descobrir qual das várias instruções de chave eu precisaria alterar etc. Minha proposta era reescrever a seção de código que era a enorme máquina de estados finitos - levaria menos tempo do que estender o código existente. Consegui consolidar em um DLL o que costumava ser três) e fornecer uma estrutura muito mais orientada a objetos que tornaria muito mais fácil executar a nova funcionalidade crítica, além de facilitar a adicione nova funcionalidade.

Havia três outros aplicativos usando as bibliotecas que precisavam ser reescritos, então eu não queria ter que reescrever completamente esses programas. O escopo era limitado à biblioteca e o que era necessário para vincular a biblioteca ao software existente. Minhas estimativas não foram muito longe e o trabalho se pagou. Logo após o redesenho, fui encarregado de adicionar um novo recurso. O que me levaria uma semana com a estrutura antiga levou apenas um dia com a nova estrutura.

0
Berin Loritsch

O OP não indica o escopo do projeto, mas a pista principal que tomei foi "escrita em [idioma/dialeto] antigo usando [libs] antigas" que, para mim, são os principais drivers de uma reescrita. De fato, a maioria dos projetos em que tenho alguma longevidade significativa no mercado acaba percebendo que a atualização de compiladores/intérpretes/sistemas operacionais é uma tarefa importante para manter a base de código.

Em resumo, planejaria a reescrita em fases, priorizando primeiro a atualização nas bibliotecas. Pode ser que, ao longo do caminho, você possa se infiltrar em outras otimizações, mas o fato de planejar adiar algumas alterações para uma fase posterior pode ser uma ótima maneira de manter o cronograma e evitar "ficar preso".

0
MarkHu