Programmazione.it v6.4
Ciao, per farti riconoscere devi fare il login. Non ti sei ancora iscritto? Che aspetti, registrati adesso!
Info Pubblicità Collabora Autori Sottoscrizioni Preferiti Bozze Scheda personale Privacy Archivio Libri Corsi per principianti Forum
Erlang Programming
Recensito da Roberto Casadei il 19-11-2009 ore 10:48
Copertina ISBN: 0596518188
Autori: Francesco Cesarini, Simon Thompson
Editore: O'Reilly
Lingua: Inglese
Anno: 2009
Pagine: 494
Allegati: Nessuno
The Parallel Universe
Erlang è un linguaggio di programmazione nato nei primi anni '90 dalle esigenze di Ericsson per quanto riguarda lo sviluppo di sistemi di telecomunicazione, come soluzione a requisiti stringenti di scalabilità, concorrenza, fault-tolerance e computazione distribuita in sistemi soft real-time. Queste caratteristiche e il supporto per l'SMP rendono inoltre Erlang una scelta valida per sfruttare appieno la potenza di calcolo di macchine multicore.

Questo libro, dal grande valore didattico, anche perché scaturito direttamente dal materiale utilizzato in dieci anni di insegnamento, vede come autori Francesco Cesarini, fondatore di Erlang Training and Consulting, e Simon Thompson, docente dell'Università di Kent e autore di altri testi significativi, tra cui Haskell: The Craft of Functional Programming.

Il target è costituito da programmatori – anche privi di conoscenze pregresse sulla programmazione funzionale, che comunque non è trattata in modo molto intensivo – desiderosi di imparare Erlang ex novo, pur dando per scontata l'esperienza con un altro linguaggio di programmazione, come ad esempio C, Java o Ruby. Coloro in cerca di una introduzione delicata potrebbero non rimanere soddisfatti, dato il passo celere nel dispensare le nozioni già fin dal principio.

La trattazione segue il modello classico: i concetti e i costrutti sono introdotti ed esplorati attraverso esempi significativi di codice, soggetti alla spiegazione e all'analisi degli autori, con eventuali immagini a supporto. Il modo migliore per apprendere quanto esposto consiste appunto nel rieseguire, passo dopo passo, il codice e i ragionamenti relativi; dopodiché, è possibile verificare la propria comprensione svolgendo gli esercizi forniti al termine di ogni capitolo, i quali consistono nel modificare o estendere il codice fornito negli esempi. Il codice sorgente è liberamente scaricabile dal sito del libro.

Il contenuto è diviso in due parti, per un'organizzazione efficace ed equilibrata: i primi 11 capitoli sono stati pensati per una lettura sequenziale, e descrivono gli aspetti fondamentali della programmazione in Erlang; i restanti capitoli sono dedicati ad argomenti sostanzialmente indipendenti, che si prestano pertanto anche a una lettura random. Per la natura stessa dei temi discussi nella seconda parte, non è stato possibile trattare tutto esaurientemente, per cui al termine di questi capitoli è in genere presente un paragrafo del tipo Further Reading, per segnalare riferimenti a informazioni aggiuntive.

L'appendice A, Using Erlang, raccoglie i dettagli sull'installazione del runtime, sull'esecuzione di programmi Erlang, e su strumenti che potrebbero essere utili, nonché ulteriori riferimenti da cui attingere informazioni.

Il primo capitolo è introduttivo e cerca di indirizzare il lettore verso le idee e i contenuti esposti. L'obiettivo è far comprendere ciò che Erlang può offrire e in quali casi il suo utilizzo può portare vantaggi significativi. Dunque si ripercorre la storia del linguaggio, si indicano le caratteristiche principali che mette a disposizione, e si analizzano due case study, per chiudere il capitolo con un confronto, dati alla mano, tra Erlang e C++.

