Le eccezioni come flusso di controllo sono considerate un serio antipattern? In tal caso, perché?


129

Alla fine degli anni '90 ho lavorato parecchio con una base di codice che utilizzava le eccezioni come controllo di flusso. Ha implementato una macchina a stati finiti per gestire le applicazioni di telefonia. Ultimamente mi vengono in mente quei giorni perché ho fatto app Web MVC.

Entrambi hanno Controllers che decidono dove andare dopo e forniscono i dati alla logica di destinazione. Le azioni dell'utente dal dominio di un telefono di vecchia scuola, come i toni DTMF, sono diventate parametri dei metodi di azione, ma invece di restituire qualcosa di simile a ViewResult, hanno lanciato a StateTransitionException.

Penso che la differenza principale fosse che i metodi di azione erano voidfunzioni. Non ricordo tutte le cose che ho fatto con questo fatto, ma sono stato titubante anche solo a ricordare molto perché da quel lavoro, come 15 anni fa, non l'ho mai visto nel codice di produzione in nessun altro lavoro . Ho pensato che questo fosse un segno che era un cosiddetto anti-schema.

È questo il caso e, in caso affermativo, perché?

Aggiornamento: quando ho posto la domanda, avevo già in mente la risposta di @ MasonWheeler, quindi sono andato con la risposta che ha aggiunto di più alla mia conoscenza. Penso che anche la sua sia una risposta valida.



25
No. In Python, l'utilizzo delle eccezioni come flusso di controllo è considerato "pythonic".
user16764

4
Se dovessi fare una cosa del genere in Java, di certo non farei eccezione. Deriverei da una gerarchia non-eccezione, non errore, gettabile.
Thomas Eding,

2
Per aggiungere alle risposte esistenti, ecco una breve guida che mi ha servito bene: - Non usare mai le eccezioni per "il percorso felice". Il percorso felice può essere sia (per il web) l'intera richiesta, sia semplicemente un oggetto / metodo. Tutte le altre regole sane si applicano ancora, ovviamente :)
Houen

8
Le eccezioni non controllano sempre il flusso di un'applicazione?

Risposte:


109

C'è una discussione dettagliata di questo sul Wiki di Ward . In generale, l'uso di eccezioni per il controllo di flusso è un anti-modello, con molte notevoli situazione - e il linguaggio specifico (si veda ad esempio, Python ) tosse eccezioni tosse .

Come una breve sintesi del perché, generalmente, è un anti-pattern:

  • Le eccezioni sono, in sostanza, sofisticate dichiarazioni GOTO
  • La programmazione con eccezioni, quindi, rende più difficile leggere e comprendere il codice
  • La maggior parte delle lingue ha strutture di controllo esistenti progettate per risolvere i tuoi problemi senza l'uso di eccezioni
  • Gli argomenti per l'efficienza tendono ad essere discutibili per i compilatori moderni, che tendono ad ottimizzare ipotizzando che le eccezioni non vengano utilizzate per il flusso di controllo.

Leggi la discussione sul wiki di Ward per informazioni molto più approfondite.


Vedi anche un duplicato di questa domanda, qui


18
La tua risposta fa sembrare che le eccezioni siano dannose per tutte le circostanze, mentre la domanda si concentra sulle eccezioni come controllo del flusso.
whatsisname

14
@MasonWheeler La differenza è che i cicli for / while contengono chiaramente le modifiche al controllo del flusso e rendono il codice facile da leggere. Se vedi un'istruzione for nel tuo codice, non devi provare a capire quale file contiene la fine del ciclo. I Goto non sono cattivi perché alcuni dei dio hanno detto che lo erano, sono cattivi semplicemente perché sono più difficili da seguire rispetto ai costrutti loop. Le eccezioni sono simili, non impossibili ma abbastanza difficili da confondere le cose.
Bill K

24
@BillK, poi argomenta, e non fare dichiarazioni semplicistiche su come le eccezioni sono goto.
Winston Ewert,

