Limiti della programmazione difensiva riconoscendo che la gestione delle eccezioni dovrebbe essere evitata

1

Ho letto Programmazione difensiva vs Gestione delle eccezioni e se / else dichiarazioni o eccezioni , ma nessuno contiene qualcosa di rilevante per quello che sto cercando per.

Tenendo conto del fatto che la gestione delle eccezioni è più costosa della semplice progettazione del codice ed evitando certi scenari, di recente sono giunto alla seguente domanda: qual è la "soglia" della complessità computazionale su cui dovrebbe essere preferita la gestione delle eccezioni? p>

Nel mio caso, sto ricevendo i dati da un middleware esterno e alcune volte i campi sono nulli. Ci sono due casi in cui posso gestirlo.

prima

try {
    if (user.departNameEn.Equals(selectedUser) 
    || user.departNameFr.Equals(selectedUser) 
    || user.departNameDe.Equals(selectedUser)) {
        string fileName = AppDomain.CurrentDomain.BaseDirectory 
            + @"Images\Users\" + user.Id + user.ShortName + ".png";
        if (File.Exists(fileName))
        {
            retVal = fileName;
            return retVal;
        }
    }
}
catch (NullReferenceException e)
{
    continue;
}

Secondo

if (!string.IsNullOrEmpty(user.departNameEn)
    && !string.IsNullOrEmpty(user.departNameFr)
    && !string.IsNullOrEmpty(user.departNameDe)
    && !string.IsNullOrEmpty(user.Id)
    && !string.IsNullOrEmpty(user.ShortName)) {
    if (user.departNameEn.Equals(selectedUser) 
    || user.departNameFr.Equals(selectedUser) 
    || user.departNameDe.Equals(selectedUser)) {
        string fileName = AppDomain.CurrentDomain.BaseDirectory 
            + @"Images\Users\" + user.Id + user.ShortName + ".png";
        if (File.Exists(fileName))
        {
            retVal = fileName;
            return retVal;
        }
    }
}

Intuitivamente, il primo approccio è molto più pulito ed elegante del secondo, ma quale di questi è meno costoso dal punto di vista computazionale? Dove finiscono i limiti della programmazione difensiva?

Nota per duplicare il rapporto: come ho spiegato nell'introduzione, ho letto i due argomenti principali per Exception Handling vs Defensive Programming ma quello che sto chiedendo in realtà è qualcosa di diverso e molto specifico: quando la Programmazione difensiva diventa computazionalmente più costosa della semplice semplificazione del codice e l'aggiunta di una singola dichiarazione try-catch ?

    
posta Lefteris008 17.09.2018 - 09:32
fonte

5 risposte

12

I am receiving data from an external middleware

File.Exists

Quindi diamo un'occhiata al quadro generale. Hai dati. Questi dati erano serializzati . Quindi invia su un filo . Quindi deserializzato . E alla fine, anche accedi al file system in base a quei dati.

Considerare come gestirlo da una prospettiva di performance è completamente inutile, perché il potere di calcolo non è in realtà il collo di bottiglia di gran lunga nel proprio scenario. È come chiedersi se l'operatore subacqueo di un 18-ruote debba essere messo a dieta per risparmiare sul peso complessivo.

Per quanto riguarda la 18 a ruote: la soluzione migliore è lasciare che l'autista faccia ciò che lo rende felice e motivato a guidare il proprio camion. Una sterlina o due in entrambe le direzioni non contano davvero. Quindi fai ciò che è meglio per il programmatore. Qualunque sia il codice più leggibile e più facile da capire per i tuoi standard è la soluzione migliore qui.

Su una nota non correlata:

user.departNameEn.Equals(selectedUser)

c'è una ragione per cui chiami Equals o forse è solo una cattiva abitudine di Java?

user?.departNameEn == selectedUser

Questa linea fa lo stesso e non getterà su un lato essendo null . L'unico "svantaggio" sarebbe che se selectedUser è null è considerato uguale, invece di lanciare come nella tua linea.

    
risposta data 17.09.2018 - 10:12
fonte
7