Il secondo capitolo inizia a dare i primi strumenti per gli aspiranti programmatori Erlang, servendosi, come in tutto il libro, della shell interattiva erl con il suo REPL (Read-Evaluate-Print Loop). In particolare, vengono introdotti, assieme alla terminologia relativa, i tipi di dato fondamentali, le operazioni elementari sulle liste, i confronti, le variabili, i termini Erlang, le funzioni, i moduli e la loro compilazione, e il pattern matching. Quest'ultimo specialmente è molto importante, poiché consente di assegnare valori alle variabili (che sono a singolo assegnamento), di estrarre valori da tipi di dato composti e di controllare il flusso di esecuzione dei programmi; infatti, il pattern matching dei parametri attuali, con le varie intestazioni di una funzione, seleziona la giusta clausola da eseguire.

Il controllo del flusso è approfondito nel capitolo 3, Sequential Erlang, con la descrizione dei costrutti case, if, e delle guard expression, con cui si possono aggiungere vincoli addizionali all'esecuzione di una certa clausola. Successivamente vengono presentate le BIF (Built-In Function) più utilizzate, per poi affrontare la ricorsione, gli errori runtime e la loro gestione mediante il costrutto try..catch, i moduli di libreria e l'utilizzo del debugger.

Il capitolo 4 getta le basi del modello di concorrenza. Ogni attività concorrente viene detta processo; tra processi non vi è condivisione di dati in memoria, ed essi comunicano scambiandosi messaggi. La trasmissione dei messaggi è asincrona, e ogni processo ha una mailbox da cui è possibile recuperare i messaggi tramite la clausola receive. La gestione e lo scheduling dei processi sono a carico della macchina virtuale Erlang; in particolare, non viene generato un thread del sistema operativo per ogni processo creato. Oltre alle dinamiche relative al passaggio di messaggi, viene trattata la registrazione dei processi – per riferirsi a essi attraverso un alias, piuttosto che con il loro pid – i timeout, il process manager, il benchmarking e sono presenti considerazioni a proposito di race condition e deadlock.

Il capitolo 5, Process Design Patterns, analizza, con tanto di esempi, pattern tipici di programmazione concorrente: client/server, FSM (Finite State Machine) ed event handler. Viene giustamente sottolineata la necessità di astrarre e nascondere le informazioni sulle risorse e sul paradigma di comunicazione dietro a un'interfaccia funzionale.

Nel capitolo 6, con la gestione degli errori tra processi, si completa il quadro sulle fondamenta della concorrenza in Erlang. Tra i meccanismi forniti, vi è la possibilità di stabilire collegamenti bidirezionali (link) e unidirezionali (monitor), su cui avviene la propagazione dei segnali d'uscita, messaggi inviati da un processo a seguito di una terminazione non corretta verso i suoi collegamenti. Normalmente nei link i segnali d'uscita provocano la terminazione dei processi collegati, ma impostando il flag trap_exit, è possibile fare in modo che questi segnali vengano convertiti in messaggi nel formato {'EXIT', Pid, Reason} e ricevuti nella mailbox per gestirli. Nella costruzione di sistemi robusti si effettua poi un layering per isolare la propagazione degli errori all'interno di un singolo supervisor tree.

Record e macro sono l'oggetto del capitolo 7. Le strutture dati a record, create con l'omonima direttiva, forniscono un'astrazione, che regala la flessibilità che non è fornita dagli altri tipi composti; ciò è ottenuto nascondendo la rappresentazione reale e uniformando così l'accesso ai dati. Le macro, invece, consistono in abbreviazioni, che vengono espanse dal preprocessore. Record e macro apportano un contributo in termini di manutenzione di programmi e vengono solitamente posti in file .hrl da caricare con la direttiva include.

La capacità di caricare aggiornamenti software a runtime (software upgrade) senza dover interrompere l'esecuzione del sistema è di grande importanza, soprattutto laddove sono da limitare al minimo i tempi di inattività. Questo, con tanto di esempi e di spiegazioni su ciò che accade dietro le quinte, è descritto nel capitolo 8.

Il capitolo 9 tratta alcuni elementi ereditati dal mondo funzionale. Gli oggetti-funzione costituiscono un tipo di dato e sono detti fun; essi possono essere associati a variabili, passati alle funzioni o restituiti dalle funzioni come valore di ritorno. Le funzioni, che hanno a che fare con le fun sono dette higher-order function; ce ne sono alcune presenti nel modulo lists che vale la pena conoscere, come ad esempio filter, map, foldl. Le list-comprehension sono delle notazioni molto compatte e concise per costruire liste applicando funzioni agli elementi di altre liste opportunamente filtrate. Inoltre si parla dei binary – strutture dati binarie definite mediante una particolare notazione, che supporta il pattern matching e la definizione di segmenti con tanto di tipo e dimensione in bit – e dei ref, etichette per identificare nodi in un ambiente distribuito.