6
Va bene, ma seriamente, che succede agli sviluppatori lato server e agli app seppellire gli errori con dichiarazioni di cattura vuote nel JavaScript? È un brutto fenomone che mi è costato molto tempo e non so come chiedere senza rantolare. Gli errori sono tuoi amici.
Erik Reppen,

12
@mattnz: ife foreachsono anche sofisticati GOTOs. Francamente, penso che il confronto con goto non sia utile; è quasi come un termine dispregiativo. L'uso di GOTO non è intrinsecamente malvagio - ha problemi reali e le eccezioni potrebbero condividerli, ma potrebbero non esserlo . Sarebbe più utile ascoltare questi problemi.
Eamon Nerbonne,

110

Il caso d'uso per cui sono state progettate le eccezioni è "Ho appena incontrato una situazione che non posso affrontare correttamente a questo punto, perché non ho abbastanza contesto per gestirlo, ma la routine che mi ha chiamato (o qualcosa di più lungo la chiamata stack) dovrebbe sapere come gestirlo ".

Il caso d'uso secondario è "Ho appena riscontrato un errore grave e in questo momento uscire da questo flusso di controllo per prevenire la corruzione dei dati o altri danni è più importante che cercare di continuare".

Se non stai usando le eccezioni per uno di questi due motivi, probabilmente c'è un modo migliore per farlo.


18
Questo non risponde alla domanda però. Ciò per cui sono stati progettati è irrilevante; l'unica cosa rilevante è il motivo per cui usarli per il flusso di controllo è negativo, che è un argomento che non hai toccato. Ad esempio, i modelli C ++ sono stati progettati per una cosa, ma sono perfettamente adatti per la metaprogrammazione, un uso che i progettisti non hanno mai previsto.
Thomas Bonini,

6
@Krelp: I ​​progettisti non hanno mai anticipato molte cose, come finire con un sistema di template completo di Turing per caso! I template C ++ non sono certo un buon esempio da usare qui.
Mason Wheeler

15
@Krelp - I modelli C ++ NON sono "perfettamente perfetti" per la metaprogrammazione. Sono un incubo fino a quando non li capisci bene, e quindi tendono al codice di sola scrittura se non sei un genio del modello. Potresti voler scegliere un esempio migliore.
Michael Kohne,

Le eccezioni danneggiano in particolare la composizione delle funzioni e la brevità del codice in generale. Ad esempio, mentre ero inesperto, ho usato un'eccezione in un progetto, e questo ha causato problemi per molto tempo, perché 1) le persone devono ricordarsi di prenderlo, 2) non puoi scrivere const myvar = theFunctionperché myvar deve essere creato da try-catch, quindi non è più costante. Ciò non significa che non lo uso in C # in quanto è un mainstream lì per qualsiasi motivo, ma sto cercando di ridurli comunque.
Ciao Angelo

2
@AndreasBonini Cosa sono progettati / destinati agli argomenti perché ciò porta spesso a decisioni di implementazione di compilatore / framework / runtime in linea con il design. Ad esempio, lanciare un'eccezione può essere molto più "costoso" di un semplice ritorno perché raccoglie informazioni destinate ad aiutare qualcuno a eseguire il debug del codice come tracce dello stack, ecc.
binki

29

Le eccezioni sono potenti come Continuations e GOTO. Sono un costrutto di flusso di controllo universale.

In alcune lingue, sono l' unico costrutto del flusso di controllo universale. JavaScript, ad esempio, non ha né Continuazioni né GOTO, neppure ha chiamate di coda adeguate. Pertanto, se si desidera implementare un flusso di controllo sofisticato in JavaScript, è necessario utilizzare Eccezioni.

