En introduksjon til Elixir-applikasjoner

I mine tidligere artikler har vi diskutert forskjellige Elixir vilkår og skrevet en heftig mengde kode. Det vi ikke har diskutert, er imidlertid hvordan du strukturerer og organiserer koden din slik at den er lett å vedlikeholde og slippe ut. 

Applikasjoner er svært vanlige for Erlang og Elixir, og brukes til å bygge gjenbrukbare komponenter som oppfører seg som frittstående enheter. En applikasjon kan ha sitt eget overvåkings-tre og -konfigurasjon, og det kan stole på andre applikasjoner som er tilgjengelige enten lokalt eller på enkelte eksterne servere. Alt i alt er det ikke så komplisert å jobbe med applikasjoner, og folk som har kommet, sier fra Rubins verden, finner mange kjente konsepter.

I denne artikkelen lærer du hvilke applikasjoner som er, hvordan de kan opprettes, hvordan du angir og installerer avhengigheter, og hvordan du gir miljøverdier. På slutten av artikkelen vil vi gjøre litt øvelse og lage en nettbasert kalkulator. 

Jeg vil bruke Elixir 1.5 i denne artikkelen (den ble utgitt for noen måneder siden), men alle de forklarte konseptene bør gjelde for versjon 1.4 også.

applikasjoner?

Noen kan hevde at begrepet "søknad" ikke er veldig hensiktsmessig fordi i Erlang og Elixir betyr det egentlig en komponent, eller noen kode som har en mengde avhengigheter. Søknaden i seg selv kan brukes som en avhengighet så vel i Ruby verden vi ville kalle det en "perle".

Alt i alt er applikasjoner svært vanlige i Elixir og lar deg lage gjenbrukbare komponenter samtidig som du gir enkel avhengighetsadministrasjon. De består av en eller flere moduler med null eller flere avhengigheter og er beskrevet av programressursfilen. Denne filen inneholder informasjon om programmets navn, versjon, moduler, avhengigheter og andre ting. Du kan opprette ressursfilen manuelt, men det er mye lettere å gjøre det med blandingsverktøyet som også vil forberede en korrekt mappestruktur for deg. 

Så la oss se hvordan vi kan lage et nytt Elixir-program!

Ny applikasjon

For å opprette et nytt program er alt du trenger å gjøre, å kjøre følgende kommando:

bland nytt appnavn

Vi kan også tilby --sup flagg for å lage en tom veileder for oss. La oss lage et nytt program som heter Prøve denne måten:

bland ny prøve - opp

Denne kommandoen vil opprette en prøve katalog for deg med en håndfull filer og mapper inne. La meg raskt veilede deg gjennom dem:

  • config mappen inneholder en eneste fil config.exs det, som du kan gjette, gir konfigurasjon for applikasjonen. I utgangspunktet har det noen nyttige kommentarer, men ingen konfigurasjon. Vær oppmerksom på at konfigurasjonen i denne filen bare er begrenset til selve applikasjonen. Hvis du laster applikasjonen som en avhengighet, er den config.exs vil bli ignorert effektivt.
  • lib er den primære mappen til programmet som inneholder en sample.ex fil og a prøve mappe med en application.ex fil. application.ex definerer en tilbakeringingsmodul med a start / 2 funksjon som skaper en tom veileder.
  • test er mappen som inneholder automatiserte tester for søknaden. Vi diskuterer ikke automatiserte tester i denne artikkelen.
  • mix.exs er filen som inneholder all nødvendig informasjon om programmet. Det er flere funksjoner her. Inne i prosjekt funksjon, gir du appens navn (som et atom), versjon og miljø. De applikasjon Funksjonen inneholder informasjon om tilbakekallingen av applikasjonsmodulen og kjøretidsavhengighetene. I vårt tilfelle, Sample.Application er satt som tilbakemelding på applikasjonsmodulen (som kan behandles som hovedinngangspunktet), og den må definere a start / 2 funksjon. Som allerede nevnt ovenfor ble denne funksjonen allerede opprettet for oss av blande verktøy. Til slutt, deps funksjonslister bygge-tiden avhengigheter.

avhengig

Det er ganske viktig å skille mellom kjøretid og bygge-tiden avhengigheter. Byggetid avhengigheter er lastet av blande verktøyet under kompileringen og er i utgangspunktet samlet inn i søknaden din. 

