Term (o "pattern"?) per "Fai qualcosa se non è già stato fatto" [chiuso]

53

Sembra abbastanza semplice, lo so, ma di recente un mio collega mi ha detto che un metodo chiamato startHttpServer è troppo complicato da comprendere perché avvia il server solo se non è già in esecuzione. Trovo di mettermi nei guai quando rispondo "Seriamente? Lo sto facendo da decenni - è un modello comune nella programmazione". Più spesso di quanto mi interessi ammettere che ritorna con alcune prove documentate che dimostrano che l'intera comunità di programmazione è dietro il suo punto di vista e finisco per sentirmi imbarazzato.

Domanda : esiste un modello di progettazione documentato dietro il concetto di un metodo che è un no-op se l'azione richiesta è già in vigore? Oppure, se non un modello, ha un nome? E se no, c'è qualche ragione per pensare che sia troppo complicato prendere in considerazione la scrittura di un metodo in questo modo?

    
posta John Calcote 27.08.2017 - 08:10
fonte

8 risposte

126

Come NickWilliams ha già detto : il concetto che l'OP descrive è chiamato idempotente (sostantivo Idempotenza ). È infatti una pratica comune, specialmente nelle API di alto livello.

BUT: rinomina la funzione.

Invece di startHttpServer chiamalo makeSureHttpServerIsRunning o ensureHttpServerIsRunning .

Quando una funzione è chiamata startHttpServer , i lettori si aspettano che avvii un server HTTP; quando chiamato dieci volte di seguito, avrò dieci server in esecuzione. La tua funzione non lo fa la maggior parte del tempo. Inoltre, il nome con "start" suggerisce che se voglio che solo un server sia in esecuzione dovrò tenere traccia di se la funzione è già stata chiamata o meno.

