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 latitudini.

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

  1. Lancia un'eccezione (arg fuori portata)
  2. Converti il ​​valore in vincolo

Poiché una coordinata di -185 ha un significato (può essere facilmente convertita in +175 in quanto sono coordinate polari), potrei accettarla e convertirla.

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

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


13
L'utente dovrebbe essere autorizzato a inserire un valore al di fuori dell'intervallo? Se la risposta è no, genera un'eccezione. Se le regole non sono così rigide, eseguire la conversione, ma dichiarare esplicitamente nella documentazione che la conversione potrebbe avvenire. Inoltre, tenere presente che in alcune lingue la gestione delle eccezioni è piuttosto costosa.
Andy,

C #, importa? Non supporta nativamente i vincoli se questo è ciò che intendi.
K. Gkinis,

2
Mi sembra abbastanza chiaro, quindi, l'approccio corretto consiste nel chiamare l'utente per inserire qualsiasi cosa al di fuori dell'intervallo e generare un'eccezione quando lo fanno (se lo standard dice che il valore degli addominali non deve essere superiore a 180, mettendo un valore maggiore di quello che è una chiara violazione). A proposito, C # è in realtà una delle lingue in cui le eccezioni sono piuttosto costose, quindi usale davvero solo in situazioni eccezionali, il che significa che non prenderle interromperà la tua applicazione, situazioni come questa.
Andy,

2
Tendo a stare lontano dal fare ipotesi su ciò che l'utente "intendeva" passando determinati valori di parametro, in particolare quelli che il mio codice non soddisfa. Sembra un caso simile.
JᴀʏMᴇᴇ,

