Qual è il modello di progettazione "Correggi tutto"?


74

In questo articolo del 2003 di Stephen Figgins su linuxdevcenter.com , BitTorrent di Bram Cohen viene descritto come usando il modello di progettazione "Correggi tutto".

Un approccio meno comune che rende BitTorrent più difficile da comprendere, ma degno di studio, è l'uso dell'idempotenza da parte di Cohen. Un processo è idempotente quando lo si applica più di una volta non provoca ulteriori modifiche. Cohen afferma di utilizzare un modello di progettazione che chiama "Correggi tutto", una funzione in grado di reagire a una serie di modifiche senza accorgersi davvero di ciò che potrebbe cambiare. Spiega, "noti l'evento che è successo, quindi chiama la funzione di correzione di tutto ciò che è scritto in questo modo molto idempotente, e pulisce tutto ciò che potrebbe succedere e ricalcola tutto da zero". Mentre l'idempotenza semplifica alcuni calcoli difficili, rende le cose un po 'contorte. Non è sempre chiaro cosa cambierà una chiamata, se non altro. Non è necessario sapere in anticipo. Sei libero di chiamare la funzione,

Sembra abbastanza carino.

Tuttavia, mi sembra che chiamare una funzione idempotente di "aggiustare tutto" migliorerebbe la robustezza del sistema a costo dell'efficienza e potenzialmente rovinerebbe il sistema di contenimento (che potrebbe preferire processi che pianificano ed eseguono con cura).

Non posso dire di averlo usato prima, però. Inoltre non riesco a trovare la fonte per la sua applicazione online (ma ho trovato questo che afferma di essere basato su di esso.). Né posso trovare riferimenti ad esso al di fuori di questo articolo (e considero il mio google-fu abbastanza buono) ma ho trovato una voce per "Idempotent Capability" su SOApatterns.org .

Questa idea è meglio conosciuta con un altro nome?

Qual è il modello di progettazione "Correggi tutto"? Quali sono i suoi pro e contro?


4
Sospetto che il nome sia anche un riferimento all'idea del punto fisso di una funzione, x = f (x). Non importa quante volte applichi f a x , il risultato è lo stesso. Una volta ottenuto il risultato corretto, la rielaborazione del risultato corretto restituisce lo stesso risultato corretto.
9000,

7
Nota che chiunque può dare un nome a tutto ciò che vuole, ma ciò non lo rende un modello software ben noto. L'idempotenza è un concetto ben noto a sé stante; sembra solo che venga utilizzato in modo creativo qui.
Robert Harvey,

1
Questo mi ricorda come è stato implementato il Main Event Loop su Mac OS. Era una singola funzione che rispondeva a qualsiasi evento ed era generalmente strutturata per testare lo stato di tutti i controlli e aggiornare l'intera UI secondo necessità. Idempotente, davvero.
Lucas,

3
This sounds quite nice on the face of it. Veramente? Mi sembra orribile!
Michael,

3
@Michael Non ti piacciono i gestori di pacchetti? Funzionano con lo stesso concetto, solo su una scala più piccola: Contrassegna l'aspetto del sistema, esegui "correggi tutto", installa / rimuove / aggiorna in modo appropriato, ma ha solo qualcosa da fare in caso di modifiche.
Izkata,

Risposte:


100

Supponiamo che tu abbia una pagina HTML piuttosto complicata: se scegli qualcosa in un menu a discesa, potrebbe apparire un altro controllo o i valori in un terzo controllo potrebbero cambiare. Ci sono due modi in cui puoi avvicinarti a questo:

  1. Scrivere un gestore separato, per ogni controllo, che risponda agli eventi su quel controllo e aggiorna altri controlli secondo necessità.

  2. Scrivi un unico gestore che controlla lo stato di tutti i controlli nella pagina e risolve tutto .

La seconda chiamata è "idempotente" perché è possibile richiamarla più volte e i controlli saranno sempre disposti correttamente. Considerando che le prime chiamate possono avere problemi se una chiamata viene persa o ripetuta, ad esempio se uno dei gestori esegue un interruttore.

La logica per la seconda chiamata sarebbe un po 'più oscura, ma devi solo scrivere un gestore.

E puoi sempre usare entrambe le soluzioni, chiamando la funzione "aggiusta tutto" secondo necessità "solo per essere al sicuro".

Il secondo approccio è particolarmente utile quando lo stato può provenire da origini diverse, ad esempio dall'input dell'utente rispetto al rendering dal server. In ASP.NET, la tecnica gioca molto bene con il concetto di postback perché esegui semplicemente la funzione fix tutto ogni volta che esegui il rendering della pagina.

Ora che ho menzionato la perdita o la ripetizione di eventi e il riconoscimento dello stato da diverse fonti, sto pensando che sia ovvio come questo approccio si associ bene a uno spazio problematico come quello di BitTorrent.

