Quando sono i ganci la scelta giusta per il design?

10

Ho lavorato su una grande app Rails in cui l'uso dei callback di ActiveRecord era dilagante e straziante. Salvare un disco spesso ha avuto effetti collaterali inaspettati ed è stata una sfida ragionare sul sistema.

Allo stesso tempo, ho visto gli hook utilizzati con buoni risultati come parte dell'ereditarietà (ad esempio una classe genitore che utilizza un metodo di modello per consentire alle sottoclassi di aggiungere un comportamento specializzato senza dover conoscere gli interni dei genitori), e in plug-in (es. una modalità emacs che esegue un hook quando è attivata, consentendo agli utenti di aggiungere un comportamento personalizzato attorno a quella modalità).

Mi rendo conto che un'applicazione Rails e un interprete Lisp sono sistemi molto diversi, ma sono curioso di sapere se ci sono criteri noti a cui la gente guarda quando decidono se gli hook sono la scelta giusta per il problema che stanno affrontando .

Il tema che mi viene in mente è la prevedibilità. L'uso improprio di ami sembra portare a azione spettrale a distanza e comportamenti sorprendenti, mentre un buon uso può portare a un quadro prevedibile senza accoppiamento stretto.

Dato che sono ancora solo pochi anni nella mia carriera di programmatore, mi considero un noob per molti aspetti, e sospetto che la gente abbia messo una buona dose di riflessione su questo argomento. Quali sono alcune linee guida che possono guidare questa decisione?

    
posta ivan 25.07.2016 - 01:09
fonte

3 risposte

5

Gli hook sono una buona scelta di design quando si vogliono disaccoppiare i dettagli di implementazione di un'astrazione dai propri consumatori trasferendo il controllo ai ricevitori del gancio.

Puoi farlo tramite una trasmissione anonima (come eventi o richiami anonimi) o utilizzando le astrazioni digitate (come le interfacce o le classi parent).

Dovresti utilizzare la trasmissione anonima quando:

  • La chiamata del gancio è facoltativa
  • Al chiamante non interessa chi riaccende l'hook.
  • L'ordine di esecuzione dei ricevitori è irrilevante.
  • Vuoi trasmettere lo stato dell'oggetto a tutti gli abbonati al gancio.

Dovresti usare un'astrazione tipizzata quando:

  • Chiamare il gancio è obbligatorio.
  • L'oggetto chiamante deve identificare il ricevitore del gancio.
  • L'ordine di esecuzione dei destinatari è rilevante per il tuo oggetto.

Un esempio di hook di trasmissione è un KeyPressedEvent. Alla classe che ha licenziato l'evento non interessa chi lo riceve e sta trasmettendo lo stato della tastiera a chiunque si sia iscritto all'evento. L'ordine di esecuzione dei ricevitori non ha alcun effetto sullo stato dell'oggetto della classe che attiva l'evento.

Un esempio di hook di astrazione tipizzato è il metodo template che hai citato. In questo caso, la classe genitore richiede un'implementazione per i suoi metodi modello, sa che i destinatari saranno figli di esso e ha un ordine di esecuzione specifico per i metodi del modello, come definito dalla classe genitore.

    
risposta data 25.07.2016 - 22:54
fonte
7

La maggior parte delle lingue e la maggior parte delle piattaforme usano l'hooking, anche se è vestita come qualcos'altro. Ogni volta che ascolti il termine "evento", "messaggio", "trigger", "segnale" o altri termini di tale natura, probabilmente stai affrontando l'hooking, anche se ci sono delle eccezioni alla regola, che probabilmente non questione per questa discussione.

Li usi perché la piattaforma te li fornisce, o forse richiede anche il loro uso per motivi di prestazioni. L'uso degli hook riduce spesso la complessità del codice, aiuta a far rispettare i requisiti aziendali e riduce l'utilizzo della CPU, prolungando la durata della batteria e dell'hardware. Dovresti usarli quando vuoi la migliore performance dal tuo codice.

Anche la tua esperienza straziante con Rails identifica in modo abbastanza approssimativo un caso di utilizzo comune per gli hook: le regole aziendali devono essere applicate e gli hook sono praticamente universalmente utilizzati per applicare le regole aziendali. Sfortunatamente, non tutte le regole hanno senso e, come puoi vedere, rendono le cose più difficili per uno sviluppatore quando sono arbitrarie, ma è per questo che la documentazione di un sistema è importante tanto quanto il codice stesso.

Come regola generale, usa i ganci perché sono funzioni di prestazioni e renderà il tuo codice più efficiente rispetto a quello alternativo (che si chiama "polling", dove attendi in un loop occupato per controllare gli eventi). Tuttavia, assicurati anche di utilizzare la documentazione appropriata e di mantenerla aggiornata. I ganci sono usati praticamente in tutte le lingue che incontrerai ed è importante sapere perché esistono.

    
risposta data 25.07.2016 - 02:20
fonte
1

In precedenza ho lavorato su un programma che a mio parere ha fatto un buon uso dei ganci. Nel mio libro, un vero hook è una chiamata (publish) a un elenco di callback (subscriber). È potente, l'abuso è facile. La migliore domanda da porsi è: voglio abilitare o disabilitare il comportamento in fase di esecuzione? Ad esempio, potresti voler consentire agli utenti di fornire script che verranno eseguiti su determinati eventi o creare un programma generico composto da plug-in più piccoli. Quindi le chiamate hook sono appropriate. In generale, hai poche altre opzioni.

In caso contrario, dovresti farla franca con un buon arco di moduli. I metodi modello funzionano bene con le funzioni sovraccariche, per questo non è necessaria la logica di runtime. Considerare che fare rispettare l'accoppiamento libero è un'illusione: c'è lo stesso livello di dipendenza tra qualcosa che si chiama direttamente o si aggancia, il callee deve comunque riempire il suo contratto.

Si noti che, forse alcune persone chiamano il metodo template con il hooking delle funzioni sovraccarico, ma questo è diverso da quanto sopra: qui si ha un collegamento statico, con un rischio inferiore di entrare in un incubo di manutenzione.

    
risposta data 26.07.2016 - 04:44
fonte

Leggi altre domande sui tag