Quais são os pontos principais do trabalho eficaz com o código legado? [fechadas]

133

Eu já vi o livro Trabalhando efetivamente com o código herdado algumas vezes. Quais são os pontos principais deste livro?

Há muito mais para lidar com código legado do que adicionar testes de unidade / integração e refatorar?

Armand
fonte
2
Obviamente, o objetivo é adicionar testes e refatorar. O livro é basicamente sobre como você consegue obter código impossivelmente complicado em teste, e há muitos olhos abertos nesse ponto. Digamos apenas que Feathers não leva prisioneiros!
Kilian Foth
9
Talvez você deve apenas ler o livro
HLGEM
Boa revisão aqui: andreaangella.com/2014/03/…
rohancragg 3/14/14

Respostas:

157

O principal problema do código legado é que ele não possui testes. Então você precisa adicionar alguns (e mais ...).

Isso por si só exigiria muito trabalho, como observou @mattnz. Mas o problema especial do código legado é que ele nunca foi projetado para ser testável . Normalmente, é uma enorme bagunça complicada de código de espaguete, em que é muito difícil ou absolutamente impossível isolar pequenas peças para serem testadas em unidade. Portanto, antes do teste de unidade, é necessário refatorar o código para torná-lo mais testável.

No entanto, para refatorar com segurança, você deve ter testes de unidade para verificar se não quebrou nada com suas alterações ... Esta é a captura 22 do código legado.

O livro ensina como interromper essa captura, fazendo as alterações mínimas e mais seguras no código, apenas para permitir os primeiros testes de unidade. Elas não são destinadas a tornar o design mais agradável - apenas para permitir testes de unidade. De fato, às vezes eles tornam o design mais feio ou mais complexo. No entanto, eles permitem que você escreva testes - e depois que você tiver testes de unidade, você estará livre para melhorar o design.

Existem muitos truques para tornar o código testável - alguns são óbvios, outros nem um pouco. Existem métodos que eu nunca teria pensado em mim mesmo sem ler o livro. Mas o mais importante é que Feathers explica o que torna precisamente uma unidade de código testável. Você precisa cortar dependências e introduzir barreiras no seu código, mas por dois motivos distintos:

  • sensoriamento - para verificar e verificar os efeitos da execução de um trecho de código, e
  • separação - para colocar o código específico em um equipamento de teste antes de tudo.

Cortar dependências com segurança pode ser complicado. A introdução de interfaces, zombarias e injeção de dependência é um objetivo limpo e agradável, mas não necessariamente seguro de fazer neste momento. Às vezes, temos que recorrer à subclasse da classe em teste para substituir algum método que normalmente, por exemplo, iniciaria uma solicitação direta a um banco de dados. Outras vezes, podemos até precisar substituir uma classe / jar de dependência por uma classe falsa no ambiente de teste ...

Para mim, o conceito mais importante trazido por Feathers é costuras . Uma costura é um local no código onde você pode alterar o comportamento do seu programa sem modificar o próprio código . A criação de costuras em seu código permite separar o trecho de código em teste, mas também permite detectar o comportamento do código em teste, mesmo quando é difícil ou impossível fazê-lo diretamente (por exemplo, porque a chamada faz alterações em outro objeto ou subsistema , cujo estado não é possível consultar diretamente de dentro do método de teste).

Esse conhecimento permite que você observe as sementes da testabilidade no monte de códigos mais desagradável e encontre as alterações mínimas, menos perturbadoras e mais seguras para chegar lá. Em outras palavras, para evitar fazer refatorações "óbvias" que correm o risco de violar o código sem você perceber - porque você ainda não tem os testes de unidade para detectá-lo.

Péter Török
fonte
5
Observe que quando a resposta acima diz "testes de unidade" , na verdade significa "testes automatizados" . Para um aplicativo legado, uma grande fração dos testes automatizados inicialmente úteis será de fato testes de integração (onde a lógica do teste executa uma laje maior do código geral e pode produzir falhas devido a defeitos em muitos locais diferentes), em vez de uma unidade verdadeira testes (que visam analisar apenas um módulo e executar partes muito menores do código cada).
Lutz Prechelt 18/01
99

Maneiras rápidas de obter os pontos principais de Trabalhar efetivamente com o código herdado

MarkJ
fonte
3
O link MP3 na página Hanselminutes está quebrado, mas o link hanselminutes.com/165/… não é - s3.amazonaws.com/hanselminutes/hanselminutes_0165.mp3 .
Peter Mortensen
Obrigado rosston por corrigir o link do PDF. Parece que objectmentor.com sumiu - talvez "Tio Bob" tenha falido?
MarkJ
Não tenho certeza do que aconteceu com o mentor de objetos, mas hoje em dia o tio Bob trabalha para a 7th Light.
Jules
40

Eu trabalho em uma base de código de milhões de linhas de código, algumas que datam dos anos 80. É apenas software, por isso é apenas uma questão de escrever alguns testes de unidade, para que você possa refatorá-lo e torná-lo muito melhor.

