Uploaded avatar of xavdid

Una riflessione su #12in23 da chi l'ha completata

@xavdid
Oltre 2 anni fa

Questo post è apparso originariamente sul sito di David ed è ripubblicato qui con il suo permesso

Lo scorso gennaio, Exercism ha annunciato un nuovo programma chiamato 12in23, che sfidava i partecipanti a provare 12 nuovi linguaggi di programmazione nel 2023. Ogni mese avrebbe avuto un tema (come «Aprile analitico» o «Ottobre orientato agli oggetti») e avrebbe messo in evidenza linguaggi specifici da provare. Adoro imparare cose nuove e sono diventato un po' un nerd dei linguaggi (di programmazione), quindi ho deciso di provarci. 12 linguaggi, 12 mesi!

Ora che l'anno è quasi finito, sono incredibilmente soddisfatto di come è andato il progetto. Ho provato con successo 12 nuovi linguaggi, ho conosciuto persone fantastiche nella community di Exercism e ho pubblicato alcune belle contribuzioni open source lungo il cammino! In questo post li ripercorro tutti e racconto cosa mi ha dato ciascuno.

Scegliere i linguaggi

Ho stabilito alcune linee guida per l'anno, per aiutarmi a sfruttare al meglio l'esperienza:

  1. I linguaggi dovevano essere del tutto nuovi per me, o almeno abbastanza poco familiari da darmi la sensazione di imparare molto.
  2. I linguaggi scelti dovevano essere (potenzialmente) utili perché io potessi approfondirli in futuro. Questo progetto era solo per divertimento, ma voglio passare il tempo a imparare cose (almeno in parte) utili.
  3. Avrei installato tutti gli strumenti locali ed il plugin di VSCode per ogni linguaggio che usavo. Volevo confrontare i linguaggi più o meno alla pari, con quanti più type hint ed intellisense possibile. Al college facevo tutti i compiti di programmazione in Sublime Text senza alcun linting o completamento automatico. Temevo che, se avessi imparato a programmare usando tutti quegli strumenti, ci avrei fatto troppo affidamento e non sarei stato un buon programmatore. È successo l'opposto. Quanta più cognizione riesco a scaricare sui miei strumenti, tanto più posso pensare al problema vero e proprio. Non ricordare le cose, ricorda come trovarle.

Iniziamo!

Gennaio (senza tema)

Quando è iniziato gennaio, il team di Exercism stava ancora scegliendo i temi mensili, quindi il linguaggio di quel mese è stato a scelta libera. Non avendo una direzione, ho inaugurato l'anno con Go. Avevo fatto un corso intensivo del linguaggio a metà 2022, ma da allora non l'avevo usato molto e non mi sentivo affatto competente.

Go è un linguaggio interessante. Il suo compilatore severo significa che il tuo programma sarà corretto e non ti muovi di un millimetro finché non ritiene che sia sicuro farlo.1 Il suo approccio prolisso alla gestione degli errori significa che non hai mai sorprese (al costo di scrivere if err != nil { return err } tantissime volte). Fa un buon lavoro rendendo facili le cose difficili (come il parallelismo tramite i canali) ma rende anche difficili alcune cose facili (la manipolazione delle stringhe). Ha una libreria standard robusta, il che significa che puoi portare a termine la maggior parte dei compiti senza moduli di terze parti. Mi piace quanto dell'ecosistema (formattazione, installazione, build, ecc.) sia first-party ed integrato nel comando go. Il linguaggio ha i suoi detrattori, ma penso che raggiunga in gran parte i suoi obiettivi di correttezza e manutenibilità.

Non mi è piaciuto usarlo al punto da sceglierlo come prima opzione, ma è un ottimo strumento da tenere nella cassetta degli attrezzi per i programmi sensibili alle prestazioni, come mostrare il percorso annidato nel mio prompt della shell.

Febbraio funzionale

Febbraio è entrato subito nel vivo con i linguaggi funzionali, un ramo molto matematico dei più comuni linguaggi di programmazione imperativi. I linguaggi funzionali sono noti per le loro funzioni «pure» (senza effetti collaterali). Ho scelto Elixir, soprattutto perché il mio amico Caleb l'ha usato per Advent of Code e ne parla entusiasta.

Mi sono divertito parecchio con Elixir. Si è ispirato a Ruby (il che ha senso; il suo creatore, José Valim, è stato un collaboratore principale di Rails). Ho trovato semplice esprimere concetti funzionali come il concatenamento dei metodi. Ho adorato tutto lo zucchero sintattico che lo rendeva facile, come l'operatore pipe (|>):

