Gestionarea excepțiilor este o practică excelentă pentru orice metodologie de dezvoltare a software-ului. Indiferent dacă este vorba despre dezvoltarea bazată pe teste, sprinturile agile sau o sesiune de hacking cu doar o listă de bătrânețe vechi, noi toți putem beneficia de asigurarea că bazele noastre sunt acoperite cu o abordare robustă pentru manipularea defectelor.
Este esențial să se asigure că erorile sunt luate în considerare, în timp ce este plăcut din punct de vedere estetic și, desigur, nu devine o problemă mare logic cu mesaje criptice pentru utilizatorul final de a încerca și de a culege sensul. Dacă faceți acest lucru, sunteți într-adevăr pe un drum grozav pentru a crea o aplicație solidă, stabilă și lipicioasă pe care utilizatorii le place să lucreze și va recomanda foarte mult altora.
Ideal pentru noi, Elixir oferă o gestionare a excepțiilor extinse prin intermediul mai multor mecanisme, cum ar fi încearcă să prinzi
, aruncă
, si : eroare, motiv
tuplu.
Pentru a afișa o eroare, utilizați a ridica
în shell-ul interactiv pentru a obține un prim gust:
iex> ridica "Oh noez!" ** (RuntimeError) Oh noez!
De asemenea, putem adăuga un tip la acest lucru:
iex> ridicați ArgumentError, mesaj: "Mesaj de eroare aici ..." ** (ArgumentError) mesaj de eroare aici ...
Unele dintre modurile în care erorile sunt tratate în Elixir nu pot fi evidente la prima vedere.
icre
, putem crea procese independente. Asta înseamnă că un eșec pe un fir nu ar trebui să afecteze nici un alt proces, cu excepția cazului în care a existat o legătură într-o anumită manieră. Dar, în mod implicit, totul va rămâne stabil.spawn_link
macro. Aceasta este o legătură bidirecțională, ceea ce înseamnă că dacă un proces legat se va termina, va fi declanșat un semnal de ieșire.:normal
, știm că avem o problemă. Și dacă prindem semnalul de ieșire Process.flag (: trap_exit, true)
, semnalul de ieșire va fi trimis în căsuța poștală a procesului, unde logica poate fi plasată pe modul de gestionare a mesajului, evitând astfel un accident dur.spawn_links
, dar acestea sunt legături unidirecționale și le putem crea Process.monitor
. Process.monitor
vor primi mesajele de eroare la eșec.Pentru o eroare de probă, încercați să adăugați un număr la un atom și veți obține următoarele:
iex>: foo + 69 ** (ArithmeticError) argument greșit în expresia aritmetică: erlang. + (: foo, 69)
Pentru a vă asigura că utilizatorul final nu este eronat, putem folosi metodele de încercare, captare și salvare oferite de Elixir.
În primul rând în caseta de instrumente pentru tratarea excepțiilor este încercați / salvare
, care captează erorile produse prin utilizarea a ridica
astfel încât este cu adevărat potrivită pentru erorile dezvoltatorului sau circumstanțe excepționale, cum ar fi eroarea de intrare.
încercați / salvare
este similar în utilizare la a încearcă să prinzi
bloc pe care l-ați văzut în alte limbi de programare. Să examinăm un exemplu în acțiune:
iex> încercați să ...> ridicați "nu a reușit!" ...> rescue ...> e în RuntimeError -> IO.puts ("Eroare:" <> e.message) ...> :O.K
Aici folosim încercați / salvare
bloc și cele menționate mai sus a ridica
pentru a prinde Eroare de rulare
.
Aceasta înseamnă ** (Eroare de rulare)
outputul implicit al a ridica
nu este afișată și este înlocuită cu o ieșire formatată mai bine din IO.puts
apel.
Ca o bună practică, trebuie să utilizați mesajul de eroare pentru a oferi utilizatorului o ieșire utilă în limbajul englez, ceea ce îi ajută în această problemă. O să ne uităm mai mult la exemplul următor.
Un beneficiu major al Elixir este că puteți obține rezultate multiple în unul dintre acestea încercați / salvare
blocuri. Uitați-vă la acest exemplu:
încercați să optați |> Keyword.fetch! (: source_file) |> File.read! de salvare e în KeyError -> IO.puts "lipsă: source_file opțiune" e în File.Error -> IO.puts "nu poate citi fișierul sursă" sfârșit
Aici am prins două erori în salvare
.
:fișier sursă
simbolul lipsește. Așa cum am menționat anterior, putem folosi acest lucru pentru a face mesaje de eroare ușor de înțeles pentru utilizatorul nostru final.
Această abordare puternică și minimă de sintaxă a lui Elixir face scrierea mai multor verificări foarte accesibile pentru a verifica multe puncte posibile de eșec, într-un mod curat și concis. Acest lucru ne ajută să ne asigurăm că nu avem nevoie de scrierea unor condiționări elaborate care să facă script-uri lungi care ar putea fi greu de vizualizat pe deplin și de depanare corectă în timpul dezvoltării ulterioare sau pentru ca un nou dezvoltator să se alăture.
Ca întotdeauna când lucrezi în Elixir, KISS este cea mai bună abordare pe care o poți lua.
Există situații în care veți avea nevoie de o acțiune specifică efectuată după blocul de încercare / salvare, indiferent dacă a apărut o eroare. Pentru dezvoltatorii Java sau PHP, s-ar putea să vă gândiți la încercați / captură / în cele din urmă
sau Ruby's începe / salvare / asigură
.
Să aruncăm o privire la un exemplu simplu de utilizare după
.
iex> încercați să ...> ridicați "Vreau să vorbesc cu managerul" ...> rescue ...> e în RuntimeError -> IO.puts ("A apărut o eroare:">> e.message) ...> after ...> "Indiferent de ceea ce se întâmplă, întotdeauna mă întorc ca un bănuț rău." ...> sfârșit Sa produs o eroare: Vreau să vorbesc cu managerul! Indiferent de ceea ce se întâmplă, mereu apar ca un bănuț rău. :O.K
Aici vedeți după
fiind folosit pentru a face constant un mesaj de afișare (sau aceasta ar putea fi orice funcție pe care ați dorit să o aruncați acolo).
O practică mai frecventă pe care o veți găsi este folosirea unui fișier în care se accesează un fișier, de exemplu aici:
: ok, file = File.open "would_defo_root.jpg" încercați să faceți # Încercați să accesați fișierul aici după # Asigurați-vă că vom curăța ulterior File.close (file) end
La fel de bine ca a ridica
și încearcă să prinzi
metodele pe care le-am subliniat mai devreme, avem, de asemenea, aruncarea și capturarea macrocomenzilor.
Utilizarea arunca
metoda iese din execuție cu o valoare specifică pe care o putem căuta în cadrul nostru captură
blocați și utilizați în continuare:
iex> încercați să ...> pentru x <- 0… 10 do… > dacă x == 3, facem: aruncăm (x) ...> IO.puts (x) ...> capăt ...> captura ...> x -
Așa că avem aici abilitatea captură
ceva ce noi arunca
în interiorul blocului de încercare. În acest caz, condiționată dacă x == 3
este declanșatorul pentru noi face: arunca (x)
.
Rezultatul obținut din iterația produsă din buclă pentru forță ne dă o înțelegere clară a ceea ce sa produs programat. În mod incremental am avansat și execuția a fost oprită captură
.
Din cauza acestei funcționalități, uneori este greu de imaginat unde arunca
captură
ar fi implementate în aplicația dvs. Un prim loc ar fi utilizarea unei biblioteci în care API nu are funcționalitate adecvată pentru toate rezultatele prezentate utilizatorului și o captură ar fi suficientă pentru a naviga rapid în jurul problemei, mai degrabă decât să se dezvolte mult mai mult în bibliotecă pentru a se ocupa problema și returnarea corespunzător pentru aceasta.
În cele din urmă în arsenalul nostru de manipulare a erorilor Elixir avem Ieșire
. Ieșirea se face nu prin magazinul de cadouri, dar în mod explicit ori de câte ori un proces moare.
Ieșirile sunt semnalate astfel:
iex> spawn_link fn -> ieșire ("ați terminat fiul!") sfârșitul ** (EXIT din #PID<0.101.0>) "ați terminat fiul!"
Semnalele de ieșire sunt declanșate de procese pentru unul din următoarele trei motive:
exit (0)
în C. Motivul de ieșire pentru acest tip de ieșire este atomul :normal
.încercați / captura / salvare
bloc sau arunca / captură
să se ocupe de ea.:ucide
, care determină încetarea procesului de primire.La orice moment dat de actualizare arunca
, Ieșire
sau erori
, de asteptare System.stacktrace
va reveni la ultima apariție în procesul curent.
Traseul stivei poate fi formatat destul de puțin, dar acest lucru este supus la schimbarea versiunilor mai noi ale Elixir. Pentru mai multe informații despre acest lucru, consultați pagina manuală.
Pentru a reveni la următoarea stivă pentru procesul curent, puteți utiliza următoarele:
Process.info (self (),: current_stacktrace)
Da, Elixir poate face și asta. Desigur, aveți mereu tipurile încorporate, cum ar fi Eroare de rulare
la dispozitia ta. Dar nu ar fi bine dacă ai putea merge mai departe?
Crearea propriului tip de eroare personalizat este ușoară prin utilizarea funcției defexception
macro, care va accepta convenabil :mesaj
, pentru a seta un mesaj de eroare implicit, cum ar fi:
defmodule MyError face mesajul defexception: "a apărut eroarea personalizată"
Iată cum se utilizează în codul dvs.:
iex> încercați să ...> ridicați MyError ...> salvare ...> e în MyError -> e ...> sfârșitul% MyError message: "eroarea personalizată a apărut"
Eroarea de manipulare într-un limbaj de meta-programare precum Elixir are o grămadă de implicații potențiale pentru modul în care proiectăm aplicațiile noastre și le facem suficient de robuste pentru a distruge riguros mediul de producție.
Putem asigura că utilizatorul final este lăsat întotdeauna cu un indiciu - un mesaj de îndrumare simplu și ușor de înțeles, care nu va face ca sarcina lor să fie dificilă, ci mai degrabă inversă. Mesajele de eroare trebuie să fie întotdeaunasă fie scrise în limba engleză și să ofere o mulțime de informații. Codurile de eroare cripte și numele variabilelor nu sunt bune pentru utilizatorii obișnuiți și pot chiar confunda dezvoltatorii!
Mergând mai departe, puteți să monitorizați excepțiile ridicate în aplicația dvs. Elixir și să configurați înregistrarea specifică pentru anumite probleme, astfel încât să puteți analiza și să vă planificați soluția sau puteți să vă uitați la utilizarea unei soluții off-the-shelf.
Îmbunătățiți acuratețea lucrărilor noastre de depanare și permiteți monitorizarea stabilității aplicațiilor dvs. cu aceste servicii ale terților disponibile pentru Elixir:
Dacă mergeți mai departe, vă recomandăm să extindeți în continuare capacitățile de gestionare a erorilor ale aplicației dvs. și să faceți mai ușor citirea codului. Pentru aceasta, vă recomand să examinați acest proiect pentru o manipulare elegantă a erorilor pe GitHub.
!