Contro? Bene, l'ovvio svantaggio è che c'è un successo in termini di prestazioni perché è meno efficiente ripassare tutto tutto il tempo. Ma una soluzione come BitTorrent è ottimizzata per ridimensionare, non ridimensionare, quindi va bene per quel genere di cose. A seconda del problema che stai cercando di risolvere, potrebbe non essere adatto a te.


9
Mi sembra che MVC sia tipico di "Correggi tutto": quando modifichi il modello e ridisegni la vista da zero, la vista viene semplicemente ridisegnata, senza tentare di indovinare quali parti potrebbero potenzialmente influenzare l'azione.
Matthieu M.

3
Questo suona essenzialmente come il principio alla base di sistemi come Saltstack, Ansible e Nix. Data una descrizione di una configurazione, è possibile teoricamente portare diversi sistemi diversi nello stesso stato finale.
Kojiro,

1
@MatthieuM. React , che è abbastanza popolare nello sviluppo di frontend, è così tranne che fa il dom virtuale diff diffondendo quindi aggiorna solo il dom reale con le modifiche effettive
Izkata

2
@Izkata Anche più di React, questa risposta mi ha fatto pensare a Redux.
Kevin,

2
Potrebbe essere utile sottolineare che "aggiustare tutto" e idempotente sono cose diverse: "aggiustare tutto" è di solito idempotente (ma non ha bisogno di esserlo), e le operazioni idempotenti non hanno bisogno di aggiustare tutto o persino di esibirsi penalità: basta dare lo stesso risultato se eseguito due volte.
Hans-Peter Störr,

15

Penso che l'articolo sia un po 'datato perché, mentre lo leggo, questa non è affatto un'idea non ortodossa o nuova. Questa idea è presentata come un modello separato quando in realtà è solo una semplice implementazione di Observer. Ripensando a quello che stavo facendo in quel momento, ricordo di aver lavorato sulla logica per sedermi dietro un'interfaccia piuttosto complessa con un numero di pannelli diversi con dati interdipendenti. L'utente potrebbe modificare i valori e / o eseguire una routine di ottimizzazione e sulla base di tali azioni, sono stati generati eventi che l'interfaccia utente avrebbe ascoltato e aggiornato secondo necessità. Durante lo sviluppo c'erano diversi problemi in cui alcuni pannelli non si aggiornavano quando avrebbero dovuto. La correzione (rimanendo all'interno del progetto) era generare eventi da altri eventi. Alla fine, quando tutto funzionava bene, quasi ogni modifica ha comportato l'aggiornamento di tutti i pannelli. Tutta la complessità del tentativo di isolare quando un determinato pannello doveva essere aggiornato era nulla. E non importava comunque. È stata effettivamente un'ottimizzazione prematura. Avrei risparmiato un sacco di tempo e fatica semplicemente facendo crollare tutto in un singolo evento che ha rinfrescato tutto.

Esistono innumerevoli sistemi progettati nel "aggiustare tutto" o aggiornare tutto in modo. Pensa a tutte le interfacce CRUD che aggiungono / aggiornano una riga e quindi richiedono il DB. Questo non è un approccio esotico, è solo l'ovvia soluzione non intelligente. Bisogna rendersi conto che nel 2003, era l'altezza della "febbre modello". Da quello che ho potuto dire, la gente pensava che nominare nuovi modelli sarebbe stato il loro percorso verso la fama e la ricchezza. Non fraintendetemi, penso che il concetto di modello sia estremamente utile per descrivere soluzioni in astratto. Le cose sono andate un po 'fuori dai binari. È sfortunato perché ha creato molto cinismo sul concetto di modello in generale. È solo in questo contesto che ha senso parlarne come una soluzione "non ortodossa". E' s simile all'ortodossia attorno agli ORM o ai contenitori DI. Non usarli è visto come non ortodosso anche se le persone avevano sviluppato software molto prima che esistessero questi strumenti e in molti casi quegli strumenti sono eccessivi.

Quindi torniamo a "aggiustare tutto". Un semplice esempio è il calcolo dei mezzi. La soluzione semplice è sommare i numeri e dividerli per la cardinalità dei valori. Se aggiungi o modifichi un numero, lo fai di nuovo dall'inizio. È possibile tenere traccia della somma e del conteggio dei numeri e quando qualcuno aggiunge un numero, si aumenta il conteggio e lo si aggiunge alla somma. Ora non stai aggiungendo nuovamente tutti i numeri. Se hai mai lavorato con Excel con una formula che fa riferimento a un intervallo e ha modificato un singolo valore in quell'intervallo, hai un esempio del modello 'aggiusta tutto', ovvero qualsiasi formula che ha un riferimento a quell'intervallo verrà ricalcolata indipendentemente dal fatto che quel valore era rilevante (ad esempio usando qualcosa come sumif ()).