Ti aspetti dati null?

Le eccezioni sono pensate per circostanze eccezionali.

La semplice regola empirica per situazioni come questa è gestire casi standard con logica, non con eccezioni.
Se un NULL è un errore, ad esempio indicando un errore di trasmissione, allora è adatta un'eccezione. Se, tuttavia, sta indicando che un campo facoltativo è vuoto, allora questo è un caso d'uso "normale" e dovrebbe essere controllato con la logica.

L'esempio utilizzato nella domanda implica che i dati non sono validi se mancano alcuni dati (e che ciò è inaspettato).
Vorrei raccomandare eccezioni in questo caso.

    
risposta data 17.09.2018 - 12:29
fonte
3

Questo dipende da più informazioni di quelle che ci dai. Cosa significa se alcuni campi sono nulli? È (1) totalmente ammissibile e dovrebbe essere interpretato come un valore di "" ? (2) non dovrebbe accadere ma comune nella pratica e suscettibile di una soluzione alternativa? (3) possibile trattare ma solo con l'input dell'utente? (4) un difetto che rende impossibile l'elaborazione di tale registrazione? (5) un segno di un tale serio problema che l'intera importazione deve essere abbandonata ("fermare e prendere fuoco")?

Le eccezioni non sono solo più costose da elaborare in fase di esecuzione, ma strutturano anche il flusso di controllo in modo diverso rispetto alle strutture di controllo standard. È possibile creare praticamente qualsiasi flusso logico possibile con le istruzioni di if , ma una volta che si lancia un'eccezione da un blocco non c'è un modo ragionevole per tornare di nuovo in esso, e le clausole di cattura annidate sono quasi impossibili da scrivere in modo leggibile. Inoltre, la programmazione di una try...catch solleva determinate aspettative nei lettori del codice; se questi non sono veri, questo rende il codice molto più difficile da capire. Questi sono almeno tre diversi aspetti della scelta di come gestire situazioni non comuni; altri possono essere applicati a seconda di cosa sta elaborando esattamente il codice.

    
risposta data 17.09.2018 - 09:41
fonte
1

I due esempi di codice non sono equivalenti logicamente.

Nel primo caso è sufficiente riempirlo e soddisfare la condizione. Nel secondo caso, tutti e tre devono essere non vuoti.

Questo a mio parere è la grande cosa perché dovresti andare per la prima versione. Hai reso il codice più complesso e hai finito con qualcos'altro allora inteso. Usa il codice che esprime il meglio di ciò che vuoi fare nel modo più facile da capire.

    
risposta data 17.09.2018 - 10:39
fonte
0

L'obiettivo della programmazione difensiva è controllare che tutto ciò che si desidera sia nello stato giusto prima di iniziare non il "Non voglio il modo eccezionalmente" di fare le cose.

Nel tuo caso: alcuni campi possono essere vuoti per definizione. Quindi nessun controllo per null è solo per evitare che NRE non sia una programmazione difensiva, è il modo normale di gestirlo.

Da parte mia la programmazione difensiva si basa principalmente sul lancio (in java) di IllegalStateException / IllegalArgumentException molto (quindi sono più in programmazione offensiva come definito per Wikipedia).

Inoltre il primo codice di esempio che fornisci per illustrare ciò che vuoi chiedere è definitivamente sbagliato in qualunque modo tu voglia andare: cathing a NullReferenceException è un no go. In questo modo, potresti prendere l'NRE che desideri ma se il codice si evolve, potresti anche catturare NRE indesiderati in particolare se in seguito tu o qualcun altro aggiorni il codice.

Infine, a parte il codice che hai citato, la mossa migliore è solo quella di cambiare il lato del tuo test: selectedUser.equals(...) perché probabilmente sei sicuro che a questo punto l'utente selezionato non è né nullo né vuoto. Questa non è una soluzione di programmazione difensiva, solo quello che dovresti fare per avere il codice più chiaro ed evitare errori indesiderati.

    
risposta data 17.09.2018 - 10:46
fonte

Leggi altre domande sui tag