A volte si ha l'esigenza di memorizzare grandi quantità di dati e al tempo stesso mantenere un accesso ai dati efficiente. Allo scopo, si utilizzano le tabelle ETS (Erlang Term Storage), che immagazzinano tuple e forniscono l'accesso attraverso un campo chiave. Queste tabelle possono essere di quattro tipi: set, con chiavi uniche; bag, con chiavi multiple ed elementi distinti; duplicate bag, nel caso si desideri avere chiavi uguali con elementi uguali; e ordered set, con le chiavi ordinate per nome. I primi tre tipi di tabella sono implementati con tabelle hash e quindi consentono un tempo d'accesso costante; gli ordered set sono invece implementati con alberi binari bilanciati, e si hanno tempi d'accesso che crescono con il logaritmo della dimensione. Quando si tratta di ottenere una memorizzazione efficiente su disco, le tabelle DETS (Disk Erlang Term Storage) vengono in aiuto. Il capitolo 10 approfondisce l'argomento e termina con un esempio completo relativo a un database degli abbonati di un provider di telefonia mobile.

E' apprezzabile l'efficacia, la concisione e il dettaglio con cui è stato esposto il nucleo del linguaggio. Con il capitolo 11, relativo alla programmazione distribuita – feature implementata come parte del linguaggio – si chiude questo primo ciclo. La fornitura di un servizio in maniera trasparente attraverso più nodi Erlang, che possono risiedere sulla stessa macchina o su computer diversi e sono identificati da un nome, è fondamentale per ottenere sistemi scalabili e affidabili. La comunicazione e un primo banale livello di sicurezza tra nodi sono dati da un cookie segreto, che dev'essere conosciuto dagli interlocutori. Una tipica applicazione consiste nel paradigma RPC (Remote Procedure Call).

Il capitolo 12 offre una panoramica degli OTP Behavior, funzionalità fornite da moduli di libreria, che formalizzano i process design pattern, e con una gestione consistente degli errori, attrezzano il programmatore con una serie di componenti, che possono essere impiegati per sviluppare efficacemente applicazioni lascamente accoppiate ed eventualmente distribuite. Sono messi a disposizione sia processi worker, che svolgono l'elaborazione, sia processi supervisor, che svolgono il monitoraggio dei processi figli; essi sono poi raggruppati in alberi di supervisione, che insieme andranno a costituire una'applicazione OTP. In pratica, si hanno a disposizione dei comportamenti generici, come ad esempio client/server o supervision, da specializzare definendo moduli di callback. Le macro componenti dei sistemi Erlang sono dunque applicazioni normali – se lanciano un albero di supervisione e worker statici – e di libreria, a basso accoppiamento, specificate in un file di release.

Mnesia è un DBMS distribuito, molto adatto per applicazioni super concorrenti, in cui sono richiesti alti livelli di scalabilità e affidabilità; esso consiste sostanzialmente in tabelle ETS e DETS integrate con un livello per le transazioni. Il capitolo 13 descrive brevemente in quali contesti è conveniente impiegare Mnesia, e introduce la configurazione e le operazioni classiche di scrittura, lettura, cancellazione, indexing, svolte in contesto transazionale.

Nel capitolo 14 si considera brevemente e sommariamente lo sviluppo di interfacce grafiche con wxErlang, binding wxWidgets per il linguaggio Erlang. Qui, oltre a indicare i principi caratteristici del toolkit, sono sviluppati due piccoli esempi; comunque, per chi realmente fosse interessato all'argomento, si rimanda a ulteriori risorse.

La programmazione distribuita in Erlang è semplice e potente, ma capita a volte di dover affidarsi a meccanismi più a basso livello. Pertanto, nel capitolo 15, Socket Programming, si mostra, anche qui senza entrare molto in profondità, come instaurare flussi di comunicazione byte-oriented appoggiandosi a UDP (User Datagram Protocol) e al protocollo TCP (Transmission Control Protocol).

