Uitzonderingsafhandeling is een goede oefening voor elke software-ontwikkelingsmethode. Of het nu gaat om testgebaseerde ontwikkeling, behendige sprints of een hacking-sessie met slechts een goeie ouwe lijst, we kunnen er allemaal baat bij hebben om te zorgen dat onze bases worden gedekt door een robuuste aanpak van defectafhandeling..
Het is van het grootste belang om ervoor te zorgen dat fouten worden afgehandeld, terwijl het esthetisch verantwoord is en natuurlijk niet logisch een groot probleem wordt met cryptische berichten voor de eindgebruiker om te proberen de betekenis te achterhalen. Als je dat doet, ben je zeker op een geweldige manier om een solide, stabiele en kleverige app te maken waar gebruikers graag mee werken en die het ten zeerste aanbevelen aan anderen.
Idealiter biedt Elixir uitgebreide uitzonderingsafhandeling via verschillende mechanismen zoals proberen te vangen
, worpen
, en de : error, reason
tuple.
Gebruik om een fout weer te geven verhogen
in je interactieve shell om een eerste voorproefje te krijgen:
iex> raise "Oh noez!" ** (RuntimeError) Oh neeez!
We kunnen hier ook een type aan toevoegen, zoals:
iex> raise ArgumentError, message: "error message here ..." ** (ArgumentError) foutmelding hier ...
Sommige manieren waarop fouten in Elixir worden behandeld, zijn op het eerste gezicht misschien niet vanzelfsprekend.
paaien
, we kunnen onafhankelijke processen creëren. Dat betekent dat een fout in een thread geen ander proces mag beïnvloeden, tenzij er op een of andere manier sprake is van een koppeling. Maar standaard blijft alles stabiel.spawn_link
macro. Dit is een bidirectionele link, wat betekent dat als een gekoppeld proces wordt beëindigd, een uitgangssignaal wordt geactiveerd.: normaal
, we weten dat we een probleem hebben. En als we het uitgangssignaal vangen met Process.flag (: trap_exit, true)
, het uitgangssignaal wordt naar de mailbox van het proces gestuurd, waar de logica kan worden geplaatst om het bericht af te handelen, waardoor een harde crash wordt vermeden.spawn_links
, maar dit zijn unidirectionele links, en we kunnen ze creëren Process.monitor
. Process.monitor
ontvangt de foutmeldingen bij een storing.Probeer voor een voorbeeldfout een getal toe te voegen aan een atoom en u krijgt het volgende:
iex>: foo + 69 ** (ArithmeticError) slecht argument in rekenkundige uitdrukking: erlang. + (: foo, 69)
Om ervoor te zorgen dat de eindgebruiker niet wordt vervormd, kunnen we de probeer-, vang- en reddingsmethoden van Elixir gebruiken.
De eerste in onze toolbox voor exception handling is probeer / rescue
, die fouten van het gebruik vangt verhogen
Dit is dus het beste geschikt voor ontwikkelaarfouten of uitzonderlijke omstandigheden zoals invoerfouten.
probeer / rescue
is vergelijkbaar in gebruik met een proberen te vangen
blokkering die je misschien in andere programmeertalen hebt gezien. Laten we een voorbeeld in actie bekijken:
iex> probeer het ...> raise "do failed!" ...> rescue ...> e in RuntimeError -> IO.puts ("Error:" <> e.message) ...> end Fout: mislukt! :OK
Hier gebruiken we de probeer / rescue
blok en de eerder genoemde verhogen
om de te vangen RuntimeError
.
Dit betekent het ** (RuntimeError)
standaarduitvoer van verhogen
wordt niet weergegeven en wordt vervangen door een mooiere uitvoer van de IO.puts
telefoontje.
Als best practice moet u de foutmelding gebruiken om de gebruiker nuttige uitvoer in gewoon Engels te geven, wat hen helpt bij het probleem. We zullen daar meer in het volgende voorbeeld naar kijken.
Een groot voordeel van Elixir is dat je meerdere uitkomsten kunt vangen in een van deze probeer / rescue
blokken. Bekijk dit voorbeeld:
probeer doen opts |> Keyword.fetch! (: source_file) |> File.read! rescue e in KeyError -> IO.puts "ontbreekt: source_file optie" e in File.Error -> IO.puts "kan bronbestand niet lezen" einde
Hier hebben we twee fouten in de redden
.
:bron bestand
symbool ontbreekt. Zoals eerder vermeld, kunnen we dit gebruiken voor het maken van gemakkelijk te begrijpen foutmeldingen voor onze eindgebruiker.
Deze krachtige en minimale syntaxisbenadering van Elixir maakt het schrijven van meerdere controles zeer toegankelijk voor ons om veel mogelijke faalpunten te controleren, op een nette en beknopte manier. Dit helpt ons om ervoor te zorgen dat we geen ingewikkelde conditionals hoeven te schrijven die langdradige scripts maken die moeilijk volledig kunnen worden gevisualiseerd en die tijdens de latere ontwikkeling correct kunnen worden beschreven of waarmee een nieuwe ontwikkelaar zich kan aanmelden.
Zoals altijd bij het werken in Elixir, is KISS de beste manier om te nemen.
Er zijn situaties waarin u een specifieke actie nodig hebt die wordt uitgevoerd na het try / rescue-blok, ongeacht of er een fout is opgetreden. Voor Java- of PHP-ontwikkelaars, denk je misschien aan de probeer / catch / eindelijk
of Ruby's beginnen / rescue / verzekeren
.
Laten we eens kijken naar een eenvoudig voorbeeld van gebruik na
.
iex> probeer het ...> raise "Ik wil met de manager praten!" ...> rescue ...> e in RuntimeError -> IO.puts ("Er is een fout opgetreden:" <> e.message) ...> after ...> IO.puts "Ongeacht wat er gebeurt, kom ik altijd op als een slechte cent." ...> einde Er is een fout opgetreden: ik wil de manager spreken! Ongeacht wat er gebeurt, kom ik altijd op als een slechte cent. :OK
Hier zie je de na
wordt gebruikt om constant een bericht weer te geven (of dit zou een functie kunnen zijn die je erin zou willen gooien).
Een meer gebruikelijke praktijk die u zult gebruiken, is waar een bestand wordt gebruikt, bijvoorbeeld hier:
: ok, file = File.open "would_defo_root.jpg" probeer het eens # Probeer het bestand hierachter te benaderen # Zorg ervoor dat we achteraf opruimen. Bestand.close (bestand) einde
Net als de verhogen
en proberen te vangen
methoden die we eerder hebben geschetst, hebben we ook de werp- en vangmacro's.
De ... gebruiken gooien
methode verlaat de uitvoering met een specifieke waarde waarnaar we kunnen zoeken in onze vangst
blokkeren en verder gebruiken zoals:
iex> probeer te doen ...> voor x <- 0… 10 do… > if x == 3, do: throw (x) ...> IO.puts (x) ...> end ...> catch ...> x -> "Caught: # x" ...> end 0 1 2 "Caught: 3"
Dus hier hebben we het vermogen om vangst
alles wat we doen gooien
in het try-blok. In dit geval, de voorwaardelijke als x == 3
is de trigger voor onze doen: gooien (x)
.
De uitvoer van de iteratie geproduceerd uit de for-lus geeft ons een duidelijk begrip van wat programmatisch is gebeurd. We zijn stap voor stap opgeschoven en de uitvoering is gestopt op de vangst
.
Vanwege deze functionaliteit kan het soms moeilijk zijn om je voor te stellen waar het gooien
vangst
zou worden geïmplementeerd in uw app. Een van de belangrijkste plaatsen zou zijn om een bibliotheek te gebruiken waar de API niet over de juiste functionaliteit beschikt voor alle resultaten die aan de gebruiker worden gepresenteerd, en een vangst zou voldoende zijn om snel door het probleem te navigeren, in plaats van dat er veel meer in de bibliotheek moet worden verwerkt het probleem en komt er op passende wijze voor terug.
Eindelijk in ons Elixir foutafhandelingsarsenaal hebben we de Uitgang
. Het verlaten gebeurt niet via de cadeauwinkel, maar expliciet wanneer een proces sterft.
Uitgangen worden als volgt aangegeven:
iex> spawn_link fn -> exit ("you are done son!") end ** (EXIT from #PID<0.101.0>) "je bent klaar zoon!"
Exit-signalen worden door processen geactiveerd om een van de volgende drie redenen:
exit (0)
in C. De uitgangsreden voor dit soort exit is het atoom : normaal
.probeer / catch / rescue
blokkeren of gooien vangen
er mee omgaan.:doden
, waardoor het ontvangende proces wordt beëindigd.Bij elk willekeurig updateschema op gooien
, Uitgang
of fouten
, het aanroepen van de System.stacktrace
zal de laatste keer terugkeren in het huidige proces.
De stapeltracering kan nogal worden geformatteerd, maar dit is onderhevig aan wijzigingen in nieuwere versies van Elixir. Raadpleeg de handleiding voor meer informatie hierover.
Als u de stacktracering voor het huidige proces wilt retourneren, kunt u het volgende gebruiken:
Process.info (self (),: current_stacktrace)
Yep, Elixir kan dat ook. Natuurlijk heb je altijd de ingebouwde typen zoals RuntimeError
tot uw beschikking. Maar zou het niet fijn zijn als je nog een stap verder kunt gaan?
Het maken van uw eigen aangepaste fouttype is eenvoudig met behulp van de defexception
macro, die gemakkelijk de :bericht
optie om een standaard foutmelding in te stellen zoals:
defmodule MyError do defexception message: "uw aangepaste fout is opgetreden" einde
Hier is hoe het te gebruiken in uw code:
iex> probeer het ...> raise MyError ...> rescue ...> e in MyError -> e ...> end% MyError message: "uw aangepaste fout is opgetreden"
Foutafhandeling in een meta-programmeertaal zoals Elixir heeft een hele hoop potentiële implicaties voor de manier waarop we onze applicaties ontwerpen en ze robuust genoeg maken voor het rigoureuze bashing van de productieomgeving.
We kunnen ervoor zorgen dat de eindgebruiker altijd een idee heeft - een eenvoudige en gemakkelijk te begrijpen leidende boodschap, die hun taak niet moeilijk zal maken, maar eerder het omgekeerde. Foutmeldingen moeten altijdgeschreven zijn in gewoon Engels en veel informatie geven. Cryptische foutcodes en variabelenamen zijn niet goed voor de gemiddelde gebruiker en kunnen zelfs ontwikkelaars in verwarring brengen!
In de toekomst kunt u de uitzonderingen in uw Elixir-toepassing volgen en specifieke logboeken instellen voor bepaalde probleemgebieden, zodat u uw fix kunt analyseren en plannen, of u kunt een kant-en-klare oplossing gebruiken..
Verbeter de nauwkeurigheid van ons foutopsporingswerk en maak monitoring voor de stabiliteit van uw apps mogelijk met deze services van derden die beschikbaar zijn voor Elixir:
In de toekomst kunt u de foutafhandelingsmogelijkheden van uw app verder uitbreiden en uw code gemakkelijker leesbaar maken. Hiervoor raad ik aan om dit project te bekijken voor elegante foutafhandeling op GitHub.
!