Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Elixir
Code

Un'introduzione alle Applicazioni Elixir

by
Length:LongLanguages:

Italian (Italiano) translation by Mirko Pizii (you can also view the original English article)

Nei miei articoli precedenti abbiamo discusso di diversi termini Elixir e abbiamo scritto una grande quantità di codice. Quello che non abbiamo discusso, però, è come strutturare e organizzare il codice in modo che sia facile da mantenere e rilasciare.

Le applicazioni sono molto comuni per Erlang e Elixir e sono utilizzate per costruire componenti riutilizzabili che si comportano come unità stand-alone. Un'applicazione può avere una propria struttura e configurazione di supervisione e può contare su altre applicazioni disponibili sia localmente o su un server remoto. Tutto sommato, lavorare con le applicazioni non è così complesso, e le persone che sono venute, per esempio, dal mondo di Ruby troveranno molti concetti familiari.

In questo articolo imparerai quali sono le applicazioni, come possono essere create, come specificare e installare le dipendenze e come fornire i valori dell'ambiente. Alla fine dell'articolo faremo una pratica e creeremo una calcolatrice basata sul web.

Utilizzo Elixir 1.5 in questo articolo (è stato rilasciato un paio di mesi fa), ma tutti i concetti spiegati dovrebbero applicarsi anche alla versione 1.4.

Applicazioni?

Qualcuno potrebbe obiettare che il termine "applicazione" non è molto appropriato, perché in Erlang ed Elixir significa in realtà un componente o un codice che ha un sacco di dipendenze. L'applicazione stessa può essere utilizzato come una dipendenza anche — nel mondo Ruby le chiameremo "gemma".

Tutto sommato, le applicazioni sono molto comuni in Elixir e consentono di creare componenti riutilizzabili, fornendo anche una facile gestione delle dipendenze. Sono costituiti da uno o più moduli con zero o più dipendenze e sono descritti dal file di risorse dell'applicazione. Questo file contiene informazioni sul nome dell'applicazione, sulla versione, sui moduli, sulle dipendenze e su altre cose. Puoi creare manualmente il file di risorse, ma è molto più facile farlo con lo strumento di mix che preparerà anche una struttura di cartelle corretta per te.

Quindi andiamo a vedere come possiamo creare una nuova applicazione Elixir!

Nuova Applicazione

Per creare una nuova applicazione, quello che devi fare è eseguire il seguente comando:

Possiamo anche fornire il flag --sup per creare un supervisore vuoto per noi. Andiamo a creare una nuova applicazione chiamata Sample in questo modo:

Questo comando creerà una directory di sample (ndr. esempio) per te con una manciata di file e cartelle all'interno. Lasciami guidarti velocemente su di loro:

  • cartella config che contiene un file solo config.exs che, come si può immaginare, fornisce la configurazione per l'applicazione. Inizialmente ha alcuni commenti utili, ma nessuna configurazione. Nota, a proposito, che la configurazione fornita in questo file è limitata solo all'applicazione stessa. Se si carica l'applicazione come una dipendenza, i suoi config.exs verranno effettivamente ignorati.
  • lib è la cartella primaria dell'applicazione che contiene un file sample.ex e una cartella di sample (ndr. esempio) con un file application.ex. application.ex definisce un modulo di callback con una funzione start/2 che crea un supervisore vuoto.
  • test è la cartella contenente test automatizzati per l'applicazione. In questo articolo non parleremo di test automatizzati.
  • mix.exs è il file che contiene tutte le informazioni necessarie sull'applicazione. Qui ci sono molteplici funzioni. All'interno della funzione di progetto viene fornito il nome dell'app (come atomo), la versione e l'ambiente. La funzione di applicazione contiene informazioni sulle richieste del modulo di applicazione e le dipendenze di runtime. Nel nostro caso, Sample.Application è impostato come callback del modulo di applicazione (che può essere considerato come il punto di ingresso principale) e deve definire una funzione start/2. Come già detto, questa funzione è già stata creata per noi dallo strumento mix. Infine, la funzione deps elenca le dipendenze di build-time.

Dipendenze

È abbastanza importante distinguere tra le dipendenze di runtime e build-time. Le dipendenze di build-time vengono caricate dallo strumento mix durante la compilazione e sono fondamentalmente compilate nell'applicazione.

Questi possono essere recuperati da un servizio come GitHub, ad esempio, o dal sito web hex.pm, un gestore di pacchetti esterni che memorizza migliaia di componenti per Elixir e Erlang. Le dipendenze di runtime vengono avviate prima dell'inizio dell'applicazione. Sono già compilati e disponibili per noi.