foo(bar(baz(new_function(other_function()))))
# becomes
other_function() |> new_function() |> baz() |> bar() |> foo()

È stata anche la mia prima volta con le macro, cioè codice che scrive codice. Poiché i programmi Elixir possono essere espressi in un AST che è esso stesso codice Elixir valido, è facile scrivere codice che produce altro codice valido. È un concetto davvero bello che Elixir ha reso facile. Mi è anche piaciuto il modo in cui le funzioni potevano fare pattern matching sulla forma dei loro argomenti, così le chiamate alle funzioni potevano essere indirizzate all'implementazione appropriata:

defmodule TuplePrinter do
  def print({a}) do
	IO.puts("single")
	IO.puts(a)
  end

  def print({a, b}) do
	IO.puts("double")
	IO.puts(a)
	IO.puts(b)
  end
end

TuplePrinter.print({1})
TuplePrinter.print({2, 2})

# single
# 1
# double
# 2
# 2

Sembra il tipo di funzionalità che o è fantastica o trasforma il tuo codice in un piatto di spaghetti. In ogni caso, era un concetto interessante!

Elixir trae anche vantaggio dal girare dentro la macchina virtuale BEAM di Erlang, che gli dà un grande ecosistema con cui comunicare. È ottimo per la concorrenza ed è il cuore dell'amato framework web Phoenix.

Anche se non ho un bisogno immediato di usare Elixir, l'ho trovato davvero divertente con cui lavorare e sicuramente qualcosa che sarei aperto a riprendere. Inoltre, è stata una sfida interessante affrontare problemi familiari in modi poco familiari (ovvero, in modo ricorsivo).

Marzo meccanico

Marzo si è concentrato sui linguaggi «di sistema», che si compilano in codice macchina.

Tra le opzioni, Go era l'unico linguaggio che mi interessava.2 Ora, i lettori attenti noteranno che avevo già fatto un mese di Go, quindi ripeterlo non avrebbe contato ai fini dei miei 12. Beh, quando l'ho scelto per gennaio, non avevano ancora annunciato i temi, quindi non mi ero reso conto che mi stavo cacciando in un angolo.

Se avessi saputo che stava arrivando Bun, probabilmente avrei provato Zig, ma purtroppo non potevo (ancora) prevedere il futuro. Quindi, in mancanza di una scelta più convincente, ho optato per un mese extra di Go, consapevole che più avanti nell'anno avrei dovuto riutilizzare un linguaggio già fatto.

Aprile analitico

Aprile è stato dedicato ai linguaggi più popolari per la data science. Conoscevo Python fin troppo bene e avevo fatto R in un corso di statistica all'università (e non mi era piaciuto), quindi Julia!

Mi sono divertito a usarlo, ma soprattutto perché sembrava così simile a Python. Era un po' inquietante: come essere americano in Canada. Tutto sembra molto familiare, ma è solo un pochino diverso, in un modo difficile da definire. All'improvviso qualcuno ti offre una moneta da 2 dollari (o una funzione che è davvero ben congegnata per fare calcoli con le matrici) e ti accorgi che non sei più nel Kansas.

La cosa che mi ha colpito di più è stato il sistema di tipi di Julia. Era annotato (facoltativamente) come il sistema di tipi di Python, ma aveva controlli a runtime per assicurarsi che gli argomenti corrispondessero ai tipi dichiarati. Penso che il sistema di Python trovi il giusto equilibrio tra l'integrarsi con gli strumenti e il non intralciarti, ma ammetto che anche gli errori a runtime di Julia per le funzioni con tipi sbagliati erano utili.

Alla fine Julia era carino, ma non è qualcosa che penso mi servirà in futuro.

Maggio del cambio di mentalità

Maggio ha raddoppiato la posta su «provare qualcosa di nuovo», mettendo in evidenza linguaggi che fanno cose molto insolite. Ho colto l'occasione per provare il sempre popolare Rust. Devo ammetterlo, capisco l'hype.

Anche se il famigerato borrow checker richiede senz'altro un po' di abitudine, mi è piaciuto il modo in cui mi faceva riflettere più attentamente sui miei programmi. Il compilatore era senz'altro severo, ma i messaggi di errore facevano davvero di tutto per aiutarmi a risolvere i problemi. Non dirò che sono stato particolarmente produttivo nella prima settimana, ma mi sembra di riuscire almeno a vedere la cima della curva di apprendimento.