Quando una funzione è chiamata makeSureHttpServerIsRunning , presumo che farà le cose necessarie per assicurarsi che un server HTTP sia in esecuzione, molto probabilmente controllando se è già in esecuzione e avviandolo altrimenti. Suppongo anche che la funzione assicuri che il server sia effettivamente in esecuzione (l'avvio di un server potrebbe richiedere del tempo in cui non è ancora abbastanza in esecuzione).

    
risposta data 27.08.2017 - 09:45
fonte
32

Rinomina in EnsureServerRunning .

Completamente non ambiguo ed è chiaro che si assicura che sia in esecuzione (se non lo è) senza implicare un riavvio se lo è.

(alternativa: StartServerIfNotRunning ?)

    
risposta data 27.08.2017 - 13:26
fonte
28

Non proprio un modello di design, ma chiamerei il tuo metodo idempotent . Di solito viene utilizzato per riferirsi alle chiamate remote, ma la descrizione sembra corrispondere a ciò che si sta facendo.

Idempotent Methods. Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. (From W3.org)

L'effetto sul lato server è che il server http viene avviato una volta chiamato il metodo. Non vedo nulla di sbagliato con un metodo che lo fa.

Se hai bisogno di un modello di progettazione, immagino che potresti esporre il tuo httpServer come un singleton che viene avviato quando inizializzato.

    
risposta data 27.08.2017 - 09:12
fonte
7

Come colui che implementa questo strumento , startHttpServer , dovresti cercare di renderlo il più semplice, semplice e senza cuciture da usare ...

La logica della funzione

Tecnicamente, dividendo la logica di startHttpServer in 2 funzioni e chiamandole separatamente , tutto ciò che fai è in movimento startHttpServer 's idempotenza nel codice che chiama invece entrambe le funzioni ... Inoltre, a meno che non si avvolga la logica in una terza funzione ( che è ciò che fa startHttpServer al primo posto), questo ti obbliga a scrivere codice non modificato, duplicandolo esponenzialmente ovunque tu debba chiamare startHttpServer . In breve, startHttpServer deve chiamarsi la funzione isHttpServerRunning .

Quindi il mio punto è:

  • Implementa la funzione isHttpServerRunning perché potrebbe comunque essere necessaria indipendentemente ...
  • Implementa startHttpServer rendendolo utilizza isHttpServerRunning per definire la sua prossima azione di conseguenza ...

Ancora, puoi fare in modo che% co_de restituisca qualsiasi valore di cui può aver bisogno l'utente di questa funzione, ad esempio:

  • startHttpServer = > errore iniziale del server
  • 0 = > server che ha avuto successo
  • 1 = > il server era già stato avviato

La denominazione della funzione

Prima di tutto, qual è l'obiettivo principale dell'utente? Per avviare il server HTTP , giusto?

Fondamentalmente, non c'è alcun problema se si intende iniziare qualcosa che è già stato avviato, AKA 2 . Quindi, almeno per me, chiamarlo " 1*1=1 " non sembra necessario, mi interessa di più per quanto tempo, naturale e memorabile è il nome della funzione.

Ora se vuoi sapere come funziona in dettaglio la funzione sotto il cofano, c'è la documentazione o il codice sorgente per questo, intendo come per qualsiasi altra funzione da libreria / framework / API / etc ...

Sei impara la funzione una volta mentre scrivi più volte ...

Ad ogni modo, rimango con ensureHttpServerIsRunning che è più breve, più semplice e più esplicito di startHttpServer .

    
risposta data 27.08.2017 - 14:26
fonte
2

Suppongo che il tuo collega abbia inteso che startHttpServer sta facendo troppo:

  • Verifica se il server è già in esecuzione,
  • Avvio del server, se necessario.

Quelle sono due parti di codice non correlate. Ad esempio, esiste una situazione simile quando un'applicazione desktop dovrebbe garantire che non sia già in esecuzione al momento del lancio; ci sarà una parte di codice che gestisce le istanze delle app (ad esempio utilizzando un mutex) e il codice che avvierà il ciclo dei messaggi dell'applicazione.

Questo significa che non devi avere uno, ma almeno¹ due metodi :

  • isHttpServerRunning: boolean
  • startHttpServer

Il punto di ingresso dell'applicazione chiamerà il primo metodo, quindi il secondo se il valore restituito è false . Ora, ogni metodo sta facendo una cosa sola ed è facile da capire.

¹ Se la logica necessaria per sapere se il server è già in esecuzione è troppo complessa, potrebbe richiedere un'ulteriore separazione in più metodi.

    
risposta data 27.08.2017 - 08:53
fonte
2

Dato che non si specifica una lingua, in JavaScript molte librerie hanno una funzione "una sola volta" es Underscore . Quindi, se ti fosse familiare, chiamalo "una volta" e rinominando il tuo metodo.

Io stesso, venendo più da Java, mi vengono in mente i termini "caching" o "lazy evaluation". "Idempotent" è tecnicamente corretto e una buona scelta, esp. se hai uno sfondo più funzionale.

    
risposta data 28.08.2017 - 18:02
fonte
-2

Preferirei startHttpServerIfNotIsRunning .

In questo modo, la condizione è chiaramente menzionata già nel nome del metodo. Ensure o makeSure mi sembra un po 'vago, in quanto non è un'espressione tecnica. Sembra che non sappiamo esattamente cosa succederà.

    
risposta data 28.08.2017 - 10:24
fonte
-3

Ciò che il tuo collega avrebbe dovuto dirti è che non hai nessun business che scriva quel metodo. È già stato scritto molte volte e scritto meglio di quanto tu possa scrivere. Per esempio: link link

Da un punto di vista architettonico, avere un po 'di codice arbitrario per gestire un server web è roba da incubo. A meno che la gestione dei servizi sia esclusivamente ciò che fa il tuo codice. Ma suppongo che tu non abbia scritto monit (o kubernetes o ...).

    
risposta data 28.08.2017 - 18:10
fonte