A palavra-chave aqui é apenas: é uma palavra de quatro letras que não pertence ao vocabulário de nenhum programador, muito menos a alguém que está trabalhando em sistemas legados.

Quanto tempo você acha necessário para escrever um teste de unidade, para testar uma hora no esforço de desenvolvimento? Para fins de discussão, digamos mais uma hora.

Quanto tempo é investido nesse sistema legado de 20 milhões de anos? Digamos, 20 desenvolvedores por 20 anos, 2000 horas / ano (eles trabalharam bastante). Vamos agora escolher um número - você tem novos computadores e novas ferramentas e é muito mais esperto do que os caras que escreveram esse pedaço de $% ^^ em primeiro lugar - digamos que você vale 10 deles. Você tem 40 anos homem, bem, você tem ...?

Portanto, a resposta para sua pergunta é que há muito mais. Por exemplo, essa rotina com 1000 linhas (tenho algumas com mais de 5000), é excessivamente complexa e é um pedaço de espaguete. Apenas (mais uma palavra de quatro letras) levaria alguns dias para redimensioná-lo em algumas rotinas de 100 linhas e mais alguns 20 auxiliares de linha, certo? ERRADO. Oculto nessas 1000 linhas, há 100 correções de bugs, cada uma delas um requisito de usuário não documentado ou um caso obscuro. São 1000 linhas porque a rotina original de 100 linhas não fez o trabalho.

Você precisa trabalhar com a mentalidade " se não estiver quebrada, não conserte ". Quando está quebrado, você precisa ter muito cuidado ao corrigi-lo - à medida que melhora, para não mudar acidentalmente outra coisa. Observe que "interrompido" pode incluir código que não pode ser mantido, mas está funcionando corretamente, que depende do sistema e de seu uso. Pergunte "o que acontece se eu estragar tudo e piorar", porque um dia você fará isso e terá que dizer ao chefe dos chefes por que escolheu fazer isso.

Esses sistemas sempre podem ser aprimorados. Você terá um orçamento para trabalhar, uma linha do tempo, o que for. Se não, vá e faça um. Pare de melhorar quando o dinheiro / tempo acabar. Adicione um recurso, reserve um tempo para torná-lo um pouco melhor. Corrija um bug - novamente, gaste um pouco de tempo extra e melhore. Nunca entregue pior do que era quando você começou.

mattnz
fonte
2
Obrigado pelas dicas! Estes são seus ou do livro?
Armand
3
Provavelmente um pouco dos dois - eu li o livro depois de alguns anos fazendo esse trabalho e provavelmente deveria lê-lo novamente. Como qualquer bom livro, ele fará com que você desafie parte do que está fazendo no momento, reforce a maior parte do que faz, mas não tem todas as respostas para o seu conjunto específico de problemas.
mattnz
7
"São 1000 linhas porque a rotina original de 100 linhas não fez o trabalho." Muito raramente, isso parece realmente ser o caso. Na maioria das vezes, são 1.000 linhas simplesmente porque o desenvolvedor original arregaçou as mangas e começou a codificar antes de poupar um momento para o planejamento ou o design.
Stephen Touset
3
Não. Estou dizendo que, na maioria dos casos (eu pessoalmente encontrei), rotinas de 1.000 linhas são indicações claras de que as pessoas começaram a escrever código antes de pensar em como escrever uma abstração adequada. As rotinas de mil linhas são virtualmente complicadas por definição - você está dizendo que uma rotina de mil linhas com centenas de correções ocultas e não comentadas é a marca registrada de um desenvolvedor responsável?
Stephen Touset
16
Se você acreditou em todas as postagens neste site, todo mundo tem que lidar com o código espaguete de 1000 linhas, mas ninguém nunca o escreveu. Na minha experiência, as rotinas de 1000 (e 10000) linhas são a marca registrada dos desenvolvedores que estão fazendo o melhor que podem com o que têm, para entregar o que lhes é exigido pelo chefe que paga seus salários. Acho insultuoso e arrogante o modo como muitos desenvolvedores se sentem à vontade para comentar do lado de fora sem conhecer as circunstâncias, sem nunca ter que expor seu trabalho à comunidade para criticar.
mattnz
19

Existem dois pontos principais a serem retirados do livro.

  1. Código legado é qualquer código que não tenha cobertura de teste.
  2. Sempre que você precisar alterar o código legado, verifique se ele tem cobertura.

Como outros respondentes apontaram, tentar atualizar preventivamente seu código legado existente é uma tarefa fácil . Em vez disso, sempre que você precisar fazer uma alteração no código legado (para um novo recurso ou uma correção de bug), reserve um tempo para remover seu status legado.

Michael Brown
fonte
6
Ponto excelente +1: "Sempre que você precisar fazer uma alteração no código herdado, reserve um tempo para remover o status herdado".
John
3
Removendo o status Legacy, obter do meu voto :)
Rachel
7

Em uma casca de noz, isso é verdade - adicionar testes e refatorar é o que importa.

Mas o livro fornece muitas técnicas diferentes para fazer isso com código que é muito difícil de testar e refatorar com segurança.

Oded
fonte