L'interfacciamento di Erlang con altri linguaggi di programmazione, e in particolare con Java, C, e Ruby, trova spazio nel capitolo 16. Questa interoperabilità è supportata o attraverso i port, i quali aprono un canale di trasmissione binario tra un nodo Erlang e un programma esterno, o attraverso primitive per la comunicazione con Erlang nel linguaggio da interfacciare, nel qual caso la gestione dei tipi è centrale. Ad esempio, la distribuzione Erlang contiene JInterface, un package Java con le classi corrispondenti ai tipi Erlang e le classi per l'interfacciamento, che sfruttano EPMD (Erlang Port Mapper Daemon) per connettere il nodo Java al nodo Erlang. Alternativamente, se è necessario minimizzare l'overhead, una soluzione più sofisticata consiste nello sviluppare estensioni, affinché sia possibile eseguire programmi esterni all'interno dello stesso thread in cui è eseguito il runtime Erlang (linked-in driver).

Una trattazione più completa e dettagliata è quella relativa al debugging, argomento sviluppato nel capitolo 17. In particolare, vengono introdotte due BIF importanti: erlang:trace/3 per abilitare o disabilitare il meccanismo di tracing del runtime, ed erlang:trace_pattern/3 per tracciare le chiamate locali e globali a funzione. Successivamente si descrive dbg tracer, un'interfaccia più user-friendly verso le suddette BIF. Infine, si illustrano le match specification, generabili comodamente attraverso dbg:fun2ms/1, e utilizzabili per regolare il tracing.

Il capitolo 18, Types and Documentation, riprende i tipi di dato in Erlang, introducendo due direttive, -type e -spec, per associare sinonimi ai tipi e per specificare un prototipo per una funzione. Le annotazioni -spec possono essere poi controllate con TypEr, un tool in grado anche di generarle tramite un motore di inferenza. La specifica del tipo è utile per fini di documentazione, per cui è presente EDoc, strumento capace di generare la documentazione relativa a uno o più file sorgenti, attingendo informazioni direttamente dalle annotazioni e dai commenti – il cui formato segue le regole del framework – presenti in essi.

Un capitolo apprezzabile, sebbene non entri affatto in profondità, è senz'altro il diciannovesimo, EUnit and Test-Driven Development. Oltre ai vantaggi ormai noti dello unit testing, sono esposti i lineamenti caratteristici del framework EUnit. Se per le funzioni pure è sufficiente applicare asserzioni – implementate come macro – in previsione del loro output, per codice con side-effects in genere occorre effettuare il setup/cleanup dei dati (fixture) ed impiegare oggetti mock o stub.

Il libro conclude in grande con il capitolo 20, Style and Efficiency, un distillato di esperienza con consigli, best practices ed errori comuni da evitare, da utilizzare come linee guida per raggiungere una buona qualità interna nel software Erlang e per ricercare, ma solo successivamente, l'efficienza.
proLa trattazione del linguaggio è molto dettagliata e ineccepibile dal punto di vista didattico. A termine di ogni capitolo sono presenti esercizi da svolgere e, nel caso di argomenti descritti superficialmente, non mancano riferimenti a risorse esterne. Inoltre, è molto apprezzabile l'attenzione posta sulle best practices e sulle tecniche di programmazione.
controQualche lettore potrebbe prediligere un'introduzione più soft e meno ricca di dettagli per raggiungere più facilmente la comprensione dei concetti. Il paradigma funzionale è stato trattato superficialmente, come anche altri argomenti, quali il testing e la programmazione di GUI.
Precedente: Accuratezza e affidabilità di Wikipedia, alcuni dati (3/3)
Successiva: Una trasmissione coast-to-coast a 20 Gb/s
Intervento di Luigi Z a.k.a. ciupaz del 19-11-2009 ore 13:09, Milano (MI)
Cavaliere
Cavaliere

(162 interventi)
Iscritto il 20-07-2001
Ciao, viene spiegato in che modo, e con quale ambiente di sviluppo, si possono provare e realizzare programmi in Erlang man mano che si acquisiscono le competenze?
Grazie
Intervento di Roberto Casadei a.k.a. robyonrails del 19-11-2009 ore 14:54, Cesena (FC)
Plebeo
Plebeo