De kan hentes fra en tjeneste som GitHub, for eksempel, eller fra hex.pm nettsiden, en ekstern pakkebehandling som lagrer tusenvis av komponenter for Elixir og Erlang. Runtime avhengigheter startes før programmet starter. De er allerede samlet og tilgjengelig for oss.

Det er et par måter å spesifisere bygge-tidsavhengigheter i a mix.exs fil. Hvis du vil bruke et program fra hex.pm nettsiden, sier du bare:

: dependency_name, "~> 0.0.1"

Det første argumentet er alltid et atom som representerer søknadens navn. Den andre er kravet, en versjon som du ønsker å bruke-den blir analysert av Versjonsmodulen. I dette eksemplet, ~> betyr at vi ønsker å laste ned minst versjon 0.0.1 eller høyere, men mindre enn 0.1.0. Hvis vi sier ~> 1,0, det betyr at vi ønsker å bruke versjon som er større enn eller lik 1.0 men mindre enn 2.0. Det er også operatører som ==, >, <, > =, og <= tilgjengelig.

Det er også mulig å spesifisere direkte en : git eller a :sti alternativ:

: gettext, git: "https://github.com/elixir-lang/gettext.git", tag: "0.1" : local_dependency, sti: "path / to / local_dependency"

Det er også en : GitHub snarvei som tillater oss å gi bare eierens og repoens navn:

: gettext, github: "elixir-lang / gettext"

For å laste ned og kompilere alle avhengigheter, kjør:

bland deps.get

Dette vil installere en Hex-klient hvis du ikke har en og deretter sjekke om noen av avhengighetene må oppdateres. Du kan for eksempel angi gift - en løsning for å analysere JSON-som en avhengighet som denne:

 defp deps gjør [: gift, "~> 3.1"] slutt

Kjør deretter:

bland deps.get

Du vil se en lignende utgang:

