Quando os ganchos são a escolha certa para o design?

10

Eu trabalhei em um aplicativo Rails grande, em que o uso de retornos de chamada ActiveRecord era galopante e angustiante. Salvar um registro geralmente tinha efeitos colaterais inesperados e era um desafio argumentar sobre o sistema.

Ao mesmo tempo, vi ganchos usados ​​com bom efeito como parte da herança (por exemplo, uma classe pai usando um método de modelo para permitir que as subclasses adicionem um comportamento especializado sem precisar conhecer os internos do pai) e em plug-ins (por exemplo, um modo emacs executando um gancho quando ativado, permitindo que os usuários adicionem um comportamento personalizado nesse modo).

Percebo que um aplicativo Rails e um intérprete Lisp são sistemas muito diferentes, mas estou curioso para saber se existem critérios conhecidos que as pessoas procuram ao decidir se os ganchos são a escolha certa de design para o problema que estão enfrentando.

O tema que pula para mim é a previsibilidade. O uso indevido de ganchos parece levar a uma ação assustadora à distância e a um comportamento surpreendente, enquanto o bom uso pode levar a uma estrutura previsível sem acoplamento rígido.

Como ainda tenho apenas alguns anos de minha carreira em programação, considero-me um noob em muitos aspectos, e suspeitamos que as pessoas tenham pensado bastante nesse assunto. Quais são algumas diretrizes que podem orientar essa decisão?

ivan
fonte

Respostas:

5

Ganchos são uma boa opção de design quando você deseja dissociar os detalhes de implementação de uma abstração de seus consumidores, transferindo o controle para os receptores do gancho.

Você pode fazer isso por uma transmissão anônima (como eventos ou retornos de chamada anônimos) ou usando abstrações digitadas (como Interfaces ou classes pai).

Você deve usar transmissão anônima quando:

  • A chamada do gancho é opcional
  • O interlocutor não se importa com quem recebe o gancho.
  • A ordem de execução dos receptores é irrelevante.
  • Você deseja transmitir o estado do objeto para todos os assinantes do gancho.

Você deve usar uma abstração digitada quando:

  • Chamar o gancho é obrigatório.
  • O objeto de chamada precisa identificar o receptor do gancho.
  • A ordem de execução dos receptores é relevante para o seu objeto.

Um exemplo de gancho de transmissão é um KeyPressedEvent. A classe que dispara o evento não se importa com quem o recebe e está transmitindo o estado do teclado para qualquer pessoa inscrita no evento. A ordem de execução dos receptores não afeta o estado do objeto da classe que dispara o evento.

Um exemplo de gancho de abstração digitado é o método de modelo que você mencionou. Nesse caso, a classe pai exige uma implementação para seus métodos de modelo, sabe que os receptores serão filhos dela e tem uma ordem de execução específica para os métodos de modelo, conforme definido pela classe pai.

Cesar Hernandez
fonte
7

A maioria dos idiomas e a maioria das plataformas usam o hooking, mesmo que esteja vestido como outra coisa. Sempre que você ouvir sobre o termo "evento", "mensagem", "gatilho", "sinal" ou outros termos dessa natureza, provavelmente estará lidando com ganchos, embora haja exceções à regra, que provavelmente não assunto para esta discussão.

Você os usa porque a plataforma os fornece a você, ou possivelmente requer o uso deles por razões de desempenho. O uso de ganchos geralmente reduz a complexidade do código, ajuda a reforçar os requisitos de negócios e reduz o uso da CPU, prolongando a vida útil da bateria e do hardware. Você deve usá-los sempre que desejar o melhor desempenho do seu código.

Até mesmo sua experiência angustiante com o Rails identifica um caso de uso comum para ganchos: as regras de negócios devem ser impostas e os ganchos são praticamente universalmente usados ​​para impor regras de negócios. Infelizmente, nem todas as regras fazem sentido e, como você pode ver, torna as coisas mais difíceis para um desenvolvedor quando são arbitrárias, mas é por isso que a documentação de um sistema é tão importante quanto o próprio código.

Como regra geral, use hooks porque são recursos de desempenho e fará com que seu código seja executado com mais eficiência do que a alternativa (que é chamada de "polling", na qual você espera em um ciclo ocupado para verificar eventos). No entanto, verifique também se você usa a documentação apropriada e a mantém atualizada. Os ganchos são usados ​​em praticamente todos os idiomas que você encontra, e é importante saber por que eles existem.

phyrfox
fonte
1

Eu já trabalhei em um programa que fez na minha opinião um bom uso de ganchos. No meu livro, um verdadeiro gancho é uma chamada (publicação) para uma lista de retornos de chamada (assinantes). É poderoso, abuso é fácil. A melhor pergunta para se fazer caso de uso é: quero ativar ou desativar o comportamento em tempo de execução? Por exemplo, convém permitir que seus usuários forneçam scripts que serão executados em determinados eventos ou crie um programa genérico feito de plugins menores. As chamadas em gancho são apropriadas. Geralmente, você tem poucas outras opções.

Caso contrário, você deve se dar bem com um bom arco de seus módulos. Os métodos de modelo funcionam bem com funções sobrecarregadas; você não precisa de lógica de tempo de execução para isso. Considere que isso imporia um acoplamento frouxo é uma ilusão: existe o mesmo nível de dependência entre algo que você chama diretamente ou que você liga, o chamado precisa cumprir seu contrato de qualquer maneira.

Observe que, talvez algumas pessoas chamem o método de modelo com a sobrecarga de funções sobrecarregadas, mas isso é diferente do acima: aqui você tem uma ligação estática, com menor risco de entrar em um pesadelo de manutenção.

Arthur Havlicek
fonte