O monkeypatching é considerado uma boa prática de programação?


15

Eu tenho a impressão de que o monkeypatching é mais uma categoria de hack rápido e sujo, em vez de boas práticas de programação padrão. Embora eu tenha usado de tempos em tempos para corrigir pequenos problemas com bibliotecas de terceiros, considerei uma correção temporária e enviaria o patch adequado ao projeto de terceiros.

No entanto, eu vi essa técnica usada como "o caminho normal" em projetos convencionais, por exemplo, no gevent.monkeymódulo de Gevent .

O monkeypatching tornou-se prática de programação convencional, normal e aceitável?

Veja também: "Monkeypatching For Humans", de Jeff Atwood


13
Eu diria que algo chamado patch de macaco NÃO é considerado uma boa prática de programação. Sem nem mesmo saber o que é, apenas pelo nome.
Littleadv

E se terceiros não quiserem fazer a correção necessária?

1
@ Thorbjørn: boa pergunta, por um lado, não gosto de monkeypatching, por outro, não gosto da idéia de clonar projeto e manter patches locais, se for apenas um pequeno problema.
Vartec 16/04

1
@littleadv: ... então chame de "hot fix" / "on-the-fly fix" ou "runtime fix" e soa bem, certo? ;) É tudo a mesma coisa.
dagnelies

3
javascript está praticamente construída em torno do conceito
ZJR

Respostas:


19

Não, mas às vezes o monkeypatch é um mal menor (do que ter código quebrado :)). Minhas regras gerais para monkeypatches em ruby ​​são:

  • tenha um bom motivo para o patch do macaco (o hotfix crítico temporário é um bom motivo. A boa formatação do método to_s não é, a menos que você esteja trabalhando no ActiveSupport)

  • torne-os o mais transparentes possível: coloque-os em um local específico na base de código e em arquivos separados, escreva documentação descrevendo o motivo do monkeypatch (veja um exemplo ).

  • fácil de remover - a documentação deve incluir informações sobre remoção e o que observar. Muitos monkeypatches são temporários, portanto devem ser fáceis de remover.


11

Sim, o monkeypatching é muito útil!

De alguma forma, os nomes parecem ser altamente influentes na percepção das pessoas. Chame de "monkeypatch" e soa mal, chame de "hot fix" ou "on-the-fly fix" e soa bem.

Independentemente disso, acho que a capacidade de alterar métodos / atributos / funções em tempo de execução é uma coisa muito útil. Até as pessoas que usam javascript usam o dia todo, talvez sem saber.

Por exemplo:

button.onclick = function(e) { ...}

Esta linha simples ilustra o fato de que você altera o comportamento do botão. Foi projetado dessa maneira. Da mesma forma, você pode alterar todas as outras funções, mas seria tolo fazê-lo.

Agora, para a questão de entregar patches dessa maneira ... bem ... por que não. Você só precisa baixar um pequeno patch em vez de um grande lançamento. Caramba, você pode até corrigir um servidor sem parar, ótimo! E então, um dia, você também pode buscar a versão mais recente para obter uma atualização maior. Justo. Então, sim, voto por "patches de tempo de execução" como uma coisa boa.

Curiosamente, algumas línguas como Erlang foram construídas em torno desse conceito. A capacidade de atualizar um servidor em tempo real.

É claro que, no final, e como em todo o resto, é uma questão de como você o usa. Você pode fazer coisas maravilhosas de OO e uma merda, é tudo a mesma coisa.

EDITAR:

Deixe-me adicionar uma distinção entre maiúsculas e minúsculas, se você está corrigindo sua própria biblioteca ou uma biblioteca de terceiros .

... basicamente, o que você faz com esse patch é consertar um bug próprio ou de uma biblioteca de terceiros . Em ambos os casos, é útil. Para você, ele permite que você forneça uma correção em tempo real. Para um terceiro, você espera (vários meses?) Até que eles o consertem por conta própria ou você o faça agora por conta própria. (você ainda pode enviar o patch para eles, para que o consertem). Quando eles liberam sua próxima versão lib com o problema corrigido, você ainda pode, se você quiser atualizar a biblioteca e remover o patch do seu lado.

Agora, é claro, se você usa um patch para alterar o comportamento de uma lib e alienar seu propósito / maneira de trabalhar, então obviamente isso é uma receita para o desastre. Até um macaco veria isso ... bem, espero. ;)


