Devo documentare le sequenze di chiamata previste quando l'ordine delle chiamate è importante?

0

Nei linguaggi dinamici e debolmente tipizzati , spesso mi trovo con strutture come il seguente pseudocodice:

class Stateful:

    # [ various datamembers / attributes / properties / fields / etc. ]

    define constructor(arguments):
        configureA(arguments)
        # [ maybe set a variable or two here ]
        configureB()

    define configureA():
    ## configures the most important parts of Stateful state
    ## throws some exceptions if these basic changes cannot be made
        # [ code goes here ]

    define configureB():
    ## handles a little bit of bookkeeping. Usually called after configureA().
    ## expects the following variables to be set: <list of vars>
        # [ code goes here ]
    #
    # ...

Sebbene ci possa essere un modo migliore per farlo, come fornire un blocco singolo che descriva la sequenza di chiamate e le conseguenze delle note tutte in una volta, è una buona idea in generale per documentare le sequenze di chiamate previste? Se è una buona idea per "documentare" questo tipo di cose quando si presenta, ci sono i migliori pratiche? O lo sta facendo forse un segnale di un problema più profondo?

* Risposte a questa domanda suggerisce che configureA() restituisca un tipo che è richiesto da configureB() , quindi ha configureB() ritorno un tipo che è richiesto da configureC() , ecc. Sto chiedendo qui di lingue che sono tipicamente debolmente e / o tipizzate, o nei casi in cui l'aggiunta di classi extra per ogni passo di configurazione darebbe solo un mucchio di classi piccole con basso a nessuna riusabilità e scarsa manutenibilità data la necessità di ancora più classi se config guadagna passaggi.

I miei pensieri contrastanti su questo seguono sotto la linea:

Motivi per documentare le sequenze di chiamata previste (in una forma o nell'altra):

  • Tali commenti spesso mi aiutano a rintracciare gli eventuali misteriosi errori nel mio codice, portandomi a riesaminare sequenze di chiamata dopo periodi di concentrazione su altri dettagli di implementazione.

  • Se il codice per le classi stateful deve essere aggiornato, questo dovrebbe aiutare gli altri programmatori a evitare errori così misteriosi.

  • Soprattutto per le funzioni private, la descrizione dei "contratti" delle funzioni nei commenti mi consente di concentrarmi sulle funzionalità essenziali in e meno su throw new DescriptiveErrorMessage("Let's talk for a while, shall me? ...") . Anche nel caso in cui le eccezioni dovrebbero alla fine essere lanciate, trovo più facile tornare indietro ed esaminare casi eccezionali dopo che sono stato separato dalla vera parte "funzionante" del codice per un po '.

  • Non tutti gli altri programmatori useranno IDE in grado di generare informazioni su sequenze di chiamate permanenti per loro, e anche se lo facessero, un IDE potrebbe non essere in grado di dire a un programmatore se una certa sequenza di chiamate di inizializzazione è necessario o solo di fatto "è in questo ordine perché è così che è stato scritto"

Motivi non per fare questo:

  • Commenti come questi sono specifici dell'implementazione e potrebbero non avere molta utilità dopo che una classe è stata stabilizzata.

  • Commenti come questi aumentano il carico di manutenzione del codice perché devono essere tenuti aggiornati oltre al codice stesso.

  • Il codice dovrebbe parlare da solo e i bravi programmatori dovrebbero usare l'introspezione invece di leggere il mio drivel.

  • I commenti che specificano questo tipo di precondizioni sequenziali potrebbero essere solo una stampella per codice errato.

posta SeldomNeedy 22.10.2015 - 03:23
fonte

1 risposta

1

Considera il seguente esercizio di riflessione "what-if":

Supponiamo di modificare configureA e configureB , in modo che invece di eseguire effettivamente il lavoro che dipende dall'ordine, i due metodi si limitino a salvare una copia dei parametri che sono stati passati.

Quindi, scrivi un altro metodo, realConfigureA_and_B che prende quei parametri salvati e fa il lavoro effettivo che dipende dall'ordine.

La domanda da porsi è: se dividi le funzioni in questo modo, i client di questa classe avranno esito negativo? I clienti devono fare cose con questa classe mentre la classe ha già configurato A ma non B (essendo in uno stato parzialmente inizializzato)?

Se i client non sono realmente interessati, potrebbe accadere che la dipendenza dell'ordine possa essere rimossa in qualche modo riorganizzando il codice o unendo il codice di alcune funzioni in un'unica funzione .

Se i client non possono tollerarlo, allora in altri linguaggi di programmazione sarebbe un segnale che la classe sta facendo troppo lavoro e deve essere divisa in più classi.

Altre opzioni. In alcuni altri paradigmi di programmazione, ...

La classe potrebbe richiedere ai client di fornire istanze già inizializzate di A e B , invece di farlo all'interno della classe.

La classe può implementare l'inizializzazione pigra per A e B , cioè, posticipa l'inizializzazione fino a quando non può più farlo, quindi inizializzerà ciò che è necessario.

La classe potrebbe richiedere ai suoi clienti di fornire alcuni callback, il cui compito è quello di aiutare a inizializzare quelle cose. La classe ha il controllo dell'ordine di inizializzazione e ai clienti viene richiesto di seguire la scelta dell'ordine della classe e di fornire le informazioni di inizializzazione su richiesta.

    
risposta data 24.10.2015 - 03:22
fonte

Leggi altre domande sui tag