Questo non vuol dire che non sia una scelta intelligente in un determinato contesto. Nell'esempio medio, supponiamo che ora dobbiamo supportare gli aggiornamenti. Ora ho bisogno di conoscere il vecchio valore in qualche modo e cambiare la somma solo con il delta. Niente di tutto questo è davvero così impegnativo finché non si considera di provare a farlo in un ambiente distribuito o concorrente. Ora devi gestire tutti i tipi di problemi di tempistica spinosi e probabilmente finirai per creare un grosso collo di bottiglia che rallenta le cose molto più del ricalcolo.

Il risultato qui è che l'approccio "aggiusta tutto" o "aggiorna tutto" è molto più facile da ottenere. Puoi far funzionare un approccio più sofisticato, ma è molto più complicato e quindi più probabile che sia imperfetto. Inoltre, in molti contesti, l'approccio "aggiorna tutto" può essere più efficiente. Ad esempio, gli approcci di copia su scrittura sono generalmente più lenti per gli approcci a thread singolo ma quando si ha una concorrenza elevata, può consentire di evitare blocchi e quindi fornire prestazioni migliori. In altri casi, può consentire di raggruppare le modifiche in modo efficiente. Quindi, per la maggior parte dei problemi, probabilmente vuoi iniziare con un approccio di aggiornamento di tutto, a meno che tu non abbia un motivo specifico per cui non puoi farlo e quindi preoccuparti di fare qualcosa di più complesso quando ne hai bisogno.


2
Sono abbastanza sicuro che Excel intende ricalcolare solo le celle dipendenti dalle modifiche, motivo per cui c'è un modo per attivare tutte le celle per ricalcolare: superuser.com/questions/448376/… (che suppongo sarebbe un "aggiustare tutto" )
Aaron Hall,

@AaronHall In caso affermativo, si tratta di un'implementazione davvero pessima. Lo guardo regolarmente consumare il 100% di 7 CPU per 15-30 minuti per calcolare ad esempio 60.000 celle. I calcoli non sono complicati. Ho spesso scritto programmi Python che possono fare tutto nel foglio in pochi secondi incluso l'avvio di Python. Questa è stata la mia ipotesi migliore su come potrebbe richiedere così tanto tempo. Potrebbe essere qualcos'altro, suppongo. Ci sono anche molti bug molto vecchi in Excel che potrebbero essere la ragione di quella caratteristica.
JimmyJames,

1
@AaronHall è anche possibile con quell'utente che il calcolo automatico è stato disabilitato sul foglio. Lo faccio spesso su grandi cartelle di lavoro perché non ho 15 minuti da perdere ogni volta che premo invio.
JimmyJames,

@AaronHall Ho pensato un po 'di più e hai ragione. Le mie ipotesi erano probabilmente eccessivamente ampie. Ho aggiornato la risposta per me più focalizzata su qualcosa in cui sono più fiducioso.
JimmyJames

2
@JimmyJames: Il punto che intendevo sottolineare è che l'approccio migliore può variare molto a seconda delle circostanze, e "riparare tutto" può essere suddiviso in "aggiustare avidamente tutto su ogni singolo cambiamento" e "riparare pigramente tutto dopo che tutte le modifiche sono state completate ".
supercat,

4

Non sono sicuro che si tratti di un "modello di progettazione", ma classificherei quel tipo di comportamento come configurazione dello stato finale o configurazione dello stato desiderato , sulla scia di Puppet, Chef o Powershell DSC.

Queste soluzioni in genere operano a livello di gestione dei sistemi, non a livello di logica aziendale come descritto nella domanda, ma è effettivamente lo stesso paradigma e sebbene tali strumenti siano di solito dichiarativi in ​​natura, gli stessi principi possono essere applicati nel codice procedurale o negli script.


1

L'ho usato principalmente nelle interfacce utente. La cosa bella è che lo scrivi una volta e gestisce ugualmente bene tutto dal caso più semplice al più difficile (ad esempio se l'utente ruota lo schermo o su un laptop / desktop se l'utente ridimensiona una finestra e praticamente tutto cambia ).

Non ci sono molte ragioni per preoccuparsi dell'efficienza. Nell'interfaccia utente, le cose costose sono cose come ridisegnare un oggetto che è stato spostato. Il calcolo di dove va ogni articolo e quanto è grande è di solito abbastanza veloce. Tutto quello che devi assicurarti è che ogni volta che scopri che un oggetto dovrebbe rimanere esattamente nel posto in cui appartiene, nessun codice viene eseguito per spostarlo. I veri cambiamenti sono tutte cose che dovevi fare comunque.


0

Sembra principi di programmazione reattiva. "Correggi tutto" esamina l'attuale stato "core" e propaga tutto ciò che dovrebbe essere interessato - "stati calcolati". Se si ottimizza questa derivazione, può raggiungere un'alta efficienza, a la React, se eseguita in modo ingenuo le prestazioni potrebbero non essere ottimali, anche se potrebbero essere abbastanza veloci.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.