Il progetto Microsoft Volta era un progetto di ricerca (ora fuori produzione) per compilare codice .NET arbitrario in JavaScript. .NET ha Eccezioni la cui semantica non si associa esattamente a JavaScript, ma, soprattutto, ha Thread , e devi mapparli in qualche modo su JavaScript. Volta ha fatto questo implementando Continuazioni Volta usando JavaScript Exceptions e quindi implementando tutti i costrutti del flusso di controllo .NET in termini di Continuazioni Volta. Hanno dovuto usare le eccezioni come flusso di controllo, perché non esiste un altro costrutto di flusso di controllo abbastanza potente.

Hai menzionato le macchine statali. Gli SM sono banali da implementare con le chiamate di coda appropriate: ogni stato è una subroutine, ogni transizione di stato è una chiamata di subroutine. Gli SM possono anche essere facilmente implementati con GOTOo Coroutine o Continuazioni. Tuttavia, Java non ha nessuno di questi quattro, ma ha ha eccezioni. Quindi, è perfettamente accettabile usare quelli come flusso di controllo. (Beh, in realtà, la scelta corretta sarebbe probabilmente quella di usare un linguaggio con il costrutto del flusso di controllo corretto, ma a volte potresti rimanere bloccato con Java.)


7
Se solo avessimo avuto una corretta ricorsione delle chiamate in coda, forse avremmo potuto dominare lo sviluppo web sul lato client con JavaScript e poi essere seguito diffondendo sul lato server e sul dispositivo mobile come l'ultima soluzione pan-platform come wildfire. Ahimè, ma non era così. Accidenti alle nostre insufficienti funzioni di prima classe, alle chiusure e al paradigma basato sugli eventi. Ciò di cui avevamo davvero bisogno era la cosa reale.
Erik Reppen,

20
@ErikReppen: mi rendo conto che sei solo sarcastico, ma. . . Non credo davvero che il fatto che "abbiamo dominato lo sviluppo web lato client con JavaScript" abbia qualcosa a che fare con le funzionalità del linguaggio. Ha un monopolio in quel mercato, quindi è stato in grado di cavarsela con molti problemi che non possono essere cancellati con il sarcasmo.
Ruakh

1
La ricorsione della coda sarebbe stata un bel bonus (stanno deprecando le funzionalità per averlo in futuro) ma sì, direi che ha vinto contro VB, Flash, Applet, ecc ... per motivi legati alle caratteristiche. Se non avesse ridotto la complessità e non si fosse normalizzato tanto facilmente quanto avrebbe avuto una vera competizione a un certo punto. Attualmente sto eseguendo Node.js per gestire la riscrittura di 21 file di configurazione per un orribile stack C # + Java e so di non essere l'unico là fuori a farlo. È molto bravo in quello che è bravo.
Erik Reppen,

1
Molte lingue non hanno né goto (considerato dannoso!), Coroutine o continuazioni e implementano un controllo del flusso perfettamente valido semplicemente usando if, whiles e funzioni chiamate (o gosubs!). La maggior parte di questi può infatti essere utilizzata per emulare l'un l'altro, proprio come una continuazione può essere utilizzata per rappresentare tutto quanto sopra. (Ad esempio puoi usare un po 'di tempo per eseguire un if, anche se è un modo puzzolente per codificare). Quindi NON sono necessarie eccezioni per eseguire il controllo avanzato del flusso.
Shayne,

2
Beh sì, potresti aver ragione se. "For" nella sua forma in stile C può tuttavia essere usato come un tempo goffamente dichiarato, e un po 'può quindi essere usato insieme a un if per implementare una macchina a stati finiti che può quindi emulare tutte le altre forme di controllo del flusso. Ancora una volta, un modo puzzolente per codificare, ma sì. E ancora, considerato dannoso. (E direi, anche con l'utilizzo di eccezioni in circostanze non eccezionali). Tieni presente che esistono linguaggi perfettamente validi e molto potenti che non forniscono né goto né eccezioni e funzionano perfettamente.
Shayne,

19