1
Ninguém diz que não é útil. No entanto, não é uma boa prática em geral. E "hotfix" e "correção on-the-fly" não me parecem melhores.
Lukas Stejskal

1
Bem, acho muito útil a capacidade de alterar o comportamento de um aplicativo em tempo real, ainda mais se for grande. Heck, você pode até ter o código armazenando o método antigo como backup e um comando para reverter automaticamente sob demanda! As possibilidades são tremendas!
dagnelies

Concordo que é um recurso poderoso e útil. Mas também muito perigoso (especialmente em Ruby), portanto, deve ser usado com extrema cautela (especialmente para modificação de bibliotecas padrão e de terceiros). Você já tentou manter o aplicativo, dependendo de várias bibliotecas de terceiros com o mesmo código? Uma receita para o desastre sempre que você tentar atualizar alguma biblioteca.
Lukas Stejskal

1
Sim, eu concordo, se você usar esses patches descuidadamente, de maneiras não intencionais ou abusar deles, ele poderá se tornar rapidamente confuso. Como você pode abusar de qualquer conceito ou bagunçar qualquer coisa. No entanto, caso contrário, se eles estiverem bem organizados e transparentes, e todos fluírem no próximo grande lançamento, parece-me limpo. ... no entanto, não tenho experiência com bibliotecas de ruby ​​com muitos patches.
Dagnelies

... Adicionei alguns comentários sobre o último caso.
Dagnelies

8

Acredito que todos os patches são inerentemente arriscados devido à sua natureza em tempo de execução e à incapacidade de serem capturados no tempo de design.

Eles aceitam exceções de tempo de execução e exigem depuradores e relógios complexos apenas para serem seguidos.

Eles são usados ​​quando as pessoas SEAL classificam e, portanto, a herança é impossível. No entanto, existem maneiras melhores de estender objetos sem danificá-los.

Meus dois centavos


4

A aplicação de patches em geral deve ser o último recurso, a aplicação de patches de macaco ainda mais. O problema é principalmente de manutenção.

Há muito tempo, meu kernel do linux tinha 3 patches separados, necessários para o driver da minha placa de vídeo e dois aplicativos proprietários que eu tinha. Dois deles tiveram alterações conflitantes, o que significava que eu precisava de um quarto patch para resolver as diferenças entre eles. Agora, sempre que um problema de segurança era corrigido no kernel upstream, eu precisava esperar pelos fornecedores desses 3 patches para lançar uma atualização para a nova versão do kernel, que levava de um a seis meses, ou eu tinha que manter manualmente o upstream patches de segurança até que os outros fornecedores de patches os alcançassem.

Depois de alguns anos, os fornecedores conseguiram ser incluídos na fonte do kernel upstream, e eu pude interromper o ato de balanceamento, mas você pode ver o que era uma bagunça nesse meio tempo. Não imponha isso aos seus programadores, a menos que você precise.


3

Não. Não é uma técnica padrão para desenvolvimento de software. Continua sendo uma solução alternativa para resolver um problema agudo e possui desvantagens claras. A violação do princípio da substituição de Liskov vem à mente. A aplicação de patches de macaco dificulta seriamente a discussão sobre os programas. Para seus próprios programas, você deve colocar o código onde ele pertence. Para bibliotecas de terceiros, você sempre estará em perigo, pois seu patch não funcionará com a próxima versão da lib.

É claro que a aplicação de patches de macaco é útil se você souber o que está fazendo e não tiver tempo para implementar uma solução SOLID . Mas você nunca deve considerar isso uma técnica padrão e criar um patch de macacos em cima de um macacão.

BTW, você já escreveu um teste de unidade para um patch de macaco?


Eu não acho que você pode aplicar o LSP aqui. Tem uma definição muito específica sobre subtipos.
Konrad Rudolph

O @KonradRudolph Monkey que corrige um objeto altera seu tipo. Em idiomas tipados dinamicamente, todo tipo t com a mesma interface que o tipo u é um subtipo de u. Se anda como um pato ...
scarfridge

"... muda seu tipo" - bastante justo. Faz sentido.
Konrad Rudolph

RE "Não é uma técnica padrão para desenvolvimento de software.", Parece ser feita o tempo todo e nas principais bibliotecas "em Python para teste."
Tommy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.