Anche cargo, il gestore di pacchetti di Rust, merita una menzione speciale. Anche se non ho installato pacchetti di terze parti, le sue funzionalità di build, test e formattazione erano ottime. Lo stesso vale per la sua estensione per VSCode, che aveva tutte le comodità che mi aspetterei da un linguaggio a tipizzazione statica come Rust. Una buona esperienza per gli sviluppatori fa davvero tutta la differenza.

Anche se a livello implementativo sono molto diversi, Rust mi è sembrato simile a Go per l'uso che ne farei: far girare i programmi molto velocemente. Molti strumenti nei linguaggi che uso regolarmente stanno iniziando a passare a Rust per le sue caratteristiche di prestazioni, quindi prevedo di vederlo di più in futuro (anche se non sarò io a scrivere Rust).

Estate delle sexp (giugno)

Giugno è stato il mese delle S-expression, una forma sintattica comune nei lisp. Ho scelto Clojure, un linguaggio funzionale che gira sulla JVM.

Avevo scritto un po' di Clojure molti anni fa. Ero appena uscito dalla scuola e sono diventato l'unico manutentore di uno script giornaliero essenziale per il business al mio primo lavoro. Inutile dirlo, è stato un periodo complicato. Ero curioso di vedere se, ora che ero più vecchio e più saggio, fosse un po' più accessibile.

Sono felice di poter dire che lo era! L'esperienza funzionale di febbraio mi ha aiutato a pensare in modo ricorsivo e la sintassi non era poi così male, quando ci si metteva davvero. Anche la sua interoperabilità con la JVM sarebbe utile se lo usassi in un progetto più grande.

Non mi vedo ad usare Clojure per qualcosa, finché ci sono alternative disponibili, ma non è stata un'esperienza del tutto spiacevole.

Missione secondaria: l'Universal Test Runner!

Per anni ho usato una piccola funzione bash per eseguire i test unitari nella mia directory corrente. Mentre lavoravo con tutti questi nuovi linguaggi, mi sono ritrovato ad aggiungerci righe per comodità; ricordarsi di eseguire t era molto più facile che reimparare ogni volta il comando di test specifico di ogni linguaggio.

Dato che la logica richiesta andava oltre la mia zona di comfort con bash, a giugno mi sono preso un po' di tempo e ho trasformato il progetto in una cosa a sé stante: l'Universal Test Runner.

L'ho condiviso nel forum di Exercism e ho ricevuto un'accoglienza positiva. È piaciuto così tanto che abbiamo deciso di integrare una funzionalità simile direttamente nella CLI di Exercism (che è scritta in Go, un argomento che per fortuna avevo appena ripassato). Così, per la seconda metà dell'anno, potevo eseguire exercism test per lanciare la suite di test del linguaggio di quel mese (un comando supportato nativamente nell'Universal Test Runner).

Se vuoi saperne di più sul processo, ne ho scritto con molti più dettagli quando è stato lanciato.

Comunque, andiamo avanti!

Luglio giurassico

Luglio ha messo in mostra i linguaggi vecchi. Questo mese le opzioni erano piuttosto scarse in termini di praticità. Ho iniziato con il venerabile COBOL, dato che avevo sentito che faceva ancora funzionare un sacco di infrastrutture critiche. Ma, con un matrimonio ad inizio agosto che incombeva su di me, non avevo la testa per mettermi ad imparare un linguaggio così diverso da quelli a me familiari. Così, invece, sono passato a Visual Basic, che sembrava l'opzione meno peggiore.

Non c'è molto da dire qui. Il linguaggio sembrava un po' prolisso, ma abbastanza facile da usare. Da quanto ho capito, era pensato soprattutto per lo sviluppo di interfacce utente su Windows, quindi fare piccoli esercizi rende difficile farsi un'idea precisa del tutto.

Agosto delle app

Agosto è stato inondato dai linguaggi con cui si costruiscono le app. Come prevedibile, questo mese c'erano molte scelte. Ho scelto Swift. Dato che uso molti prodotti Apple, il loro linguaggio creato su misura è piuttosto rilevante per me. Non era del tutto nuovo per me: nel 2016 ho pubblicato una singola app iOS scritta interamente in Swift. Ma da allora non avevo più toccato il linguaggio ed è evoluto parecchio, quindi ho pensato che contasse comunque.

Sono rimasto piacevolmente sorpreso da quanto fosse facile lavorarci. A differenza di molti degli altri linguaggi qui, Swift è piuttosto nuovo. È stato rilasciato per la prima volta nel 2014 e ha chiaramente tratto beneficio dalle lezioni di progettazione dei linguaggi moderni. Ha un gestore di pacchetti first-party, l'optional chaining, funzioni di prima classe e un'interpolazione di stringhe sensata. Era ergonomico da leggere e da scrivere, anche senza usare Xcode.

