01 Sep 2019
Ho iniziato a leggere un thread affascinante su LWN, in ripresa di un post piuttosto lungo sul blog di Packt:
Systems programming often involves low-level manipulations and requires low-level details of the processors such as privileged instructions. For this, Rust supports using inline Assembly via the ‘asm!’ macro. However, it is only present in the nightly compiler and not yet stabilized. Triplett in a collaboration with other Rust developers is writing a proposal to introduce more robust syntax for inline Assembly.
Non penso che il punto sia rendere obsoleto C quanto ormai è obsoleto Assembly. Casomai, penso che il punto sia ridare dignità a ognuno di questi strumenti nel modo migliore. Rust è un ottimo rimpiazzo di C per quanto riguarda la programmazione di sistema, soprattutto quando vengono meno determinati bisogni (ovvero restrizioni dovute alla memoria che puoi avere su determinati chippetti). Assembly, viceversa, è un tool che a meno di assurde invenzioni non è possibile sostituire.
Rust indirizza tutti questi bisogni in una maniera estremamente elegante, unendo una sintassi estremamente efficace, tooling ottimo, soprattutto moderno, e alcune finezze funzionali che lo rendono il mio primo candidato quando si tratta di piccoli programmi.
Il thread su LWN è veramente ricco di spunti, ve lo raccomando. Per esempio dal commento di Archimedes:
cargo as build system is “nice and simple” and can handle a lot but falls short if complex builds are needed which can be done in C using the automake/autoconf, cmake, … hell …
Questo evidenzia una giovinezza in alcuni aspetti del tooling legato a Rust, e anche degli aspetti in cui la catena di montaggio attuale si può migliorare a tal punto da servire come punto d’appoggio per una brand awareness fortissima da parte di aziende che decidono di scrivere larga parte del loro software in Rust, e sentono questo tipo di necessità.
Poi non venite a dire che non ve l’ho detto. ;-)
31 Aug 2019
Ne hanno già parlato ampiamente tanti blogger, su tutti voglio citare Aldo:
Questa mattina ho ricevuto un invito tramite Google Calendar a partecipare a un “evento” in cui avrei vinto un iPhone. L’invito era ripetuto per 5 giorni, dal 23 al 27 agosto. Ovviamente l’invito conteneva un link.
A quanto pare, l’orbe terracqueo ha scoperto che se invii una email con un invito a un evento su Google Calendar, quell’evento viene subito aggiunto al calendario con tanto di notifiche ricorrenti su partecipazioni, accettazioni e quant’altro. E gli spammer hanno capito che era terreno fertile.
Ne sono molto infastidito: è una feature che usavo da anni, e pare che l’unico modo per scongiurare l’eventualità che questo tipo di evento ricapiti sia disabilitare la possibilità che GMail faccia questa cosa. Sempre dal post di Aldo:
È possibile evitare del tutto questa truffa, cambiando due impostazioni generali di Google Calendar, che sono attive di default. Basta disattivare in “Impostazioni generali” > “Impostazioni evento” > “Aggiungi automaticamente gli inviti”, mettendolo su “No, mostra solo gli inviti a cui ho risposto”, mentre, poco più sotto, in “Opzioni di visualizzazione” disattivare “Mostra eventi rifiutati”.
Io però sono estremamente contrariato: semplicemente vorrei che Google disabilitasse questo tipo di comportamento per le email marcate come spam. Altrimenti si viene condannati a smettere di usare qualcosa di comodo, semplicemente per via di uno scriteriato abuso da parte di qualcun altro.
15 Aug 2019
In questo periodo di totale nullafacenza che sono le ferie mie e di Agnese ho preso la palla al balzo per dare un’aggiornata globale a un progetto che ha preso un numero imbarazzante di star su GitHub, che aveva bisogno di tantissimo amore (non ci mettevo mano letteralmente da anni), e che aveva anche un discreto numero di notifiche di sicurezza dovute a librerie non aggiornate.
Sto parlando di Stocazzo As A Service, un esperimento divertente che mi ha permesso illo tempore di sperimentare un po’ con Hapi, un framework per lo sviluppo di applicazioni web, e che ha persino ricevuto qualche pull request interessante.
Ci ho messo abbastanza poco a capire che non sarebbe bastato aggiornare le dipendenze, e che in realtà la codebase aveva bisogno di una riscrittura totale in barba a tutte le raccomandazioni del tipo “non andare a rompere quello che funziona” che ogni guru del software vi darebbe. Non essendo un pazzo suicida però ho deciso di lavorare iterativamente, seguendo la regola del boy scout, un sacco di cautela e la suite di test che avevo già scritto in precedenza.
Siccome vengo da anni di JavaScript ma soprattutto anche da (meno) anni di Elixir nel tempo libero, ho sentito subito la mancanza di alcune cosette:
- Un formatter come
mix format
;
- Un tool di analisi statica come Credo;
- Pipe operator e immutabilità.
Siccome per quanto riguarda la terza non potevo farci niente (almeno non sul momento), ho deciso di concentrarmi sul rendere la mia toolchain un po’ più confortevole, quindi ho aggiunto Prettier e ho configurato npm per formattare tutto tipo mix format
; successivamente, ho dato un bel giro di vite alla codebase esistente aggiungendo ESLint al progetto con una configurazione abbastanza generica.
A quel punto ho aggiornato le librerie di testing (Code per expectation e Lab per la test instrumentation) e ho cominciato a vedere cosa si rompeva. L’interfaccia col webserver in realtà non era cambiata molto: il brutto del guardare indietro al codice che hai scritto tanto tempo fa è più che altro lo sguardo lanciato nel baratro degli errori di gioventù che hai commesso. Tipo un modulo utils
e una serie di funzioni dentro che fanno “cose” fantasiose coi parametri che gli passi. Ho stracoperto quella parte di test, perché era la parte più debole, poi ho portato tutto alla nuova versione di Hapi, che è leggermente diversa nel funzionamento dato che si basa molto su async
e await
. Contestualmente ho aggiornato la test suite, in modo da usare nuove funzioni.
L’ultimo passo è stato cominciare a riscrivere la libreria di “utils” che avevo partorito all’epoca. Ormai forte di una test suite a prova di bomba, non potevo rompere niente e sono stato guidato dai test rotti alla ricerca di eventuali problemi.
Ci ho messo un paio d’ore a fare tutto, forse tre. Non era una codebase particolarmente larga, quindi mi sono potuto permettere il lusso di farle un lifting completo.
“Che c’è di nuovo?” Direte voi, miei lettori. “È una storia di un refactoring come tanti altri”. Ed è vero. Quello che ho notato però è come la mia esperienza con un altro linguaggio e un’altra piattaforma mi abbia condotto alla ricerca del miglior tooling per fare quello di cui avevo bisogno, e come io abbia messo in pratica best practice totalmente trasversali.
In parole povere, sono convinto che nel momento in cui impariamo un nuovo linguaggio, o un nuovo tool, impariamo un nuovo modo di lavorare oppure perfezioniamo il metodo che abbiamo già. E questo, almeno per me, è incredibilmente incoraggiante, perché con questa esperienza ho avuto modo di toccare con mano quanto il tempo che ho speso su Elixir abbia cambiato in meglio le mie abitudini in maniera estremamente profonda.
Photo courtesy of Safar Safarov
28 Jul 2019
Più passa il tempo più mi diverto con Elixir, sia usandolo su progetti più grandi che su scemenze domestiche. Tra The Big Elixir l’anno scorso e un po’ di esperienza sul campo ho imparato soprattutto una cosa: che quelle che pensavo fossero ovvietà in realtà sono piccoli consigli che consentono a chiunque di migliorare la qualità del proprio codice senza fare nulla.
mix compile --warnings-as-errors
I più giovani la vedranno come una mossa malvagia senza alcun guadagno, ma in realtà mix compile --warnings-as-errors
è un comando che ci permette di trarre vantaggio da un assetto più pedante del compilatore senza dover fare nulla, e salvandoci da potenziali errori in produzione. Quello che succede usando questo comando è che il nostro codice viene compilato, ma appena viene trovato un warning (quindi qualcosa di cui il compilatore ci avvisa ma su cui normalmente passa sopra) la compilazione fallisce irrimediabilmente, e noi siamo costretti a dover andare ad aggiustare la porcata che abbiamo (forse) scritto.
La cosa interessante è che questo riguarda solo il nostro codice: fortunatamente se c’è un warning in qualche dipendenza il compilatore continuerà a costruire il nostro pacchetto come se nulla fosse.
Perché è utile? Beh: innanzi tutto senza aver scritto alcun test, anche per un progetto stupidissimo di un weekend, possiamo infilare questo comando in una pipeline e avere una build di continuous integration più affidabile e gratis. In secondo luogo, è sempre utile un occhio in più sul codice, e il compilatore di Elixir da solo è in grado di aiutarci sulle marachelle più grandi.
Da Elixir 1.6 è disponibile, direttamente integrato nella piattaforma, un formatter nativo che prende tutti i file .ex
/.exs
e se abbiamo fatto qualche errore di formattazione o semplicemente scritto codice in maniera poco leggibile, prende il file e lo riscrive in modo da aumentare la leggibilità.
I benefici dell’usare un formatter vanno dalla leggibilità di base al fatto che essendo la configurazione parte del progetto, sia che siamo da soli a lavorare su una codebase sia che siamo in novecento avremo uno stile coerente su tutto il codice.
Quello di usare un formatter è un consiglio valido per ogni tipo di piattaforma e linguaggio, ma il formatter di Elixir ci dà qualcosa in più: un comando per controllare se i file sono stati formattati, da inserire ovviamente insieme a mix compile --warnings-as-errors
nella nostra pipeline.
Se andiamo a guardare le opzioni di mix format
infatti possiamo vedere qualcosa di interessante:
--check-formatted
- checks that the file is already formatted. This is useful in pre-commit hooks and CI scripts if you want to reject contributions with unformatted code. However keep in mind that the formatted output may differ between Elixir versions as improvements and fixes are applied to the formatter.
--check-equivalent
- checks if the files after formatting have the same AST as before formatting. If the ASTs are not equivalent, it is a bug in the code formatter. This option is useful if you suspect you have ran into a formatter bug and you would like confirmation.
In base a che livello di comprensione abbiamo di come funziona la compilazione del codice Elixir possiamo usare uno di questi due flag. Io personalmente tendo a usare --check-formatted
, dato che --check-equivalent
è più adatto per cercare bachi all’interno del formatter stesso.
Insomma, se vogliamo controllare che ogni cambiamento sia adeguatamente formattato andiamo a inserire mix format --check-formatted
all’interno della nostra pipeline e subito ne noteremo i risultati.
Usare Credo
L’ultimo consiglio ma non per importanza è l’adozione di Credo. Conosco questo tool di linting e analisi statica del codice (soprattutto la seconda) da quando ho iniziato a scrivere i miei primi programmi in Elixir, merito della segnalazione del buon Claudio: è veramente una figata. Innanzi tutto perché non c’è niente da fare ed è veramente “drop in” come approccio: lo metti tra le dipendenze, il tempo di un mix deps.get
e sei già in pole position con mix credo
.
I consigli che dà sono tra i più disparati, e se lo infilate dentro il progetto quando siete all’inizio non avrete necessità di fare refactoring sanguinolenti più in là: vi segnalerà indentazioni sbagliate, pezzi di codice ottimizzabili, addirittura problemi di design del codice, e tronconi del vostro programma dove potete migliorare la leggibilità.
È veramente una figata, e ovviamente potete introdurlo in maniera incrementale dato che ogni check di Credo è disabilitabile da file di configurazione, quindi è possibile partire con una configurazione più blanda per andare poi col tempo, dopo un po’ di refactoring se il progetto è vecchio, a introdurre man mano sempre più controlli.
Beh, spero di avervi dato qualche indizio interessante su mosse di effort minimo che possono avere un grande impatto di qualità sui vostri progetti in Elixir. Se nella vostra cintura avete altri strumenti simili vi aspetto nei commenti ;-)
Photo courtesy of Artem Maltsev
02 Jun 2019
L’altro giorno ho visitato uno strano sito. Un sito carino, con un sacco di figure che pretendevano di spiegare alcune cose altrimenti complicate. E in tutto il sito, un po’ ovunque, campeggiava una parola con una radice che sempre più spesso vedo usare nell’informatica, e sempre più sovente impropriamente: “micro”. Ho sbattuto un paio di volte le palpebre, riconosciuto l’oggettiva validità dei concetti esposti, chiuso il browser e iniziato a pensare a tutte le volte che ho visto stampate su uno schermo le parole che avevo appena letto.
Backend: l’alba dei microservizi
Sono già un bel po’ di anni che mi sorbisco le auto-lodi masturbatorie di coloro che implementano architetture a microservizi, e c’è un pattern ricorrente che voglio mettere per iscritto: di solito la distanza tra il racconto e la realtà dei fatti è abissale. Ma andiamo per ordine: l’architettura a microservizi è una chimera a forma di cloud computing e cluster di container che ha preso forma qualche anno fa, venendo immediatamente presa come esempio di virtù da qualsiasi backend developer e architetto di sistemi software. Negli ultimi due o tre anni, non ho mai sostenuto un colloquio, che fosse per una posizione frontend, backend, full-stack o per andare a fare il cameriere senza che mi venisse messa in ottima luce la presenza nell’azienda X (che fosse Tesla, che fosse Amazon, che fosse l’enoteca sotto casa mia) di una sfavillante, scintillante, stupenda architettura a microservizi. Ci sono alcuni casi in cui ho fatto delle domande per approfondire e ho trovato qualcosa che mi ha convinto. In altri momenti mi sono messo le mani nei capelli. Un caso tipico è l’approfondimento della piattaforma alla base dei servizi: gli incapaci (scusate ragazzi, ma non mi viene in mente un sinonimo caruccio) solitamente si vantano di avere tutti i servizi scritti in un solo linguaggio. Ora, delle due l’una: o il dominio che tratti è eccezionalmente ristretto, oppure da qualche parte stai usando un cucchiaio per piantare un chiodo nel muro.
Oltre questo, la buzzword dei microservizi portata avanti dalle società di consulenza di mezzo mondo insieme a una manciata di manager saccenti e architetti sotto LSD ci ha portati alla dimenticanza del passato, ovvero che la Service Oriented Architecture di una volta era esattamente quello che adesso viene spacciato come architettura a microservizi, per un motivo molto semplice: nonostante la domanda fosse lì in bella vista, ha ricevuto la solita risposta per salvare capre e cavoli. Al quesito “quanto deve essere grande un microservizio?”, la risposta (beninteso: la risposta che darei anch’io ad oggi) è “dipende”.
Questo chiaramente significa che c’è chi si è sentito in potere di definire la propria architettura “a microservizi” anche se di mezzo c’era un Enterprise Service Bus, che le architetture a microservices cercano di abbattere. O che altri hanno deciso che invece di fare cotract-based development potevano serializzare gli oggetti di dominio. In sostanza, “microservices” ha perso la propria indentità esattamente come tempo prima Service Oriented Architecture aveva perso la propria, con velenose parole in proposito da parte di Martin Fowler:
When we’ve talked about microservices a common question is whether this is just Service Oriented Architecture (SOA) that we saw a decade ago. There is merit to this point, because the microservice style is very similar to what some advocates of SOA have been in favor of. The problem, however, is that SOA means too many different things, and that most of the time that we come across something called “SOA” it’s significantly different to the style we’re describing here, usually due to a focus on ESBs used to integrate monolithic applications.
[…]
This common manifestation of SOA has led some microservice advocates to reject the SOA label entirely, although others consider microservices to be one form of SOA, perhaps service orientation done right. Either way, the fact that SOA means such different things means it’s valuable to have a term that more crisply defines this architectural style.
In sostanza quello che sostengo è che esattamente come la Service Oriented Architecture sia diventata un meltin’ pot di qualsiasi soluzione “fattorizzata” per i backend applicativi architetturalmente parlando, anche la “microservices architecture” sia diventata una “microservices culture/tribe/community”, non fornendo un pattern vincolante. Perché è possibile dare un nome alle cose solo quando c’è un vincolo a tenerle assieme. Come la carbonara che è formata da abbondante uovo, abbondante pecorino, e abbondante guanciale.
Frontend: l’alba dei micro-frontend (appunto)
All’inizio del post ho menzionato un sito. Il sito in questione è Micro-frontends, e descrive un’architettura per i frontend di applicazioni web che in queste ultime settimane ha fatto discutere la community in lungo e in largo. In generale il pattern è più o meno questo: metti svariate micro-applicazioni scritte nel linguaggio che vuoi, già compilate, nella stessa pagina, poi speri che succeda qualcosa. Nello specifico il minestrone di applicazioni dovrebbe funzionare accettando di venire orchestrato da un meccanismo di “IPC” (se sto parlando arabo c’è Wikipedia) che gestisce le informazioni da passare all’una o all’altra app. È una buona idea, ma di fatto ha molte limitazioni nel quotidiano, esattamente come nel quotidiano hanno delle limitazioni i microservizi e qualsiasi cosa che venga venduta come la panacea a un sacco di mali se non a tutti.
Per esempio, i browser caricano tanti bundle ognuno con la propria versione di React, Angular o Vue? Per forza, altrimenti nulla di tutto questo sarebbe agnostico alla tecnologia che usano gli altri. Solo che tanti bundle pesano, per cui serve coordinamento per indirizzare questa criticità in modo che qualche altro meccanismo possa fornire delle librerie “common” (come i common chunks di Webpack?) che consentano a tutti i componenti di funzionare mantenendo i bundle a una dimensione accettabile. In questo modo si sposta la complessità sul lato architetturale, come per i microservizi, e si mantiene semplice il dominio di ogni componente, ma lo stesso Dan Abramov (che è il ragazzotto che ha scritto Redux) si è espresso in merito:
I don’t understand micro-frontends.
The problems they’re supposed to solve sound to me like they’re already solved by a good component model. So is this solving an organizational issue rather than technical one? Such as if two teams can’t agree on anything, even shared infra.
E mi piace molto la risposta che gli ha dato Luca Matteis:
I think “micro-frontends” is an overloaded term. Facebook’s frontend has various teams working on different sections. They probably don’t share same tech (Ads uses different stuff from the Wall). You’d still call that micro-frontend I guess
Esattamente come per i microservizi, tutto questo ha un costo in termini di governo dell’entropia che può generare. È per questo che chiunque dovrebbe riflettere benissimo prima di adottare un pattern del genere: perché le persone da cui viene, e le persone che lo propongono, lo propongono come soluzione ai loro problemi, problemi di un’azienda con:
- Centinaia (se non migliaia) di dipendenti
- Centinaia di pagine servite al secondo
- Centinaia di repository e team
Ho sentito parlare di micro-frontend di sfuggita da Facebook. Da Zalando. Ed esattamente come i microservizi, da piccole e medie imprese di quartiere che pensano a risolvere problemi che non hanno prima di mettere un punto a quelli che hanno (tipo la revenue per dipendente, che è un problema che nessun software per quanto ben scritto possa risolvere, ve lo garantisco).
Dare un nome alle cose
E quindi siamo qua. Io ormai ogni volta che sento la parola “micro” come prefisso a qualcosa ho un riflesso della glottide che non è per niente bello da vedere, fidatevi. Allo stesso tempo in queste settimane durante le mie avventure ho capito che è possbile risolvere problemi anche leggendo paper di vent’anni fa, che le architetture alla fine sono sempre tutte un po’ diverse, e che ogni scarrafone è bello a mamma sua.
Come scrivevo poco sopra, per dare un nome alle cose è necessario definirne i tratti formali che le tengano vincolate alla realtà. Per questo motivo preferisco sempre chi mi descrive minuziosamente quello che fa senza tentare di riassumerlo con una buzzword. E sempre per questo motivo all’interno del mio ultimo progetto ho definito un’architettura di servizi chiamata “molecule architecture”, che non voglio spiegarvi proprio perché non mi interessa che diventi uno standard, un pattern, una buzzword. Le ho dato un nome, una definizione formale, e mi tengo tutto stretto perché non ho l’ansia di far vedere quanto sono bravo (anzi, ne ho un po’ vergogna); né ho l’ansia di rifarmi al percorso di altri, se non in parte, perché sono conscio del fatto che le problematiche in cui incorro io sono diverse dalle criticità legate alla gestione del dominio di conoscenza di Netflix o Google o Facebook. Mi auguro che questa generazione di sviluppatori impari a riconoscere i pattern e ad applicare i design solo quando necessari, e che le persone imparino a fuggire dal “micro” a tutti i costi. Perché se è vero che spezzare i problemi è un buon modo per risolverne di grossi a un costo accettabile, una domanda assolutamente legittima è se questo tipo di separazioni dei concetti sia profittevole sul corto, medio, lungo termine. E per chi.
Photos coutesy of Soumil K. and Marcellino Andrian