La gestione delle eccezioni è un'ottima pratica per qualsiasi metodologia di sviluppo del software. Che si tratti di uno sviluppo basato su test, di sprint agili o di una sessione di hacking con solo una buona vecchia lista di cose da fare, tutti possiamo trarre vantaggio dall'assicurare che le nostre basi siano coperte da un solido approccio alla gestione dei difetti.
È fondamentale assicurarsi che gli errori siano curati, pur essendo esteticamente gradevoli e, naturalmente, non si trasformino in un grosso problema logicamente con messaggi criptici per l'utente finale che cerca di carpire il significato. Se lo fai, sei sicuramente sulla buona strada per creare un'app solida, stabile e appiccicosa con cui gli utenti si divertono a lavorare e che consiglierà molto agli altri.
Idealmente per noi, Elixir fornisce un'eccezionale gestione delle eccezioni tramite diversi meccanismi come prova a prendere
, getta
, e il : errore, motivo
tuple.
Per visualizzare un errore, utilizzare aumentare
nella tua shell interattiva per ottenere un primo assaggio:
iex> rilancia "Oh noez!" ** (RuntimeError) Oh noez!
Possiamo anche aggiungere un tipo a questo in questo modo:
iex> raise ArgumentError, message: "messaggio di errore qui ..." ** (ArgumentError) messaggio di errore qui ...
Alcuni dei modi in cui gli errori sono trattati in elisir possono non essere evidenti a prima vista.
uova
, possiamo creare processi indipendenti. Ciò significa che un errore su un thread non dovrebbe influire su nessun altro processo, a meno che non ci fosse un collegamento in qualche modo. Ma per impostazione predefinita, tutto rimarrà stabile.spawn_link
macro. Questo è un collegamento bidirezionale, il che significa che se un processo collegato termina, verrà attivato un segnale di uscita.:normale
, sappiamo che abbiamo un problema E se intercettiamo il segnale di uscita con Process.flag (: trap_exit, true)
, il segnale di uscita verrà inviato alla casella di posta del processo, in cui è possibile posizionare la logica su come gestire il messaggio, evitando così un arresto anomalo.spawn_links
, ma questi sono collegamenti unidirezionali e possiamo crearli con Process.monitor
. Process.monitor
riceverà i messaggi di errore in caso di errore.Per un errore di esempio, prova ad aggiungere un numero a un atomo e otterrai quanto segue:
iex>: foo + 69 ** (ArithmeticError) Argomento non valido nell'espressione aritmetica: erlang. + (: foo, 69)
Per garantire che l'utente finale non diventi errato, possiamo utilizzare i metodi try, catch e rescue forniti da Elixir.
Il primo nella nostra casella degli strumenti per la gestione delle eccezioni è provare / salvataggio
, che cattura gli errori prodotti usando aumentare
quindi è davvero il più adatto per errori dello sviluppatore, o circostanze eccezionali come l'errore di input.
provare / salvataggio
è simile nell'uso a a prova a prendere
blocco che potresti aver visto in altri linguaggi di programmazione. Diamo un'occhiata a un esempio in azione:
iex> try do ...> raise "do failed!" ...> rescue ...> e in RuntimeError -> IO.puts ("Errore:" <> e.message) ...> end Error: do failed! :ok
Qui utilizziamo il provare / salvataggio
blocco e il suddetto aumentare
prendere il RuntimeError
.
Questo significa ** (RuntimeError)
uscita predefinita di aumentare
non viene visualizzato e viene sostituito da un output formattato più bello da IO.puts
chiamata.
Come best practice, è necessario utilizzare il messaggio di errore per fornire all'utente un output utile in inglese semplice, che li aiuta a risolvere il problema. Lo vedremo di più nel prossimo esempio.
Uno dei principali vantaggi di Elixir è che puoi prendere più risultati in uno di questi provare / salvataggio
blocchi. Guarda questo esempio:
prova opts |> Keyword.fetch! (: source_file) |> File.read! rescue e in KeyError -> IO.puts "mancante: opzione source_file" e in File.Error -> IO.puts "impossibile leggere il file sorgente" fine
Qui abbiamo riscontrato due errori nel salvare
.
:file sorgente
manca il simbolo. Come accennato in precedenza, possiamo usarlo per creare messaggi di errore di facile comprensione per il nostro utente finale.
Questo approccio sintattico potente e minimale di Elixir rende molto accessibile la scrittura di più assegni per controllare molti possibili punti di errore, in modo accurato e conciso. Questo ci aiuta ad assicurarci che non abbiamo bisogno di scrivere condizionali elaborati per creare script prolissi che potrebbero essere difficili da visualizzare completamente e debuggare correttamente durante lo sviluppo successivo o per un nuovo sviluppatore.
Come sempre quando si lavora in Elixir, KISS è l'approccio migliore da adottare.
Esistono situazioni in cui è necessario eseguire un'azione specifica dopo il blocco try / rescue, indipendentemente dal fatto che si sia verificato un errore. Per gli sviluppatori Java o PHP, potresti pensare al try / catch / finally
o di Ruby iniziare / rescue / garantire
.
Diamo un'occhiata a un semplice esempio di utilizzo dopo
.
iex> try do ...> raise "Voglio parlare con il manager!" ...> rescue ...> e in RuntimeError -> IO.puts ("Si è verificato un errore:" <> e.message) ...> after ...> IO.puts "Indipendentemente da quello che succede, vengo sempre come un brutto penny." ...> fine Si è verificato un errore: voglio parlare con il manager! Indipendentemente da quello che succede, vengo sempre come un brutto penny. :ok
Qui vedi il dopo
essere utilizzato per visualizzare costantemente un messaggio (o questa potrebbe essere una funzione che si desidera inserire).
Una pratica più comune su cui si trova questo utilizzo è dove si accede a un file, ad esempio qui:
: ok, file = File.open "would_defo_root.jpg" prova # Prova ad accedere al file qui dopo # Assicurati di ripulire dopo File.close (file) fine
Così come il aumentare
e prova a prendere
metodi che abbiamo delineato in precedenza, abbiamo anche i macro di lancio e cattura.
Usando il gettare
il metodo esce dall'esecuzione con un valore specifico che possiamo cercare nel nostro catturare
bloccare e utilizzare ulteriormente in questo modo:
iex> prova ...> per x <- 0… 10 do… > se x == 3, do: throw (x) ...> IO.puts (x) ...> end ...> catch ...> x -> "Catturato: # x" ...> fine 0 1 2 "Catturato: 3"
Quindi qui abbiamo la capacità di catturare
qualsiasi cosa noi gettare
all'interno del blocco try. In questo caso, il condizionale se x == 3
è l'innesco per il nostro do: throw (x)
.
L'output dall'iterazione prodotta dal ciclo for ci fornisce una chiara comprensione di ciò che si è verificato a livello di codice. Incrementalmente ci siamo fatti avanti e l'esecuzione è stata interrotta catturare
.
A causa di questa funzionalità, a volte può essere difficile immaginare dove gettare
catturare
sarebbe implementato nella tua app. Un posto privilegiato sarebbe l'uso di una libreria in cui l'API non ha funzionalità adeguate per tutti i risultati presentati all'utente, e una cattura sarebbe sufficiente per navigare rapidamente attorno al problema, piuttosto che dover sviluppare molto di più all'interno della libreria per gestire il problema e tornare in modo appropriato per questo.
Infine, nel nostro errore di elisir che gestisce l'arsenale, abbiamo il Uscita
. L'uscita viene effettuata non attraverso il negozio di articoli da regalo, ma esplicitamente ogni volta che un processo muore.
Le uscite sono segnalate in questo modo:
iex> spawn_link fn -> exit ("hai finito figlio!") fine ** (ESCI da #PID<0.101.0>) "hai finito figlio!"
I segnali di uscita vengono attivati dai processi per uno dei seguenti tre motivi:
exit (0)
in C. Il motivo dell'uscita per questo tipo di uscita è l'atomo :normale
.try / catch / salvataggio
blocco o tiro / catch
occuparsene.:uccidere
, che costringe il processo di ricezione a terminare.In qualsiasi data di aggiornamento, il collegamento è attivo gettare
, Uscita
o errori
, chiamando il System.stacktrace
restituirà l'ultima occorrenza nel processo corrente.
La traccia dello stack può essere formattata un po ', ma questo è soggetto a modifiche nelle versioni più recenti di Elixir. Per ulteriori informazioni su questo, si prega di fare riferimento alla pagina di manuale.
Per restituire la traccia dello stack per il processo corrente, è possibile utilizzare quanto segue:
Process.info (self (),: current_stacktrace)
Sì, anche l'elisir può farlo. Ovviamente, hai sempre i tipi built-in come RuntimeError
A tua disposizione. Ma non sarebbe bello se tu potessi fare un ulteriore passo avanti?
Creare il proprio tipo di errore personalizzato è facile usando il defexception
macro, che accetterà comodamente il :Messaggio
opzione, per impostare un messaggio di errore predefinito in questo modo:
defmodule MyError fa messaggio di defexception: "il tuo errore personalizzato si è verificato" fine
Ecco come usarlo nel tuo codice:
iex> try do ...> raise MyError ...> rescue ...> e in MyError -> e ...> end% MyError message: "il tuo errore personalizzato si è verificato"
La gestione degli errori in un linguaggio di meta-programmazione come Elixir ha un mucchio di potenziali implicazioni per il modo in cui progettiamo le nostre applicazioni e le rendiamo abbastanza robuste per il rigoroso attacco all'ambiente di produzione.
Possiamo garantire che l'utente finale abbia sempre un indizio: un messaggio guida semplice e facile da capire, che non renderà difficile il loro compito, ma piuttosto l'inverso. I messaggi di errore devono sempreessere scritto in inglese e dare molte informazioni. Codici di errore criptici e nomi di variabili non sono buoni per gli utenti medi e possono anche confondere gli sviluppatori!
In futuro, è possibile monitorare le eccezioni sollevate nell'applicazione Elixir e impostare la registrazione specifica per determinati punti problematici, in modo da poter analizzare e pianificare la correzione, oppure è possibile esaminare utilizzando una soluzione pronta per l'uso..
Migliora l'accuratezza del nostro lavoro di debug e abilita il monitoraggio della stabilità delle tue app con questi servizi di terze parti disponibili per Elixir:
In futuro, potresti voler estendere ulteriormente le capacità di gestione degli errori della tua app e rendere il tuo codice più facile da leggere. Per questo, ti consiglio di dare un'occhiata a questo progetto per l'elegante gestione degli errori su GitHub.
!