Como evitar métodos de cola gigante?

21

No meu trabalho atual, fui encarregado de limpar o código antigo algumas vezes. Geralmente, o código é um labirinto e os dados por trás dele são ainda mais confusos. Encontro-me penteando as coisas em métodos agradáveis, puros e modulares. Cada método faz uma coisa e faz bem. É quando as coisas começam a ir para o sul ...

Invariavelmente, eu acabo com uma API limpa e sem uma maneira real de vincular tudo. A solução foi escrever um método grande e feio de "cola" (geralmente cheio de instruções condicionais) que eventualmente chama todos os meus métodos "limpos".

O método cola geralmente acaba sendo uma versão concisa do emaranhado de código / dados que eu estava tentando limpar. Geralmente é mais legível, mas ainda é irritante.

Como posso evitar esses métodos? Isso é um sintoma dos dados emaranhados ou um reflexo de algo que estou fazendo de errado?

cmhobbs
fonte
3
APIs devem ser usadas. A partir da bagunça emaranhada que você criou, você criou uma API e a reorganizou. Talvez seja apenas o requisito comercial. Mas você agregou valor porque outra pessoa pode vir e fazer com que outra cola funcione facilmente usando sua API. Não há necessidade de torcer as mãos ...
Aditya MP
1
Estamos falando de objetos aqui ou apenas funciona em todo o lugar?
precisa
3
Eu não acho que isso seja uma duplicata dessa pergunta, estou falando um pouco mais geralmente (e em uma escala maior que uma única função).
Cmhobbs
1
erik - eu estou falando sobre objetos e métodos aqui. Peguei algumas bagunças condicionais e as transformei em APIs. O problema surge quando é hora de chamar a API. A primeira resposta aqui pode ser exatamente o que estou procurando.
cmhobbs 27/02
2
Como diabos isso é uma duplicata?
MattDavey

Respostas:

12

Darei a você nossa experiência na refatoração do LedgerSMB. Decidimos fazer as coisas de maneira diferente desde o início e ainda estamos fazendo exatamente o que você descreve, mas sem muitos métodos de colagem (temos alguns métodos de colagem, mas não muito).

Vida com duas bases de código

O LedgerSMB sobreviveu com duas bases de código por cerca de 5 anos e serão várias mais antes que a antiga base de código seja eliminada. A antiga base de código é um verdadeiro horror de se ver. Com design ruim de banco de dados, o Perl constrói como IS->some_func(\%$some_object);junto com o código que mostra exatamente por que a metáfora do espaguete às vezes é usada (caminhos de execução que vagam entre os módulos e as costas e entre os idiomas, sem rima ou razão). A nova base de código evita isso, movendo consultas db para procedimentos armazenados, tendo uma estrutura mais limpa para manipulação de solicitações e muito mais.

A primeira coisa que decidimos fazer foi tentar refatorar módulo por módulo. Isso significa mover todas as funcionalidades em uma área específica para um novo módulo e conectar o código antigo ao novo módulo. Se a nova API estiver limpa, isso não é grande coisa. Se a nova API não estiver complicada, é um convite para trabalhar um pouco mais com a nova API ...

A segunda coisa é que há muitas vezes em que o novo código precisa acessar a lógica no código antigo. Isso deve ser evitado na medida do possível, pois leva a métodos de cola feios, mas nem sempre é possível evitá-lo. Nesse caso, os métodos de cola devem ser minimizados e evitados na medida do possível, mas utilizados quando necessário.

Para fazer isso funcionar, você precisa se comprometer a reescrever todas as funcionalidades em uma área específica. Se você pode, por exemplo, reescrever todos os códigos de rastreamento de informações do cliente de uma só vez, isso significa que não é difícil trabalhar com o código que chama isso do código antigo e o envio para o código antigo a partir do novo código é minimizado.

A segunda coisa é que, se você tiver abstrações razoáveis, poderá escolher qual nível da API chamar e como mantê-la limpa. No entanto, você deve reescrever as partes que estão chamando sua API para que elas também sejam um pouco mais limpas.