Come altri hanno già detto numerose volte ( ad esempio in questa domanda di Stack Overflow ), il principio del minimo stupore vieta l'uso eccessivo delle eccezioni solo per scopi di controllo del flusso. D'altra parte, nessuna regola è corretta al 100% e ci sono sempre quei casi in cui un'eccezione è "lo strumento giusto" - molto simile a gotose stessa, a proposito, che viene fornita sotto forma di breake continuein linguaggi come Java, che sono spesso il modo perfetto per saltare da anelli pesantemente annidati, che non sono sempre evitabili.

Il seguente post sul blog spiega un caso d'uso piuttosto complesso ma anche piuttosto interessante per un non locale ControlFlowException :

Spiega come all'interno di jOOQ (una libreria di astrazione SQL per Java) (dichiarazione di non responsabilità: lavoro per il fornitore), tali eccezioni vengono occasionalmente utilizzate per interrompere presto il processo di rendering SQL quando viene soddisfatta una condizione "rara".

Esempi di tali condizioni sono:

  • Sono stati rilevati troppi valori di bind. Alcuni database non supportano numeri arbitrari di valori di bind nelle loro istruzioni SQL (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100). In questi casi, jOOQ interrompe la fase di rendering SQL e esegue nuovamente il rendering dell'istruzione SQL con valori di bind incorporati. Esempio:

    // Pseudo-code attaching a "handler" that will
    // abort query rendering once the maximum number
    // of bind values was exceeded:
    context.attachBindValueCounter();
    String sql;
    try {
    
      // In most cases, this will succeed:
      sql = query.render();
    }
    catch (ReRenderWithInlinedVariables e) {
      sql = query.renderWithInlinedBindValues();
    }
    

    Se estraessimo esplicitamente i valori di bind dalla query AST per contarli ogni volta, sprecheremmo preziosi cicli della CPU per il 99,9% delle query che non soffrono di questo problema.

  • Alcune logiche sono disponibili solo indirettamente tramite un'API che vogliamo eseguire solo "parzialmente". Il UpdatableRecord.store()metodo genera un'istruzione INSERTo UPDATE, a seconda Recorddei flag interni del. Dall'esterno, non sappiamo in quale tipo di logica sia contenuta store()(ad es. Blocco ottimistico, gestione del listener di eventi, ecc.), Quindi non vogliamo ripetere quella logica quando memorizziamo diversi record in un'istruzione batch, dove vorremmo store()solo generare l'istruzione SQL, non effettivamente eseguirla. Esempio:

    // Pseudo-code attaching a "handler" that will
    // prevent query execution and throw exceptions
    // instead:
    context.attachQueryCollector();
    
    // Collect the SQL for every store operation
    for (int i = 0; i < records.length; i++) {
      try {
        records[i].store();
      }
    
      // The attached handler will result in this
      // exception being thrown rather than actually
      // storing records to the database
      catch (QueryCollectorException e) {
    
        // The exception is thrown after the rendered
        // SQL statement is available
        queries.add(e.query());                
      }
    }
    

    Se avessimo esternalizzato la store()logica in API "riutilizzabili" che possono essere personalizzate per facoltativamente non eseguire l'SQL, cercheremmo di creare un'API piuttosto difficile da mantenere, difficilmente riutilizzabile.

Conclusione

In sostanza, il nostro uso di questi non locali gotoè proprio in linea con quanto affermato da Mason Wheeler nella sua risposta:

"Ho appena incontrato una situazione che non posso affrontare correttamente a questo punto, perché non ho abbastanza contesto per gestirlo, ma la routine che mi ha chiamato (o qualcosa più in alto nello stack di chiamate) dovrebbe sapere come gestirlo ".

Entrambi gli usi di ControlFlowExceptionserano piuttosto facili da implementare rispetto alle loro alternative, permettendoci di riutilizzare una vasta gamma di logiche senza refactoring dai relativi interni.