2
Le coordinate di Web Mercator non vanno da -180 a 180 e da -90 a 90. Questa è latitudine / longitudine (e ci sono anche diversi sistemi di coordinate per questo). Le proiezioni di Mercatore sono in genere in centinaia di migliaia o milioni e hanno unità di "metri" (nemmeno rigorosamente, poiché la lunghezza di ciascuna unità copre l'aumento della distanza reale dal suolo quando ci si avvicina ai poli), non gradi. Anche in termini di gradi, è limitato a ± 85,051129 gradi perché la proiezione diventa infinitamente ampia ai poli. (Ho inviato una modifica per correggere questo, dal momento che non è il nocciolo della domanda.)
jpmc26

Risposte:


51

Se il nocciolo della tua domanda è questo ...

Se un codice client passa un argomento il cui valore non è valido per la cosa che la mia struttura dati sta modellando, dovrei rifiutare il valore o convertirlo in qualcosa di sensato?

... allora la mia risposta generale sarebbe "rifiutare", perché questo aiuterà ad attirare l'attenzione su potenziali bug nel codice client che stanno effettivamente facendo apparire il valore non valido nel programma e raggiungere il costruttore. Attirare l'attenzione sui bug è generalmente una proprietà desiderata nella maggior parte dei sistemi, almeno durante lo sviluppo (a meno che non sia una proprietà desiderata del sistema da confondere in caso di errori).

La domanda è se stai effettivamente affrontando quel caso .

  • Se la tua struttura di dati ha lo scopo di modellare le coordinate polari in generale, accetta il valore perché gli angoli al di fuori dell'intervallo -180 e +180 non sono realmente validi. Sono perfettamente validi e capita sempre che abbiano sempre un equivalente compreso tra -180 e +180 (e se vuoi convertirli in tale intervallo, sentiti libero - il codice client di solito non ha bisogno di cura) .

  • Se la tua struttura di dati sta modellando esplicitamente le coordinate di Web Mercator (secondo la domanda nella sua forma iniziale), allora è meglio seguire le disposizioni menzionate nelle specifiche (che non conosco, quindi non dirò nulla al 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 prestazione. Quindi, potresti lanciare un'eccezione (nel costruttore) o restituire una versione nullable della tua struttura (attraverso un metodo statico che invoca un costruttore privato) o restituire un valore booleano e passare la tua struttura al chiamante come outparametro (di nuovo tramite un metodo statico che richiama un costruttore privato) e così via.


12
Una longitudine al di fuori dell'intervallo da -180 a +180 dovrebbe probabilmente essere considerata accettabile, ma la latitudine al di fuori dell'intervallo da -90 a +90 sembrerebbe senza senso. Una volta che si raggiunge il Polo Nord o Sud, ulteriori viaggi verso nord o sud non sono definiti.
supercat,

4
@supercat Tendo ad essere d'accordo con te, ma dal momento che non so quali valori non siano effettivamente validi nelle specifiche di Web Mercator, sto cercando di non trarre alcuna conclusione difficile. L'OP conosce il dominio problematico meglio di me.
Theodoros Chatzigiannakis,

1
@supercat: inizia dove il meridiano raggiunge l'equatore. viaggiare lungo il meridiano in base alla latitudine. Se la latitudine è> 90, continua a seguire lo stesso grande cerchio. Nessun problema. Documentalo e lascia il resto al cliente.
Kevin Cline,

4
@supercat È peggio di così. Nella proiezione di Web Mercator, ± 90 viene effettivamente proiettato su una larghezza infinita. Quindi lo standard effettivamente lo interrompe a ± 85.051129. Inoltre, lat / long! = Coordinate del web mercator. Le coordinate di Mercatore usano una variazione di metri, non gradi. (Man mano che ci si avvicina ai poli, ogni "metro" corrisponde effettivamente a un pezzo di terra sempre più grande.) Le coordinate dei PO sono puramente lat / long. Web Mercator non ha nulla a che fare con loro, tranne che potrebbero essere visualizzati in cima a una mappa di base di Web Mercator e una libreria spaziale sta proiettando sotto di loro.
jpmc26,

1
Dovrei dire "l'equivalente di ± 85.051129", poiché questa non è la coordinata effettiva.
jpmc26,

10

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

L'unica cosa assolutamente sbagliata da fare per il tuo codice è dimenticare di considerare che l'input dell'utente potrebbe essere al di fuori dell'intervallo previsto e scrivere il codice che ha un comportamento accidentale. Perché allora alcune persone faranno un'ipotesi errata su come si comporta il tuo codice e causerà bug, mentre altri finiranno a seconda del comportamento che il tuo codice ha accidentalmente (anche se quel comportamento è completamente disordinato) e quindi causerai più bug quando in seguito risolverai il problema.

In questo caso posso vedere gli argomenti in entrambi i modi. Se qualcuno viaggia +10 gradi da 175 gradi, dovrebbe finire a -175. Se normalizzi sempre l'input dell'utente e tratti 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 da inserire nella logica di normalizzazione (o almeno ricordate di chiamare la vostra procedura di normalizzazione), in realtà causeretebug (anche se si spera sia facile catturare quelli che verranno rapidamente schiacciati). Ma se un numero di longitudine viene inserito dall'utente, scritto letteralmente nel programma o calcolato attraverso una procedura intesa sempre in [-180, 180), è molto probabile che un valore al di fuori di tale intervallo indichi un errore, quindi "utile "convertirlo potrebbe nascondere problemi.

Il mio ideale in questo caso sarebbe probabilmente quello di definire un tipo che rappresenti il ​​dominio corretto. Usa un tipo astratto (non lasciare che il codice client acceda semplicemente ai numeri non elaborati al suo interno) e fornisci sia una fabbrica normalizzante che una validatrice (in modo che il client possa effettuare il compromesso). Ma qualunque sia il valore di questo tipo, 185 dovrebbe essere indistinguibile da -175 quando visto attraverso l'API pubblica (non importa se sono convertiti in costruzione o se si forniscono uguaglianza, accessori e altre operazioni che ignorano in qualche modo la differenza) .


3

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

Dato che la tua struttura è di sola lettura e creata da un metodo / costruttore, potresti fornire due sovraccarichi in base alle opzioni che l'utente ha:

  • Lancia un'eccezione (arg fuori portata)
  • Converti il ​​valore in vincolo

Inoltre, non lasciare che l'utente abbia una struttura non valida per passare ad altri metodi, rendilo giusto alla creazione.

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


Grazie per l'input! Ci penserò, anche se temo che minerebbe lo scopo del costruttore che lancia l'eccezione, se uno potesse evitarlo. È interessante però!
K. Gkinis,

Se hai intenzione di utilizzare questa idea, sarebbe meglio definire un'interfaccia e avere due implementazioni che generano o convertono. Sarebbe difficile sovraccaricare un costruttore in un modo ragionevole per funzionare come hai descritto.

2
@Snowman: Sì, sarebbe difficile sovraccaricare un costruttore con gli stessi tipi di argomenti, ma non sarebbe difficile avere due metodi statici e un costruttore privato.
mercoledì

1
@ K.Gkinis: lo scopo del costruttore di eccezioni non è "assicurarsi che l'applicazione muoia", dopotutto, il client può sempre le catchtue eccezioni. Come altri hanno già detto, è per consentire al cliente di limitarsi se lo desidera. Non stai davvero eludendo nulla.
mercoledì

Questo suggerimento complica il codice senza alcun vantaggio. Il metodo dovrebbe convertire input non validi oppure no. Avere due sovraccarichi rende il codice più complesso senza risolvere il dilemma.
Jacques B

0

Dipende se l'input proviene direttamente da un utente tramite un'interfaccia utente o dal sistema.

Input attraverso un'interfaccia utente

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

  • Avvisare l'utente dell'errore e chiedere all'utente di risolverlo prima di procedere (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 procedi.

La scelta dipende dalle aspettative dei tuoi utenti e dalla criticità dei dati. Ad esempio, Google corregge automaticamente l'ortografia nelle query, ma questo è a basso rischio perché una modifica non utile non è un problema ed è facile da risolvere (e anche in questo caso nella pagina dei risultati viene chiarito che la query è stata modificata). D'altra parte, se si stanno inserendo 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.

Ancora più importante, dovresti considerare se la correzione dell'input ha anche un vantaggio per l'utente. Perché un utente dovrebbe inserire dati non validi? È facile vedere come qualcuno potrebbe commettere un errore di ortografia, ma perché qualcuno dovrebbe inserire una longitudine di -185? Se l'utente intendesse davvero +175 probabilmente avrebbero digitato +175. Penso che sia molto probabile che una longitudine non valida sia semplicemente un errore di battitura, e l'utente intendesse -85 o qualcos'altro. In questo caso la conversione silenziosa è dannosa e inutile . L'approccio più intuitivo 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 c'è dubbio. Dovresti lanciare un'eccezione. Non si dovrebbe mai silenzioso convertire input non validi da un altro sistema, poiché potrebbe mascherare errori altrove nel sistema. Se l'input viene "corretto", dovrebbe avvenire nel livello dell'interfaccia utente, non più in profondità nel sistema.


0

Dovresti lanciare un'eccezione.

Nell'esempio che hai fornito, inviando 185 e convertendolo in -175, in alcuni casi potrebbe essere utile fornire tale funzionalità. E se il chiamante invia 1 milione? Intendono davvero convertirlo? Sembra più probabile che sia un errore. Quindi, se devi lanciare un'eccezione per 1.000.000 ma non per 185, devi prendere una decisione su una soglia arbitraria per lanciare un'eccezione. Tale soglia ti farà inciampare qualche volta mentre alcune app chiamanti inviano valori intorno alla soglia.

Meglio gettare l'eccezione per i valori fuori dall'intervallo.


-1

L'opzione più conveniente per uno sviluppatore sarebbe un supporto per errori di compilazione nella piattaforma, per valori fuori range. In questo caso, anche l'intervallo dovrebbe far parte della firma del metodo, proprio come il tipo di parametri. Allo stesso modo in cui l'utente API non può passare una stringa se la firma del metodo è definita per assumere un numero intero , l'utente non avrebbe dovuto essere in grado di passare un valore senza verificare se il valore rientra nell'intervallo indicato nella firma del metodo. Se non selezionato, dovrebbe ricevere un errore di tempo di compilazione e, quindi, l'errore di runtime potrebbe essere evitato.

Ma attualmente, pochissimi compilatori / piattaforme supportano questo tipo di controllo del tempo di compilazione. Quindi, è un mal di testa per gli sviluppatori. Ma idealmente, il tuo metodo dovrebbe semplicemente generare un'eccezione significativa per i valori non supportati e documentarlo chiaramente.

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


Come forniresti errori di compilazione per l'input dell'utente?
Jacques B

@JacquesB Il compilatore genererà un errore se l'input dell'utente non viene controllato per essere compreso nell'intervallo dopo l'inserimento, indipendentemente dal valore effettivo compreso nell'intervallo.
Gulshan,

Ma poi devi ancora decidere se vuoi rifiutare l'input o convertirlo in un intervallo valido, quindi questo non risponde alla domanda originale.
Jacques B

@JacquesB Dovrei dire questo, all'inizio, ho sempre pensato che OP sta sviluppando un'API e l'interfaccia utente è stata sviluppata da qualcun altro, consumando la sua API. Ho sbagliato su questo punto. Ho appena letto di nuovo la domanda e me ne sono reso conto. Tutto quello che sto cercando di dire è che la convalida dovrebbe essere fatta ai consumatori API e, in caso contrario, il compilatore dovrebbe generare un errore.
Gulshan,

Quindi ... devi creare una nuova classe che contenga input e convalida. Annnnnd quando costruisci l'oggetto di classe dagli input grezzi, cosa succede? Generare un'eccezione? Passa silenziosamente? Basta spostare il problema.
Djechlin,

-1

L'impostazione predefinita dovrebbe essere lanciare un'eccezione. Potresti anche consentire un'opzione simile strict=falsee fare la coercizione in base alla bandiera, dove ovviamente strict=trueè l'impostazione predefinita. Questo è abbastanza comune:

  • Java DateFormatsupporta lenient .
  • Il parser JSON di Gson supporta anche una modalità clemente .
  • Eccetera.

Ciò complica il codice senza alcun vantaggio.
Jacques B

@JacquesB genera un'eccezione per impostazione predefinita o consente strict=false?
Djechlin,

@JacquesB Ho aggiunto alcuni esempi di API che supportano le modalità rigide e indulgenti, per favore dai un'occhiata.
Djechlin,

-2

Per me la migliore pratica è di non cambiare mai l'input dell'utente. L'approccio che di solito seguo è quello di separare la validazione dall'esecuzione.

  • Avere una classe semplice che utilizza solo i parametri indicati.
  • Utilizzare un decoratore per fornire un livello di convalida che può essere modificato a piacimento senza influire sulla classe di esecuzione (oppure iniettare un validatore se questo approccio è troppo difficile).

L '"utente" a cui si riferisce la domanda è lo sviluppatore che utilizza l'API, non l'utente finale ...
Jay Elston,
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.