Existem muitas áreas de ferramentas de negócios que são irredutivelmente complexas. Você não pode se livrar de toda complexidade. Mas você pode gerenciá-lo concentrando-se em APIs limpas, que fazem especificamente o que você precisa fazer, e em módulos que utilizam essa API construtivamente. A cola deve ser o último recurso somente depois de considerar que a reescrita do restante do código de chamada pode ser mais rápida.

Chris Travers
fonte
Eu acho que você pode ter acertado a unha na cabeça. A razão pela qual a cola existe pode ser devido ao código que chama a interface que eu criei. Vou esperar por mais algumas respostas para ver se estamos perdendo alguma coisa, mas acredito que esta resume muito bem.
Cmhobbs
1
"caminhos de execução vagando entre módulos e de volta, e entre idiomas, sem rima ou razão" - isso me lembra algumas práticas modernas de OO também.
user253751
8

Parece que você tem feito é tomado um emaranhado de uma precedural base de código e criou uma linda modular precedural base de código.

Invariavelmente, eu acabo com uma API limpa e sem uma maneira real de vincular tudo. A solução foi escrever um método grande e feio de "cola" (geralmente cheio de instruções condicionais) que eventualmente chama todos os meus métodos "limpos".

Com o código processual (mesmo que esteja disfarçado de OO), você sempre acabará com algum tipo de fluxo de trabalho sequencial definido em algum lugar, geralmente preenchido com ramificações condicionais complexas conforme você descreve. Eu suspeito que é essa natureza processual do código que está fazendo você sentir que algo está errado. Isso não é necessariamente uma coisa ruim e, ao trabalhar com código legado, pode ser totalmente inevitável

MattDavey
fonte
6

Você deve limpar o método de cola grande e feia da mesma maneira que limpou a base de código original. Divida-o em métodos modulares puros. Você provavelmente tem grupos de linhas de código que realizam alguma tarefa dividir essas linhas em métodos; se você compartilhar algumas variáveis, poderá considerar colocar as variáveis ​​compartilhadas e os novos métodos em uma classe.

Paling
fonte
2
Você não pega uma árvore de cola então?
Pieter B
3
@ PieterB talvez, mas é mais fácil extrair as diferentes dependências quando você tem tarefas diferentes em métodos diferentes. Você poderia fazer outra passagem de refatoração após extrair os novos métodos.
Enviado
1

Basicamente, você continua adicionando camadas de abstração, até que pareça correta em cada camada tirada sozinha . O aspecto paradoxal da abstração é que você adiciona complexidade para reduzi-la, porque quando você lê código abstraído, se preocupa apenas com uma camada de cada vez. Se cada camada é pequena o suficiente para ser facilmente entendida, não importa em quantas camadas ela está apoiada.

É também isso que torna as abstrações difíceis de escrever. Mesmo algo tão simples como um lápis é incompreensível, se você tentar segurar todas as suas camadas de abstração na cabeça de uma só vez. A chave é obter uma camada do jeito que você gosta, e depois esquecer toda a complexidade subjacente a essa camada e fazer a mesma coisa no próximo nível.

Karl Bielefeldt
fonte
0

Parece que você está refatorando a API apenas pensando na implementação da API, mas sem pensar o suficiente no código que usa a API - ou seja, o "código de cola" de que você está falando.

Se isso for verdade, você pode tentar começar do outro lado. Reescreva as coisas que ameaçam se tornar seu código de cola feio primeiro e crie algumas interfaces ainda não implementadas que se tornarão sua API nesse processo. Ainda não pense muito na implementação real dessa API - tudo bem se você tiver a sensação de que pode fazê-lo. E só então reescreva o labirinto de código para estar em conformidade com essa API. Obviamente, haverá algumas alterações na API e no código de cola nesse processo, mas deve se encaixar melhor.

Hans-Peter Störr
fonte