Ma la sensazione di essere un po 'una sorpresa per i futuri manutentori rimane. Il codice sembra piuttosto delicato e, sebbene in questo caso sia stata la scelta giusta, preferiremmo sempre non utilizzare le eccezioni per il flusso di controllo locale , dove è facile evitare l'uso di diramazioni ordinarie if - else.


11

L'uso delle eccezioni per il flusso di controllo è generalmente considerato un anti-pattern, ma ci sono eccezioni (nessun gioco di parole previsto).

È stato detto mille volte che le eccezioni sono pensate per condizioni eccezionali. Una connessione al database interrotta è una condizione eccezionale. Un utente che inserisce lettere in un campo di input che dovrebbe consentire solo numeri non lo è .

Un bug nel tuo software che provoca la chiamata di una funzione con argomenti illegali, ad esempio nulldove non lo consente, è una condizione eccezionale.

Usando le eccezioni per qualcosa che non è eccezionale, stai usando astrazioni inadeguate per il problema che stai cercando di risolvere.

Ma può esserci anche una penalità per le prestazioni. Alcune lingue hanno un'implementazione della gestione delle eccezioni più o meno efficiente, quindi se la tua lingua preferita non ha una gestione efficiente delle eccezioni, può essere molto costosa, dal punto di vista delle prestazioni *.

Ma altre lingue, ad esempio Ruby, hanno una sintassi simile all'eccezione per il flusso di controllo. Situazioni eccezionali sono gestite dagli operatori raise/ rescue. Ma puoi usare throw/ catchper costrutti di flusso di controllo simili a eccezioni **.

Pertanto, sebbene le eccezioni non vengano generalmente utilizzate per il flusso di controllo, la lingua scelta può avere altri modi di dire.

* Nell'esempio di un uso costoso delle eccezioni in termini di prestazioni: una volta mi ero prefissato di ottimizzare un'applicazione ASP.NET Web Form con prestazioni scadenti. Si è scoperto che il rendering di un grande tavolo stava chiamando int.Parse()circa. mille stringhe vuote su una pagina media, risultando in ca. mille eccezioni vengono gestite. Sostituendo il codice con int.TryParse()mi sono rasato un secondo! Per ogni singola richiesta di pagina!

** Questo può essere molto confusa per un programmatore venire a Ruby da altre lingue, sia come throwe catchsono parole chiave associate con le eccezioni in molte altre lingue.


1
+1 per "Usando le eccezioni per qualcosa che non è eccezionale, stai usando astrazioni inadeguate per il problema che stai cercando di risolvere."
Giorgio,

8

È completamente possibile gestire le condizioni di errore senza l'uso di eccezioni. Alcune lingue, in particolare C, non hanno nemmeno eccezioni e le persone riescono comunque a creare applicazioni piuttosto complesse. Il motivo per cui le eccezioni sono utili è che consentono di specificare in modo succinto due flussi di controllo essenzialmente indipendenti nello stesso codice: uno in caso di errore e uno in caso contrario. Senza di essi, si finisce con il codice in tutto il posto che assomiglia a questo:

status = getValue(&inout);
if (status < 0)
{
    logError("message");
    return status;
}

doSomething(*inout);

O equivalente nella tua lingua, come restituire una tupla con un valore come stato di errore, ecc. Spesso le persone che sottolineano quanto sia "costosa" la gestione delle eccezioni, trascurano tutte le ifdichiarazioni extra come quelle sopra che devi aggiungere se non utilizzare eccezioni.

Sebbene questo schema si verifichi più spesso quando si gestiscono errori o altre "condizioni eccezionali", a mio avviso se si inizia a vedere il codice del boilerplate come questo in altre circostanze, si ha un buon argomento per usare le eccezioni. A seconda della situazione e dell'implementazione, posso vedere le eccezioni utilizzate validamente in una macchina a stati, perché hai due flussi di controllo ortogonali: uno che sta cambiando lo stato e uno per gli eventi che si verificano all'interno degli stati.