Detto questo, Swift è utile soprattutto nel contesto delle app per le piattaforme Apple, che al momento non sviluppo. Anche se ha funzionato bene per gli esercizi, non prevedo di tornarci presto. Però adoro poterlo scrivere sul mio iPad!

Settembre minimalista

Settembre ha esplorato linguaggi molto concisi o piccoli. Ho scelto jq, uno strumento che uso ed adoro da anni.

Però l'ho sempre considerato solo uno strumento per lavorare con JSON, non un linguaggio di programmazione general-purpose. Sono rimasto piacevolmente sorpreso nel vedere che ha tutte le caratteristiche normali (funzioni, variabili, cicli, ecc.), quindi ho potuto scrivere programmi piuttosto complessi:

# input: { "series": "1", "sliceLength": 1 }
. as {series: $series, sliceLength: $sliceLength} |
if
  $series == "" then
	"series cannot be empty" | halt_error
  elif $sliceLength > ($series | length) then
	"slice length cannot be greater than series length" | halt_error
  elif $sliceLength == 0 then
	"slice length cannot be zero" | halt_error
  elif $sliceLength < 0 then
	"slice length cannot be negative" | halt_error
  else
	.
end
| [range(0; $series | length)]
| map($series[. : . + $sliceLength])
| map(select(. | length == $sliceLength))

È stato divertente provare tutte le funzionalità di jq di cui non avevo mai avuto bisogno per semplici trasformazioni di dati. Anche se gli strumenti qui erano un po' carenti (nessuna integrazione con l'editor, ecc.), una comprensione più profonda dell'ampiezza delle funzionalità di jq è stata preziosa.

modifica: DJ Adams su Mastodon mi ha segnalato il progetto jq-lsp ed il suo plugin per VSCode corrispondente. Questa volta me la sono persa, ma in futuro ci darò un'occhiata.

Ottobre orientato agli oggetti

Ottobre ha approfondito i linguaggi orientati agli oggetti. Ho un debole per la progettazione OO, che rispecchia da vicino come visualizzo i programmi nella mia testa. Ho scelto Ruby, che potrebbe sembrare una scelta strana.

Lavoro in Stripe, sede della più grande codebase Ruby del mondo. Di sicuro non poteva valere come linguaggio «poco familiare»? Anche se è tutto vero, il nostro monolite Ruby sembra molto lontano dal Ruby «standard»: tutto è controllato a livello di tipi con Sorbet, c'è tantissima generazione di codice e facciamo un sacco di magie per far funzionare e scalare tutto insieme. Anche se il Ruby dentro e fuori Stripe è in fondo lo stesso linguaggio, lavorare a scale così diverse offre esperienze molto diverse; volevo sapere com'era la vita fuori (negli anni da quando avevo usato Ruby intensamente).

In gran parte, è andata bene! Ruby stesso è ottimo e cita la «felicità del programmatore» come obiettivo principale, che ha trovato eco in me. Mi piace quanto spesso riesca ad indovinare il nome di funzioni della libreria standard che non ho mai usato. Mi piace quanto sia facile costruire codice funzionale e quanto la sintassi sia ergonomica ed espressiva.

Detto questo, sono rimasto sorpreso da quanto gli strumenti per gli sviluppatori fossero indietro rispetto a Python. Forse sono stato viziato, ma avere i type hint nell'editor ed avere linting e formattazione estremamente veloci è per me più importante di quanto pensassi. Per un linguaggio popolare come lo è stato Ruby al suo apice, sono rimasto sorpreso da quanto sembrasse indietro da questo punto di vista.3 Non mi sono mai abituato del tutto alle parentesi facoltative nelle chiamate di funzione, il che rendeva meno immediato passare funzioni come argomenti.

Ruby resta un ottimo linguaggio e continuerò a usarlo al lavoro, ma non fa niente per me che Python non faccia già, almeno per ora.

Novembre a piccoli morsi

Novembre è stato il mese più difficile finora: i linguaggi assembly. Anche se non è più comune scriverli a mano, è un argomento utile ed interessante da conoscere. Ho scelto WebAssembly per la sua importanza per il web moderno e futuro. Anche se di solito viene usato come target di compilazione (e non è qualcosa che si scrive a mano), esistono degli strumenti per gli sfegatati là fuori.