Ci sono un paio di modi per specificare le dipendenze di build-time in un file mix.exs. Se desideri utilizzare un'applicazione dal sito web hex.pm, dite semplicemente:

Il primo argomento è sempre un atomo che rappresenta il nome dell'applicazione. Il secondo è il requisito, una versione che si desidera utilizzare - viene analizzato dal modulo Versione. In questo esempio, ~> significa che desideriamo scaricare almeno la versione 0.0.1 o successive ma meno di 0.1.0. Se diciamo ~> 1.0 significa che vorremmo utilizzare una versione più grande o uguale a 1.0 ma inferiore a 2.0. Esistono anche gli operatori come ==>,  <>= e <= disponibili.

E' anche possibile specificare direttamente una opzione :git o :path:

C'è anche una scorciatoia :github che ci permette di fornire solo il nome del proprietario e del repo:

Per scaricare e compilare tutte le dipendenze, esegui:

Questo installerà un client Hex se non lo hai e quindi controlla se una delle dipendenze deve essere aggiornata. Ad esempio, è possibile specificare Poison - una soluzione per analizzare JSON - come una dipendenza in questo modo:

E poi esegui:

Vedrai un output simile:

Poison è ora compilato e disponibile sul tuo PC. Inoltre, verrà creato un file mix.lock automaticamente. Questo file fornisce le versioni esatte delle dipendenze da utilizzare quando viene avviata l'applicazione.

Per saperne di più sulle dipendenze, esegui il seguente comando:

Comportamento

Le applicazioni sono comportamenti, proprio come GenServer e supervisori, che abbiamo parlato negli articoli precedenti. Come ho già detto in precedenza, forniamo un modulo di richiamata all'interno del file mix.exs nel seguente modo:

Sample.Application è il nome del modulo, mentre [] può contenere un elenco di argomenti da passare alla funzione start/2. La funzione start/2 deve essere implementata in modo che l'applicazione venga avviata correttamente.

Il file application.ex contiene il modulo di richiamata che si mostrerà così:

La funzione start/2 dovrà sempre ritornare {:ok, pid} (con uno stato opzionale come terzo elemento) o {:error, reason}.

Un'altra cosa da sottolineare è che le applicazioni non richiedono affatto il modulo di callback. Significa che la funzione di applicazione all'interno del file mix.exs può diventare davvero minima:

Tali applicazioni sono chiamate applicazioni di libreria. Non hanno alcun albero di supervisione ma possono ancora essere utilizzati come dipendenze da altre applicazioni. Un esempio di un'applicazione di libreria sarebbe Poison, che abbiamo specificato come una dipendenza nella sezione precedente.

Avviare una applicazione

Il modo più semplice per avviare l'applicazione è eseguire il seguente comando:

Vedrai un output simile a questo:

Una cartella _build verrà creata all'interno della cartella sample. Conterrà file .beam e alcuni altri file e cartelle.

Se non vuoi cominciare con una shell di Elixir, un'altra opzione è eseguire:

Il problema, però, è che l'applicazione si interromperà non appena la funzione di start finisce il suo lavoro. Pertanto, è possibile fornire il tasto --no-halt per mantenere l'applicazione in esecuzione per quanto necessario:

Lo stesso può essere ottenuto usando il comando elixir:

Notare tuttavia che l'applicazione si interromperà non appena si chiude il terminale in cui è stato eseguito questo comando. Ciò può essere evitato avviando l'applicazione in modalità disinserita:

Ambiente dell'applicazione

A volte è possibile che l'utente di un'applicazione imposta un parametro prima che l'applicazione sia effettivamente avviata. Questo è utile quando, ad esempio, l'utente dovrebbe essere in grado di controllare quale porta un server web dovrebbe ascoltare. Tali parametri possono essere specificati nell'ambiente di applicazione che è un semplice memorizzazione in chiave di memoria in memoria.

Per leggere un determinato parametro, utilizzare la funzione fetch_env/2 che accetta un'app e una chiave:

Se la chiave non può essere trovata, viene restituito un atomo :error. Ci sono anche una funzione fetch_env!/2 che solleva un errore e get_env/3 che può fornire un valore predefinito.

Per salvare un parametro, usa put_env/4:

Il quarto valore contiene opzioni e non è necessario impostare.

Infine, per eliminare una chiave, utilizza la funzione delete_env/3:

Come possiamo fornire un valore per l'ambiente quando si avvia un'applicazione? Ebbene, questi parametri vengono impostati con il tasto --erl nel seguente modo:

Successivamente puoi facilmente ottenere il valore:

Che cosa succede se un utente dimentica di specificare un parametro all'avvio dell'applicazione? Beh, molto probabilmente dobbiamo fornire un valore predefinito per tali casi. Ci sono due possibili punti in cui puoi farlo: all'interno del config.exs o all'interno del file mix.exs.

La prima opzione è quella preferita perché config.exs è il file che è effettivamente inteso per memorizzare varie opzioni di configurazione. Se la tua applicazione ha un sacco di parametri di ambiente, dovresti definitivamente attaccare con config.exs:

Per un'applicazione più piccola, però, è abbastanza opportuno fornire i valori dell'ambiente proprio all'interno di mix.exs, modificando la funzione dell'applicazione:

Esempio: creare un CalcServer web-based

Okay, per vedere le applicazioni in azione, modifichiamo l'esempio già discusso negli articoli di GenServer e Supervisors. Si tratta di una semplice calcolatrice che consente agli utenti di eseguire varie operazioni matematiche e di ottenere il risultato piuttosto facilmente.

Quello che voglio fare è rendere questo calcolatore basato su web, in modo da poter inviare richieste POST per eseguire calcoli e una richiesta GET per afferrare il risultato.

Crea un nuovo file lib/calc_server.ex con il seguente contenuto:

Noi aggiungeremo solo il supporto per l'operazione add. Tutte le altre operazioni matematiche possono essere introdotte nello stesso modo, quindi non li elencherò qui per rendere il codice più compatto.

Il CalcServer utilizza GenServer, in modo che otteniamo automaticamente child_spec e possiamo avviarlo dalla funzione di callback come questo:

0 qui è il risultato iniziale. Deve essere un numero, altrimenti CalcServer terminerà immediatamente.

Ora la domanda è come facciamo ad aggiungere il supporto web? A tal fine, ci occorrono due dipendenze di terze parti: Plug, che agirà come una libreria di astrazione e Cowboy, che agirà come un vero server web. Naturalmente, occorre specificare queste dipendenze all'interno del file mix.exs:

Ora possiamo avviare l'applicazione Plug sotto la nostra struttura di supervisione. Modifica la funzione di avvio come questa:

Qui stiamo fornendo child_spec e impostando Sample.Router per rispondere alle richieste. Questo modulo verrà creato in un momento. Quello che non mi piace di questo setup, tuttavia, è che il numero di porta è codificato, che non è veramente conveniente. Potrei volerla modificare quando si avvia l'applicazione, quindi lo memorizziamo nell'ambiente:

Immettere ora il valore di porta predefinito all'interno del file config.exs:

Ottimo!

E il router? Crea un nuovo file lib/router.ex con il seguente contenuto:

Ora dobbiamo definire un paio di percorsi per eseguire l'aggiunta e recuperare il risultato:

Stiamo usando le macro di get e post per definire i percorsi /result e /add. Quelle macro creeranno l'oggetto conn per noi.

ok e fetch_number sono funzioni private definite nel modo seguente:

fetch_query_params/2 restituisce un oggetto con tutti i parametri di query. Siamo interessati solo al numero che l'utente ci invia. Tutti i parametri inizialmente sono stringhe, quindi dobbiamo convertirlo in intero.

send_resp/3 invia una risposta al client con il codice di stato e un corpo fornito. Non eseguiamo alcun controllo degli errori qui, quindi il codice sarà sempre 200, il che significa che tutto va bene.

E questo è così! Adesso puoi avviare l'applicazione in uno dei modi elencati in precedenza (ad esempio digitando iex -S mix) e utilizzare lo strumento curl per eseguire le richieste:

Conclusione

In questo articolo abbiamo discusso le applicazioni Elixir e il loro scopo. Hai imparato a creare applicazioni, fornire vari tipi di informazioni e elencare le dipendenze all'interno del file mix.exs. Hai anche visto come memorizzare la configurazione nell'ambiente dell'app e ha imparato un paio di modi per avviare l'applicazione. Infine, abbiamo visto applicazioni in azione e creato una semplice calcolatrice basata sul web.

Non dimentichiamo che il sito web hex.pm elenca molti centinaia di applicazioni di terze parti pronte per essere utilizzate nei vostri progetti, perciò assicuratevi di consultare il catalogo e scegliere la soluzione che ti soddisfa!

Speriamo che tu abbia trovato questo articolo utile e interessante. Vi ringrazio per rimanere con me e fino alla prossima volta.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.