Tuttavia, quelle situazioni sono rare e se hai intenzione di fare un'eccezione (gioco di parole intenzionale) alla regola, è meglio essere preparati a mostrare la sua superiorità ad altre soluzioni. Una deviazione senza tale giustificazione è giustamente chiamata anti-schema.


2
Fintanto che le dichiarazioni if ​​falliscono solo in circostanze "eccezionali", la logica di previsione delle filiali delle CPU moderne rende i loro costi trascurabili. Questo è un posto in cui le macro possono effettivamente aiutare, purché tu stia attento e non provi a fare troppo in esse.
James

5

In Python, le eccezioni vengono utilizzate per la terminazione del generatore e dell'iterazione. Python ha dei tentativi / blocchi molto efficienti, ma in realtà sollevare un'eccezione ha un certo sovraccarico.

A causa della mancanza di interruzioni multilivello o di un'istruzione goto in Python, a volte ho usato le eccezioni:

class GOTO(Exception):
  pass

try:
  # Do lots of stuff
  # in here with multiple exit points
  # each exit point does a "raise GOTO()"
except GOTO:
  pass
except Exception as e:
  #display error

6
Se devi terminare il calcolo da qualche parte in un'istruzione profondamente annidata e passare a un codice di continuazione comune, questo particolare percorso di esecuzione può molto probabilmente essere considerato come una funzione, con returnal posto di goto.
9000

3
@ 9000 Stavo per commentare esattamente la stessa cosa ... Tieni i try:blocchi su 1 o 2 righe per favore, mai try: # Do lots of stuff.
mercoledì

1
@ 9000, in alcuni casi, certo. Ma poi perdi l'accesso alle variabili locali e sposti il ​​tuo codice ancora un altro posto, quando il processo è un processo coerente e lineare.
gahooa,

4
@gahooa: pensavo come te. Era un segno di cattiva struttura del mio codice. Quando ci ho pensato di più, ho notato che i contesti locali possono essere districati e l'intero disordine trasformato in brevi funzioni con pochi parametri, poche righe di codice e significato molto preciso. Non ho mai guardato indietro.
9000

4

Facciamo uno schizzo di tale utilizzo delle eccezioni:

L'algoritmo cerca ricorsivamente fino a quando non viene trovato qualcosa. Quindi, tornando dalla ricorsione, si deve controllare il risultato per essere trovato, e poi tornare, altrimenti continuare. E questo torna ripetutamente da una certa profondità di ricorsione.

Oltre alla necessità di un valore booleano aggiuntivo found(da impacchettare in una classe, dove altrimenti sarebbe stato restituito solo un int), e per la profondità di ricorsione si verifica lo stesso postlude.

Un tale svolgimento di uno stack di chiamate è proprio ciò a cui fa eccezione. Quindi mi sembra un mezzo di programmazione non simil-goto, più immediato e appropriato. Non necessario, uso raro, forse cattivo stile, ma al punto. Paragonabile all'operazione di taglio Prolog.


Hmm, è il downvoting per la posizione effettivamente contraria, o per argomentazione insufficiente o breve? Sono davvero curioso
Joop Eggen,

Sto affrontando esattamente questa situazione, speravo che tu potessi vedere cosa ne pensi della mia domanda successiva? Utilizzo ricorsivo delle eccezioni per accumulare il motivo (messaggio) di un'eccezione di livello superiore codereview.stackexchange.com/questions/107862/…
CL22

@Jodes Ho appena letto la tua tecnica interessante, ma per ora sono abbastanza occupato. Spero che qualcun altro possa far luce sul problema.
Joop Eggen,

4

La programmazione riguarda il lavoro

Penso che il modo più semplice per rispondere a questo sia capire i progressi che OOP ha fatto nel corso degli anni. Tutto ciò che viene fatto in OOP (e la maggior parte dei paradigmi di programmazione, per quella materia) è modellato sulla necessità di lavorare .