(44 interventi)
Iscritto il 24-12-2006
ciupaz ha scritto:
Ciao, viene spiegato in che modo, e con quale ambiente di sviluppo, si possono provare e realizzare programmi in Erlang man mano che si acquisiscono le competenze?
Grazie

Non proprio.
Relativamente all'ambiente di sviluppo, vengono giusto introdotti (o citati) strumenti utili da utilizzare nella fase di programmazione / manutenzione del codice. Mi riferisco al process manager, a dbg, a EDoc, a TypEr, cioè tool che può essere il caso di utilizzare durante il ciclo di sviluppo.

Ma non si fa riferimento ad alcun IDE, né si indica come strutturare il proprio environment di programmazione.

E anche per quanto riguarda lo sviluppo di progetti, non vi sono riferimenti espliciti. In piccola parte le informazioni sono fornite (qualcosina a proposito della organizzazione dei sorgenti, indicazioni varie..), ma è il lettore che dev'essere abbastanza intelligente da estrarle da un'esposizione che segue altre strade.

Del resto, poiché il libro è rivolto (principalmente) a programmatori che provengono da altri linguaggi (e anche giustamente; mi chiedo quante persone abbiano imparato Erlang come primo linguaggio xD, visto che mira ad obiettivi "insoliti" per chi non conosce il campo), può darsi che si sia scelto di non aggiungere pagine per cercare di incontrare chissà quali pretese.

Non so se mi sono spiegato. :)
Intervento di Luigi Z a.k.a. ciupaz del 19-11-2009 ore 15:17, Milano (MI)
Cavaliere
Cavaliere

(162 interventi)
Iscritto il 20-07-2001
Mi par di capire allora che il libro affronta il linguaggio con un approccio da "purista", ovvero,
Intervento di Francesco Cesarini a.k.a. cesarini del 19-11-2009 ore 17:03
Plebeo
Plebeo
(1 intervento)
Iscritto il 19-11-2009
Grazie per i vostri commenti.

Quando abbiamo scritto il libro, abbiamo voluto concentrarci su Erlang come lingua di programmazione. Volevamo insegnare a programmare in Erlang, non spiegare i vantaggi o cercare di convertire gli utenti. Se dovevamo metterci a discutere l'infrastruttura OTP, release handling ed altre materie necessarie per progetti industriali, finivamo con un libro di 800 pagine. Speriamo invece di documentate i miei 15 anni di sviluppo di questi sistemi, assieme ad il middleware OTP, Mnesia e problemi di scalability ed architetture in un secondo libro. Nel frattempo, potete leggere un libro che sara in vendita i primi d'Aprile (disponibile tuttora come early release in pdf) da Manning. Si chiama OTP in action. Loro proseguono dove abbiamo lasciato noi.

Saluti da Londra,
Francesco & Simon
Intervento di Roberto Casadei a.k.a. robyonrails del 19-11-2009 ore 17:54, Cesena (FC)
Plebeo
Plebeo

(44 interventi)
Iscritto il 24-12-2006
cesarini ha scritto:
Quando abbiamo scritto il libro, abbiamo voluto concentrarci su Erlang come lingua di programmazione.

E infatti questo l'ho molto apprezzato!
Penso sia fondamentale (soprattutto oggigiorno dove il tempo è poco..) evitare inutili dispersioni e scrivere tanto per scrivere e fare numero con le pagine.

In particolare, la sensazione che ho provato leggendo il libro è quella di sapere esattamente COSA si stava cercando di spiegare. Occorre un filo logico, e la chiarezza non si raggiunge con strade contorte.

Termino il commento con una citazione, che ci sta a pennello:
La perfezione si ottiene non quando non c'è nient'altro da aggiungere, bensì quando non c'è più niente da togliere. (Antoine de Saint-Exupéry)
Copyright Programmazione.it™ 1999-2014. Alcuni diritti riservati. Testata giornalistica iscritta col n. 569 presso il Tribunale di Milano in data 14/10/2002. Pagina generata in 0.266 secondi.