Devo lanciare un'eccezione in caso di un valore significativo al di fuori dell'intervallo o gestirlo da solo?

42

Ho scritto una struttura che rappresenta le coordinate di latitudine / longitudine. I loro valori vanno da -180 a 180 per le longitudini e da 90 a -90 per le lattitudini.

Se un utente di quella struttura mi dà un valore al di fuori di tale intervallo, ho 2 opzioni:

  1. Genera un'eccezione (arg fuori gamma)
  2. Converti il valore nel vincolo

Perché una coordinata di -185 ha un significato (può essere facilmente convertita in +175 come quelle polari), potrei accettarlo e convertirlo.

È meglio lanciare un'eccezione per dire all'utente che il suo codice mi ha dato un valore che non dovrebbe avere?

Modifica: conosco anche la differenza tra lat / lng e coordinate, ma volevo semplificarlo per facilitare la discussione - non era la più brillante delle idee

    
posta K. Gkinis 18.02.2016 - 12:11
fonte

8 risposte

51

Se il nucleo della tua domanda è questo ...

If some client code passes an argument whose value is invalid for the thing that my data structure is modeling, should I reject the value or convert it to something sensible?

... quindi la mia risposta generale sarebbe "rifiutare", perché ciò aiuterà a richiamare l'attenzione sui potenziali bug nel codice client che stanno effettivamente facendo apparire il valore non valido nel programma e raggiungono il costruttore. Attirare l'attenzione sui bug è generalmente una proprietà desiderata nella maggior parte dei sistemi, almeno durante lo sviluppo (a meno che non si tratti di una proprietà desiderata del tuo sistema per cavarsela in caso di errori).