Running dependence resolution ... Avhengighetsoppløsning fullført: gift 3.1.0 * Få gift (Hex pakke) Kontroller pakken (https://repo.hex.pm/tarballs/poison-3.1.0.tar) Fetched pakke

Gift er nå samlet og tilgjengelig på din PC. Hva mer, a mix.lock filen vil bli opprettet automatisk. Denne filen inneholder de nøyaktige versjonene av avhengighetene som skal brukes når programmet startes. 

For å lære mer om avhengigheter, kjør følgende kommando:

bland hjelpedepter

Oppførsel igjen

Programmer er atferd, akkurat som GenServer og veiledere, som vi snakket om i de forrige artiklene. Som jeg allerede nevnte ovenfor, gir vi en tilbakeringingsmodul inne i mix.exs filen på følgende måte:

 def søk gjør [mod: Sample.Application, []] end

Sample.Application er modulens navn, mens [] kan inneholde en liste over argumenter som skal overføres til start / 2 funksjon. De start / 2 funksjonen må implementeres for at programmet skal starte opp riktig.

De application.ex inneholder tilbakeringingsmodulen som ser slik ut:

defmodule Sample.Application bruker Application def start (_type, _args) gjør barn = [] opts = [strategy:: one_for_one, navn: Sample.Supervisor] Supervisor.start_link (children, opt) end-end

De start / 2 funksjonen må enten returnere : ok, pid (med en valgfri tilstand som det tredje elementet) eller : feil, grunn.

En annen ting som er verdt å nevne er at programmer ikke egentlig krever tilbakekallingsmodulen i det hele tatt. Det betyr at applikasjonsfunksjonen inne i mix.exs filen kan bli veldig minimalistisk:

def søknad slutter []

Slike applikasjoner kalles bibliotek applikasjoner. De har ikke noe tilsynstreet, men kan fortsatt brukes som avhengigheter av andre applikasjoner. Et eksempel på et bibliotekssøknad ville være gift, som vi angav som en avhengighet i den forrige delen.

Starte et program

Den enkleste måten å starte programmet på er å kjøre følgende kommando:

iex -S blanding

Du ser en utgang som ligner denne:

Kompilere 2 filer (.ex) Generert prøveapp

EN _bygge katalog vil bli opprettet inne i prøve mappe. Det vil inneholde .stråle filer samt noen andre filer og mapper.

Hvis du ikke vil starte et Elixir-skall, er det et annet alternativ å kjøre:

mix runde

Problemet er imidlertid at søknaden vil stoppe så snart som start funksjonen fullfører jobben sin. Derfor kan du gi --no-stans nøkkel for å holde programmet i gang så lenge det trengs:

bland kjøringen - ingen stopp

Det samme kan oppnås ved bruk av elixir kommando:

eliksir -S blander kjøre -no-halt

Vær imidlertid oppmerksom på at programmet stopper så snart du lukker terminalen der denne kommandoen ble utført. Dette kan unngås ved å starte søknaden din i en frittliggende modus: 

eliksir -S blander kjøre -no-halt - løsrevet

Applikasjonsmiljø

Noen ganger kan det hende du vil at brukeren av et program skal angi en parameter før appen faktisk startes. Dette er nyttig når brukeren for eksempel skal kunne kontrollere hvilken port en webserver skal lytte til. Slike parametere kan spesifiseres i applikasjonsmiljøet som er en enkel minneoppbevaring for nøkkelverdi. 

For å lese noen parameter, bruk fetch_env / 2 funksjon som godtar en app og en nøkkel:

Application.fetch_env (: sample,: some_key) 

Hvis nøkkelen ikke kan bli funnet, an :feil atom returneres. Det er også en fetch_env! / 2 funksjon som reiser en feil i stedet og get_env / 3 som kan gi en standardverdi.

For å lagre en parameter, bruk put_env / 4:

Application.put_env (: sample,: key,: value)

Den fjerde verdien inneholder alternativer og er ikke nødvendig å bli satt.

Til slutt, for å slette en nøkkel, bruk delete_env / 3 funksjon:

Application.delete_env (: sample,: key)

Hvordan gir vi en verdi for miljøet når du starter en app? Vel, slike parametere er satt ved hjelp av --Erl tast på følgende måte:

iex --erl "-sample key value" -S-blanding

Du kan da enkelt hente verdien:

Application.get_env: sample,: key # =>: verdi

Hva om en bruker glemmer å angi en parameter når du starter programmet? Vel, sannsynligvis må vi gi en standardverdi for slike tilfeller. Det er to mulige steder hvor du kan gjøre dette: inne i config.exs eller inne i mix.exs fil.

Det første alternativet er det foretrukne fordi config.exs er filen som faktisk er ment å lagre ulike konfigurasjonsalternativer. Hvis søknaden din har mange miljøparametere, bør du definitivt holde fast med config.exs:

bruk Mix.Config config: sample, key:: value

For en mindre applikasjon er det imidlertid ganske greit å gi miljøverdier rett innvendig mix.exs ved å justere søknadsfunksjonen:

 def applikasjon gjør [ekstra_applikasjoner: [: logger], mod: Sample.Application, [], env: [# <==== key: :value ] ] end

Eksempel: Opprette en nettbasert CalcServer

Ok, for å se applikasjoner i aksjon, la vi endre eksemplet som allerede ble diskutert i mine GenServer- og Supervisors-artikler. Dette er en enkel kalkulator som lar brukerne utføre ulike matematiske operasjoner og henter resultatet ganske enkelt. 

Det jeg vil gjøre er å gjøre denne kalkulatoren webbasert, slik at vi kan sende POST-forespørsler for å utføre beregninger og en GET-forespørsel for å få tak i resultatet.

Lage en ny lib / calc_server.ex fil med følgende innhold:

defmodule Sample.CalcServer bruker GenServer def start_link (initial_value) gjør GenServer.start_link (__ MODULE__, initial_value, navn: __MODULE__) avslutt def init (initial_value) når is_nummer (initial_value) gjør : ok, initial_value ende def init : stop, "Verdien må være et heltall!" End Def add (tall) gjør GenServer.cast (__ MODULE__, : add, number) avslutte def resultat gjør GenServer.call (__ MODULE__,: result) end def handle_call (: resultat, _, state) gjør : svar, state, state ende def handle_cast (operasjon, state) stopp, "Ikke implementert", state ende ende def terminate (_reason, _state) gjør IO.puts "Den server terminerte" slutten

Vi vil bare legge til støtte for Legg til operasjon. Alle andre matematiske operasjoner kan innføres på samme måte, så jeg vil ikke liste dem her for å gjøre koden mer kompakt.

De CalcServer benytter GenServer, så får vi det child_spec automatisk og kan starte den fra tilbakeringingsfunksjonen som denne:

 def start (_type, _args) gjør barn = [Sample.CalcServer, 0] opts = [strategi:: one_for_one, navn: Sample.Supervisor] Supervisor.start_link (children, opts) end

0 her er det første resultatet. Det må være et nummer, ellers CalcServer vil umiddelbart avsluttes.

Nå er spørsmålet hvordan legger vi til nettstøtte? For å gjøre det, trenger vi to tredjepartsavhengigheter: Plug, som vil fungere som et abstraksjonsbibliotek, og Cowboy, som vil fungere som en faktisk webserver. Selvfølgelig må vi spesifisere disse avhengighetene inne i mix.exs fil:

 defp deps gjør [: cowboy, "~> 1.1", : plug, "~> 1.4"] slutten

Nå kan vi starte Plug-programmet under eget tilsynstreet. Tweak start-funksjonen slik:

 def start (_type, _args) gjør barn = [Plug.Adapters.Cowboy.child_spec (: http, Sample.Router, [], [port: Application.fetch_env! (: sample,: port)]), Sample.CalcServer , 0] # ... ende

Her leverer vi child_spec og innstilling Sample.Router å svare på forespørsler. Denne modulen vil bli opprettet i et øyeblikk. Det jeg ikke liker om dette oppsettet er imidlertid at portnummeret er hardkodet, noe som ikke er veldig praktisk. Jeg vil kanskje tilpasse det når du starter programmet, så la oss lagre det i miljøet:

Plug.Adapters.Cowboy.child_spec (: http, Sample.Router, [], [port: Application.fetch_env! (: Sample,: port)])

Gi nå standardportverdien inne i config.exs fil:

config: sample, port: 8088

Flott! 

Hva med ruteren? Lage en ny lib / router.ex fil med følgende innhold:

Defmodule Sample.Router bruker Plug.Router-pluggen: matchplugg: forsendelsesend

Nå må vi definere et par ruter for å utføre tillegg og hente resultatet:

 få "/ result" do conn |> ok (to_string (Sample.CalcServer.result)) slutt innlegget "/ add" do fetch_number (conn) |> Sample.CalcServer.add conn |> ok end

Vi bruker og post makroer for å definere /resultat og /Legg til ruter. Disse makroene vil sette tilk objekt for oss. 

ok og fetch_number er private funksjoner definert på følgende måte:

 defp fetch_number (conn) gjør Plug.Conn.fetch_query_params (conn) .params ["number"] |> String.to_integer ende defp ok (conn, data \\ "OK") send_resp conn, 200, data ende

fetch_query_params / 2 returnerer et objekt med alle søkeparametrene. Vi er bare interessert i nummeret som brukeren sender til oss. Alle parametere er i utgangspunktet strenge, så vi må konvertere det til heltall.

send_resp / 3 sender et svar til klienten med den angitte statuskoden og en kropp. Vi vil ikke utføre noen feilkontroll her, så koden vil alltid være 200, noe som betyr at alt er greit.

Og dette er det! Nå kan du starte programmet på noen av måtene som er nevnt ovenfor (for eksempel ved å skrive iex -S blanding) og bruk curl verktøy for å utføre forespørslene:

krølle http: // localhost: 8088 / result # => 0 krølle http: // localhost: 8088 / add? number = 1 -X POST # => OK krølle http: // localhost: 8088 / result # => 1

Konklusjon

I denne artikkelen har vi diskutert Elixir-applikasjoner og deres formål. Du har lært hvordan du oppretter programmer, gir ulike typer informasjon, og lister avhengigheter i mix.exs fil. Du har også sett hvordan du lagrer konfigurasjonen i appens miljø og lærte et par måter å starte programmet på. Til slutt har vi sett applikasjoner i gang og opprettet en enkel nettbasert kalkulator.

Ikke glem at hex.pm nettsiden viser mange hundrevis av tredjeparts applikasjoner klar til bruk i prosjektene dine, så vær sikker på å bla gjennom katalogen og velg løsningen som passer deg! 

Forhåpentligvis fant du denne artikkelen nyttig og interessant. Jeg takker for at du bodde hos meg og til neste gang.