Il saggio progetto svedese, rinato: Elixir e Phoenix

Negli ultimi 20 anni sono successe tante cose imprevedibili. Nel 1995 nasce Java. Nello stesso periodo nasce Erlang. Java inizialmente segue la strada culturale tracciata da Sun, e si configura come un linguaggio estremamente verboso, con API specifiche per la gestione della concorrenza (es keyword synchronized per gestire nativamente le zone critiche che necessitano di mutex). Inzialmente Java è per far girare applet, poi Sun presenta un chip ad hoc (picoJava) poi IBM ci mette del suo e il linguaggio si trasforma in una ottima piattaforma per lo sviluppo server side.

Nel corso di questi 20 anni Java ha cambiato pelle almeno tre volte (applet, enterprise e ora macchina virtuale come base per linguaggi come Scala e Clojure). Le sue ultime evoluzioni hanno tradito un po’ le sue origini: sono stati introdotti i template (considerati “troppo complessi” nei tutorial del 1995!) e le “default implementation” nelle interfacce (una idea orripilante, ma tant’é….).

Mantenere tutta la retro compatibilità sta portando Java a diventare un linguaggio bizzarro: il codice scritto 6/10 anni fa ora si può riscrivere in modo completamente diverso.

Erlang ha scelto una strada diversa, è pensato per essere completamente asicrono e funzionale. Forse è stata solo fortuna, ma il piccolo linguaggio svedese ha retto bene alla prova del tempo, viene aggiornato circa una volta l’anno e anche se ha beneficiato di una frazione degli investimenti miliardari di Java, si dimostra efficace.

Al giorno d’oggi, dove anche un cellulare ha almeno un paio di processori, sviluppare sistemi che possano performare il meglio possibile su più processori è un must. E’ notizia di questi mesi che la Intel ha smesso di spingere la legge di moore (che consentiva un raddoppio della potenza dei processori ogni 18 mesi) a causa dei costi eccessivi che il processo di mignaturizzazione porta con sé. Si badi bene che ancora non abbiamo toccato il limite fisco teorico, è un problema di strategia e di costi.

In tutto questo scenario c’è Elixir, una evoluzione sintattica di Erlang con qualche buona freccia al suo arco, e un buon numero di librerie disponibili

Elixir svecchia la sintassi di Erlang lo rende più amichevole, è retro compatibile con le liberie Erlang e ha consentito la creazione di framework alla ruby on ralis chiamato Phoenix che sostiene di essere molto efficente.

C’è un aspetto critico che mi porta a insistere ogni anno su Erlang.

Quando facevamo l’università c’era un problema noto a tutti nello sviluppo di applicazioni client server (non necessariamente web).

C’erano due tipi sostanziali di tecniche:

  1. server multi richiesta multi processo
    Più semplici da programmare prevedevano la creazione di un nuovo thread per ogni richiesta in arrivo.
    Vantaggi: scala se hai tante richieste contemporanee, ma il costo associato alla creazione di un thread è molto alto.
    Ideale per task CPU Bound.
  2. server multi richiesta mono processo
    Più complessi e intricati da sviluppare, prevedevano un server che non si bloccava in attesa dei dati ma processava la prima socket client con dati pronti
    Vantaggi: scala bene se hai moltissime connessioni con parecchie latenze
    Ideal per sistemi I/O bound che non riescano a saturare il mono-processo.

Ora nessuna di queste due tecniche in realtà è migliore dell’altra, e in OOP non è banale bilanciare tra questi due approcci.
Per come è pensato Erlang però, è possibile avere i vantaggi di entrambe le teniche in un colpo solo!

Difatti l’architettura a processi stateless (anziché a istanze di classi su cui si “montano” thread) consente di sviluppare una macchina virtuale supervisore (un application server, per gli amanti di Java) che possa di volta in volta bilanciare tra l’esigenza (1) e (2).

Non è possibile ottenere questi vantaggi con un framework, come ha evidenziato il creatore di Erlang in un’email che ho ripreso tempo fa: si devono avere primitive di invio e ricezione di messaggi asincroni, innervate nella semantica del linguaggio.

Il fatto poi che Erlang sia funzionale e senza stato è stata la sinergia vincente. In caso di errore è banale far ripertire la parte di processi Erlang in errore; poiché sono privi di stato, l’anomalia viene limitata al caso critico.

Processi separati e senza stato consentono un Garbge Collector più semplice; in Java siamo dovuti arrivare al G1, la nuova implementazione a bassa latenza per risolvere alcuni problemi che i gestori di memoria automatici si portano dietro.