Per questo mese mi sono sentito insolitamente ben preparato. La sintassi sembrava quella di Clojure e la struttura del linguaggio sembrava quella di TIS-100 di Zachtronics. Stranamente mi è piaciuto dover partire da zero per ogni operazione; sembrava d'altri tempi. Lo odierei se dovessi davvero concludere qualcosa in questo modo, ma nel frattempo è stata una curiosità divertente. Con commenti generosi, sono riuscito a scrivere qualcosa di quasi leggibile:

(module
  (func (export "eggCount") (param $number i32) (result i32)
	(local $res i32) ;; result
	(local $remainder i32) ;; loop counter

	(loop $loop

  	;; $res =
  	(local.set $res
    	;; $res +
    	(i32.add
      	(local.get $res)
      	;; $number % 2
      	(i32.rem_u
        	(local.get $number)
        	(i32.const 2)
      	)
    	)
  	)

  	;; $number //= 2
  	;; (keep on stack)
  	(local.tee $number
    	(i32.div_u
      	(local.get $number)
      	(i32.const 2)
    	)
  	)

  	;; this will keep looping until remainder is 0
  	br_if $loop
	)

	local.get $res
  )
)

L'ostacolo più grande è stata la mancanza di documentazione e risorse. Era persino difficile capire quali funzioni globali fossero disponibili. Ma dato che non userò davvero questo linguaggio, una volta che ho preso il via non mi ha dato troppo fastidio.

Dicembre ha chiuso l'anno con linguaggi che non rientravano in altre categorie. Dato che a marzo avevo riutilizzato un linguaggio, questo mese dovevo completarne due.

Ho iniziato con Wren. Creato da Bob Nystrom, noto tra le altre cose per Crafting Interpreters. Mi ha conquistato per la sua attenzione ai dettagli, le dimensioni contenute e il design top-down; tutto sembra molto ben ponderato. Quel livello di cura è evidente nei dettagli dello scope delle variabili e delle regole di privacy. Il suo compilatore è piccolo e ricco di commenti, quindi è un'ottima risorsa di apprendimento se ti interessano le implementazioni dei linguaggi.

Wren è un po' grezzo e sembra essere per lo più abbandonato, ma penso che per un linguaggio giocattolo vada bene. Nessuno si avvicina a questo aspettandosi che sia pronto per la produzione. C'è sicuramente spazio nel mondo per i linguaggi non destinati alla produzione.

Inoltre: Lua

La mia seconda scelta questo mese è stata Lua. A differenza di Wren, è incredibilmente pratico. Il fatto che sia facile da incorporare fa sì che compaia in molti posti, come lo scripting in Redis e le mod di Factorio. Il modello a oggetti ha richiesto un po' di abitudine, ma vedo come potrei diventare produttivo in fretta. Mi sono affezionato in fretta alle tabelle come struttura che fa tutto. Gli strumenti erano buoni: il gestore di pacchetti funzionava da subito e l'estensione per VSCode supportava le annotazioni di tipo basate su commenti senza problemi.

Anche se non ho nulla per cui mi serva subito Lua, è un altro ottimo strumento da tenere nella cassetta degli attrezzi, vista la sua diffusione.

Tiriamo le somme

Questo giro tra i linguaggi mi è piaciuto più di quanto pensassi. Non solo ho imparato alcune nuove competenze pratiche, ma sento di aver davvero ampliato i miei orizzonti.

Quanto a cosa viene dopo, penso che sarà imparare molto più Rust. A questo punto la sua importanza nel panorama degli strumenti per sviluppatori è evidente, e voglio assicurarmi di saper leggere e contribuire alle cose su cui faccio affidamento.

Non ho in mente un obiettivo concreto, ma ho tutto il libro di Rust da leggere, un corso Rust for JS devs che mi sono fatto rimborsare un anno fa, ed un'intera traccia di Exercism da completare. Mi piacerebbe contribuire ad almeno un progetto open source (probabilmente Just, un mio nuovo programma preferito), ma vedremo dove mi porterà l'anno.

Fino ad allora, buone feste e buon proseguimento del tuo 2023!

  1. Le variabili inutilizzate sono un errore di compilazione?? Cioè, ma dai ↩

  2. In realtà ho provato prima C++ (che non scrivevo dai tempi dell'università). Semplicemente non era divertente, quindi l'ho abbandonato ↩

  3. Questo è un altro modo in cui il Ruby «reale» differisce dalla mia esperienza in Stripe, quindi sono contento di averlo potuto provare in entrambi i modi ↩

05 gennaio 2024 · Ti è stato utile?