Ogni volta che viene chiamato un metodo, il chiamante dice "Non so come fare questo lavoro, ma tu sai come, quindi lo fai per me".

Ciò presentava una difficoltà: cosa succede quando il metodo chiamato generalmente sa come fare il lavoro, ma non sempre? Avevamo bisogno di un modo per comunicare "Volevo aiutarti, davvero, ma non posso proprio farlo."

Una metodologia iniziale per comunicare ciò consisteva semplicemente nel restituire un valore "immondizia". Forse ti aspetti un numero intero positivo, quindi il metodo chiamato restituisce un numero negativo. Un altro modo per ottenere ciò era impostare un valore di errore da qualche parte. Sfortunatamente, in entrambi i modi il codice kosher mi ha permesso di controllare qui tutto per assicurarmi di controllare tutto . Man mano che le cose diventano più complicate, questo sistema cade a pezzi.

Un'analogia eccezionale

Supponiamo che tu abbia un falegname, un idraulico e un elettricista. Vuoi un idraulico per sistemare il lavandino, quindi lui lo guarda. Non è molto utile se dice solo a te: "Mi dispiace, non posso ripararlo. È rotto." Diavolo, è ancora peggio se dovesse dare un'occhiata, andarsene e spedirti una lettera dicendo che non poteva aggiustarlo. Ora devi controllare la tua posta prima ancora di sapere che non ha fatto quello che volevi.

Quello che preferiresti è che ti dica "Guarda, non sono riuscito a ripararlo perché sembra che la tua pompa non funzioni".

Con queste informazioni, puoi concludere che desideri che l'elettricista dia un'occhiata al problema. Forse l'elettricista troverà qualcosa di simile al carpentiere e dovrai far riparare il carpentiere.

Cavolo, potresti non sapere nemmeno di aver bisogno di un elettricista, potresti non sapere di chi hai bisogno. Sei solo un intermediario in un'impresa di riparazioni domestiche e la tua attenzione è l'idraulica. Quindi dite Non Sei capo del problema, e poi si dice l'elettricista per risolvere il problema.

Questo è ciò che le eccezioni stanno modellando: modalità di fallimento complesse in modo disaccoppiato. L'idraulico non ha bisogno di sapere dell'elettricista, non ha nemmeno bisogno di sapere che qualcuno nella catena può risolvere il problema. Riferisce solo sul problema che ha riscontrato.

Quindi ... un anti-pattern?

Ok, quindi capire il punto delle eccezioni è il primo passo. Il prossimo è capire cos'è un anti-pattern.

Per qualificarsi come anti-modello, è necessario

  • risolvere il problema
  • hanno conseguenze decisamente negative

Il primo punto è facilmente soddisfatto: il sistema ha funzionato, giusto?

Il secondo punto è più appiccicoso. Il motivo principale per l'utilizzo delle eccezioni come flusso di controllo normale è negativo perché non è questo il loro scopo. Ogni data funzionalità di un programma dovrebbe avere uno scopo relativamente chiaro e la cooptazione di tale scopo porta a una confusione non necessaria.

Ma questo non è un danno definitivo . È un modo scarso di fare le cose, e strano, ma un anti-schema? No. Solo ... strano.


C'è una brutta conseguenza, almeno nelle lingue che forniscono una traccia dello stack completo. Poiché il codice è fortemente ottimizzato con un sacco di inline, la traccia dello stack reale e quella che uno sviluppatore vuole vedere differiscono molto e quindi la generazione della traccia dello stack è costosa. L'uso eccessivo delle eccezioni è molto negativo per le prestazioni in tali linguaggi (Java, C #).
Maaartinus,

"È un modo scarso di fare le cose" - Non dovrebbe bastare a classificarlo come anti-schema?
Maybe_Factor

@Maybe_Factor Per la definizione di un modello di formica, no.
MirroredFate
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.