La domanda è se stai effettivamente affrontando quel caso .

  • Se la struttura dei dati è concepita per modellare le coordinate polari in generale, quindi accettare il valore poiché gli angoli compresi nell'intervallo -180 e +180 non sono realmente validi. Sono perfettamente validi e hanno sempre un equivalente compreso tra -180 e +180 (e se vuoi convertirli per raggiungere quella fascia, sentiti libero - il codice cliente di solito non ha bisogno di attenzione) .

  • Se la struttura dei dati sta modellando in modo esplicito le coordinate di Web Mercator (secondo la domanda nella sua forma iniziale), allora è meglio seguire le disposizioni menzionate nella specifica (che non conosco, quindi ho vinto " t dire nulla a riguardo). Se la specifica della cosa che stai modellando dice che alcuni valori non sono validi, respingili. Se dice che possono essere interpretati come qualcosa di sensato (e quindi sono effettivamente validi), accettali.

Il meccanismo che usi per segnalare se i valori sono stati accettati o meno dipende dalle caratteristiche della tua lingua, dalla sua filosofia generale e dai tuoi requisiti di rendimento. Quindi, potresti lanciare un'eccezione (nel costruttore) o restituire una versione nullable della tua struct (tramite un metodo statico che richiama un costruttore privato) o restituire un booleano e passare la struct al chiamante come parametro out ( di nuovo attraverso un metodo statico che richiama un costruttore privato), e così via.

    
risposta data 18.02.2016 - 12:32
fonte
10

Dipende molto. Ma dovresti decidere di fare qualcosa e documentarlo .

L'unica cosa sicuramente sbagliata che il tuo codice deve fare è dimenticare di considerare che l'input dell'utente potrebbe essere al di fuori dell'intervallo previsto e scrivere codice che accidentalmente ha qualche comportamento. Perché alcune persone faranno un'assunzione errata su come si comporta il tuo codice e causeranno bug, mentre altri finiranno per a seconda del comportamento che il tuo codice ha accidentalmente (anche se tale comportamento è completamente disonesto) e quindi causerai più bug quando in seguito risolvi il problema.

In questo caso, posso vedere gli argomenti in entrambi i casi. Se qualcuno viaggia a +10 gradi da 175 gradi, dovrebbe arrivare a -175. Se si normalizza sempre l'input dell'utente e quindi si considera 185 come equivalente a -175, il codice client non può fare la cosa sbagliata quando aggiunge 10 gradi; ha sempre l'effetto giusto. Se trattate 185 come un errore, forzate ogni caso in cui il codice client sta aggiungendo gradi relativi per inserire la logica di normalizzazione (o almeno ricordate di chiamare la vostra procedura di normalizzazione), voi in realtà causate bug ( anche se speriamo sia facile catturarne uno che sarà rapidamente schiacciato). Ma se un numero di longitudine è immesso dall'utente, scritto letteralmente nel programma, o calcolato attraverso una procedura destinata a essere sempre in [-180, 180), un valore al di fuori di tale intervallo è molto probabile che indichi un errore, quindi "utile "convertirlo potrebbe nascondere problemi.

Il mio ideale in questo caso sarebbe probabilmente quello di definire un tipo che rappresenta il dominio corretto. Usa un tipo astratto (non lasciare che il codice client acceda semplicemente ai numeri grezzi al suo interno) e fornisca sia un factory normalizzante che un validatore (quindi il client può fare il compromesso). Ma qualunque sia il valore di questo tipo, 185 dovrebbe essere indistinguibile da -175 quando viene visto attraverso la tua API pubblica (non importa se sono convertiti in costruzione o fornisci uguaglianza, accessor e altre operazioni che ignorano in qualche modo la differenza) .

    
risposta data 19.02.2016 - 07:54
fonte
3

Se non ti interessa davvero scegliere una soluzione, puoi semplicemente lasciare decidere all'utente.

Dato che la tua struct è object valore readonly e creata da un metodo / costruttore, potresti fornire due overload in base alle opzioni che l'utente ha:

  • Genera un'eccezione (arg fuori gamma)
  • Converti il valore nel vincolo

Inoltre, non lasciare mai che l'utente abbia una struttura non valida per passare agli altri tuoi metodi, fallo subito alla creazione.

Modifica: in base ai commenti, presumo tu stia utilizzando c #.

    
risposta data 18.02.2016 - 13:22
fonte
0

Dipende se l'input è direttamente da un utente attraverso alcune UI, o dal sistema.

Immissione tramite un'interfaccia utente

È una domanda sull'esperienza utente come gestire input non validi. Non so del tuo caso specifico, ma in generale ci sono alcune opzioni:

  • Avvisa l'utente dell'errore e fallo correggere all'utente prima di procedere (il più comune)
  • Converti automaticamente nell'intervallo valido (se possibile), ma avvisa l'utente della modifica e consenti all'utente di verificare prima di procedere.
  • Converti silenziosamente nell'intervallo valido e continua.

La scelta dipende dalle aspettative degli utenti e dalla criticità dei dati. Ad esempio, Google aggiusta automaticamente l'ortografia nelle query, ma questo è a basso rischio perché una modifica inutile non è un problema ed è facile da correggere (e anche in questo caso viene reso chiaro sulla pagina dei risultati che la query è stata modificata). D'altra parte, se si inseriscono le coordinate per un missile nucleare, si potrebbe desiderare una convalida dell'input più rigida e nessuna correzione silenziosa di dati non validi. Quindi non esiste una risposta universale.

Soprattutto, dovresti considerare se correggere l'input ha anche un vantaggio per l'utente. Perché un utente immetterà dati non validi? È facile vedere come qualcuno potrebbe fare un errore di ortografia, ma perché qualcuno dovrebbe inserire una longitudine di -185? Se l'utente intendesse veramente +175, probabilmente avrebbero digitato +175. Penso che sia molto probabilmente che una longitudine non valida è semplicemente un errore di battitura, e l'utente intendeva -85 o qualcos'altro. In questo caso la conversione silenziosa è cattiva e inutile . L'approccio più user-friendly per la tua app sarebbe probabilmente quello di avvisare l'utente del valore non valido e farlo correggere da solo.

Input tramite un'API

Se l'input proviene da un altro sistema o sottosistema, non ci sono dubbi. Dovresti lanciare un'eccezione. Non si dovrebbe mai convertire in silenzio l'input non valido da un altro sistema, poiché potrebbe mascherare gli errori in altre parti del sistema. Se l'input è "corretto", dovrebbe avvenire nel livello dell'interfaccia utente, non in profondità nel sistema.

    
risposta data 23.02.2016 - 08:31
fonte
0

Dovresti lanciare un'eccezione.

Nell'esempio che hai fornito, inviando 185 e convertendolo in -175, potrebbe essere utile in alcuni casi fornire tale funzionalità. Ma cosa succede se il chiamante invia 1 milione? Intendono davvero per convertirlo? Sembra più probabile che si tratti di un errore. Quindi, se hai bisogno di generare un'eccezione per 1.000.000 ma non per 185, devi prendere una decisione su una soglia arbitraria per lanciare un'eccezione. Quella soglia ti farà inciampare nel momento in cui alcune app chiamanti inviano valori attorno alla soglia.

È meglio lanciare l'eccezione per i valori fuori dall'intervallo.

    
risposta data 24.02.2016 - 08:16
fonte
-1

L'opzione più conveniente per uno sviluppatore sarebbe un supporto di errore in fase di compilazione nella piattaforma, per valori fuori intervallo. In questo caso, l'intervallo dovrebbe anche far parte della firma del metodo, proprio come il tipo dei parametri. Allo stesso modo in cui il tuo utente API non può passare una Stringa se la tua firma del metodo è definita per prendere un numero intero , l'utente non avrebbe potuto passare un valore senza verificare se il valore è compreso nell'intervallo indicato nella firma del metodo. Se non selezionato, dovrebbe ottenere un errore in fase di compilazione e, quindi, l'errore di runtime potrebbe essere evitato.

Ma attualmente, pochi compilatori / piattaforme supportano questo tipo di controllo del tempo di compilazione. Quindi, è un mal di testa per gli sviluppatori. Idealmente, il tuo metodo dovrebbe solo generare un'eccezione significativa per i valori non supportati e documentarlo in modo chiaro.

A proposito, adoro il modello di errore proposto da Joe Duffy qui .

    
risposta data 19.02.2016 - 06:35
fonte
-1

L'impostazione predefinita dovrebbe essere quella di generare un'eccezione. Puoi anche consentire un'opzione come strict=false e fare la coercizione basata sul flag, dove ovviamente strict=true è il valore predefinito. Questo è abbastanza comune:

risposta data 19.02.2016 - 01:19
fonte
-2

Per me la migliore pratica è non modificare mai l'input dell'utente. L'approccio che prendo di solito è separare la convalida dall'esecuzione.

  • Avere una semplice classe che utilizza solo i parametri forniti.
  • Utilizzare un decoratore per fornire uno strato di convalida che può essere modificato a piacimento senza influire sulla classe di esecuzione (o altrimenti iniettare un validatore se questo approccio è troppo difficile).
risposta data 18.02.2016 - 18:28
fonte

Leggi altre domande sui tag