Cos'è Scala e perché lo trovi nei big data
Cos'è Scala: oggetti e funzionale sulla JVM, il legame con Apache Spark, given e using di Scala 3, i limiti reali e chi dovrebbe impararlo davvero oggi.
Stai leggendo un annuncio per data engineer e tra i requisiti, accanto a Spark e Kafka, compare un linguaggio di cui non hai mai scritto una riga: Scala. Cerchi due esempi e trovi codice che sembra Java scritto da un matematico, pieno di underscore e di tipi annidati. In questo articolo trovi cos'è Scala, perché è finito proprio nel mondo dei big data e se ha senso impararlo oggi.
Cos'è Scala
Scala è un linguaggio a tipizzazione statica che gira sulla Java Virtual Machine e unisce in un unico modello la programmazione a oggetti e quella funzionale, restando pienamente interoperabile con Java: puoi usare qualunque libreria Java da Scala e viceversa.
Il nome viene da "scalable language": l'idea era un linguaggio che andasse bene sia per script di poche righe sia per sistemi enormi. È stato progettato da Martin Odersky all'EPFL di Losanna, un ricercatore che aveva già lavorato sul compilatore Java e sui generici di Java. Non serve ripetere qui come funziona la JVM: se ti manca quel pezzo, parti da cos'è Java.
Oggetti e funzioni nello stesso linguaggio
Molti linguaggi sono "multi-paradigma" nel senso che tollerano più stili. Scala è diverso: prova a fonderli. Ogni valore è un oggetto, ogni funzione è un valore, e le due cose convivono senza che una sia un'aggiunta posticcia all'altra. Se questi termini ti sono poco familiari, il quadro generale è in paradigmi di programmazione.
In pratica significa che hai classi, ereditarietà e interfacce (qui si chiamano trait) come in Java, ma anche collezioni immutabili, funzioni di ordine superiore e pattern matching come nei linguaggi funzionali.
case class Ordine(cliente: String, totale: Double)
val ordini = List(
Ordine("Rossi", 120.0),
Ordine("Bianchi", 45.5),
Ordine("Rossi", 80.0)
)
val totalePerCliente: Map[String, Double] =
ordini
.groupBy(_.cliente)
.map((cliente, lista) => cliente -> lista.map(_.totale).sum)
Nessun ciclo, nessuna variabile modificata: descrivi la trasformazione e il risultato è una nuova mappa. Una case class ti dà gratis costruttore, uguaglianza per valore e stampa leggibile, cose che in Java classico richiedono decine di righe.
Il pattern matching è l'altra metà del fascino:
sealed trait Pagamento
case class Carta(numero: String) extends Pagamento
case class Bonifico(iban: String) extends Pagamento
case object Contanti extends Pagamento
def descrivi(p: Pagamento): String = p match
case Carta(n) => s"carta che termina con ${n.takeRight(4)}"
case Bonifico(i) => s"bonifico da $i"
case Contanti => "contanti"
Il sealed dice al compilatore che i casi possibili sono solo quelli. Se aggiungi un nuovo tipo di pagamento e dimentichi di gestirlo, il compilatore ti avvisa. È lo stesso tipo di garanzia che trovi in Haskell, portato su una piattaforma che le aziende usano già.
Il vero motivo per cui lo incontri: Apache Spark
Qui arriva la parte che quasi nessuna introduzione dice chiaramente. Se oggi incontri Scala, il motivo è quasi sempre uno solo: Apache Spark è scritto in Scala.
Spark è il motore più diffuso per elaborare grandi quantità di dati distribuite su molte macchine. È nato in ambito accademico, è diventato un progetto Apache ed è stato adottato da un'enorme quantità di aziende per pipeline di dati, ETL e analisi su larga scala. Le sue API native sono in Scala, le prime funzionalità nuove storicamente arrivavano prima lì, e chi voleva spremere il massimo da Spark scriveva Scala.
Il mondo dei big data si è quindi portato dietro il linguaggio. Un job Spark in Scala ha questo aspetto:
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions.{sum, desc}
val spark = SparkSession.builder.appName("vendite").getOrCreate()
val vendite = spark.read
.option("header", "true")
.option("inferSchema", "true")
.csv("vendite.csv")
vendite
.groupBy("regione")
.agg(sum("importo").as("totale"))
.orderBy(desc("totale"))
.show()
Chi conosce SQL riconosce subito la logica: è un GROUP BY con una somma e un ordinamento, eseguito in parallelo su un cluster. Il legame con SQL non è casuale, perché Spark offre anche un'interfaccia SQL diretta.
PySpark: la verità scomoda
Va detto subito: per usare Spark oggi non serve Scala. Esiste PySpark, l'interfaccia Python, e nella maggior parte dei team di dati è la scelta più comune. Il motivo è semplice: chi lavora con i dati conosce già Python, e con le API a DataFrame la differenza di prestazioni tra Python e Scala si è ridotta molto, perché il lavoro pesante lo fa comunque il motore di Spark.
Scala resta avvantaggiato in alcuni casi precisi: quando scrivi funzioni personalizzate che girano su ogni riga, quando lavori sul codice interno di Spark o di librerie collegate, quando il resto dell'infrastruttura è già su JVM. Fuori da questi casi, Python è la strada più battuta.
Il sistema di tipi: potenza vera, rischio vero
Scala ha uno dei sistemi di tipi più espressivi tra i linguaggi usati in produzione. Il compilatore inferisce molto, quindi scrivi meno annotazioni di Java, ma dietro puoi costruire astrazioni molto sofisticate.
Il meccanismo più potente e più discusso sono gli impliciti: valori e conversioni che il compilatore inserisce da solo, cercandoli nel contesto. In Scala 2 la stessa parola chiave implicit serviva a scopi diversi, ed era una fonte classica di confusione. In Scala 3 sono stati ripensati come given e using, con una sintassi che rende esplicita l'intenzione:
trait Formato[A]:
def mostra(a: A): String
given Formato[Double] with
def mostra(d: Double): String = f"$d%.2f euro"
def stampa[A](valore: A)(using f: Formato[A]): Unit =
println(f.mostra(valore))
stampa(12.5) // il compilatore trova da solo il Formato[Double]
Quando si chiama stampa, nessuno passa il formato: il compilatore cerca un given del tipo giusto e lo inserisce. È il modo in cui si costruiscono librerie flessibili, estendibili senza toccarne il codice.
Il rovescio è altrettanto reale. Usati con misura, questi strumenti rendono il codice elegante. Abusati, lo rendono illeggibile: leggi una riga e non sai quale codice verrà eseguito davvero, perché metà degli argomenti li ha scelti il compilatore da qualche import lontano. Le basi di codice Scala mal gestite sono famose proprio per questo.
Scala 2 e Scala 3: la frattura
Scala 3 non è un semplice aggiornamento. Ha cambiato sintassi (le parentesi graffe sono diventate opzionali, con l'indentazione significativa che vedi negli esempi sopra), ha riscritto il sistema degli impliciti e ha rimosso alcune funzionalità avanzate di Scala 2, in particolare il vecchio sistema di macro.
Esiste una compatibilità tra le due versioni, ma il passaggio non è stato indolore: alcune librerie hanno impiegato molto tempo per essere disponibili su Scala 3, e Spark stesso è rimasto a lungo legato a Scala 2. Quando cerchi tutorial, controlla sempre per quale versione sono scritti: su progetti Spark ti capiterà spesso di trovare ancora Scala 2. Verifica alla fonte lo stato attuale della compatibilità tra le versioni che ti servono.
I limiti, detti onestamente
Kotlin ha preso gran parte dello spazio del "Java migliore". Per anni Scala è stato l'alternativa per chi voleva un Java più conciso sulla JVM. Poi è arrivato Kotlin: più semplice, più vicino a Java, con strumenti eccellenti e l'adozione su Android. Chi cercava solo meno verbosità è andato lì.
La compilazione è lenta. Un sistema di tipi così ricco ha un costo, e su progetti grandi i tempi di build si sentono. Gli strumenti di compilazione incrementale aiutano, ma chi arriva da Go o da Java lo nota subito.
La comunità è divisa tra stili. C'è chi scrive Scala come un Java migliore, pragmatico e orientato agli oggetti, e chi lo usa per programmazione funzionale pura, con librerie come Cats o ZIO e concetti presi dalla teoria delle categorie. Due progetti Scala possono sembrare scritti in linguaggi diversi, e passare da uno all'altro richiede tempo.
Il mercato è di nicchia. Le offerte esistono, ma si concentrano in data engineering, fintech e aziende con infrastruttura JVM già consolidata. Non è un linguaggio con cui "trovi lavoro ovunque".
| Situazione | Scala ha senso? | Perché |
|---|---|---|
| Pipeline Spark su team JVM | Sì | API native, stesso ecosistema del resto |
| Spark in un team di data scientist | Poco | PySpark è più comune e più semplice |
| Backend Java da modernizzare | Poco | Kotlin è la scelta più diffusa |
| Primo linguaggio | No | Troppi concetti insieme, curva ripida |
| Studiare programmazione funzionale sulla JVM | Sì | È il posto più maturo per farlo |
Errori comuni
Impararlo "per fare big data" senza guardare il team. Se il gruppo in cui vuoi entrare usa PySpark, Scala è un investimento che non verrà ripagato subito. Guarda gli annunci reali prima di scegliere.
Abusare di impliciti e operatori simbolici. Definire operatori come |+| o ~> e conversioni automatiche sembra elegante mentre scrivi. Sei mesi dopo, nessuno, tu compreso, capisce il codice.
Mescolare tutorial Scala 2 e Scala 3. La sintassi degli impliciti, le macro e la struttura dei blocchi sono cambiate: copiare un esempio vecchio in un progetto nuovo porta a errori di compilazione incomprensibili.
Portare la mentalità Java senza cambiarla. Usare var ovunque, collezioni mutabili e null significa pagare la complessità di Scala senza averne i vantaggi. Parti da val, collezioni immutabili e Option.
Buttarsi subito sul funzionale puro. Monadi, effetti e type class sono potenti, ma affrontarli prima di aver scritto codice Scala semplice è il modo più rapido per abbandonare.
In sintesi
Scala unisce oggetti e programmazione funzionale sulla JVM, con un sistema di tipi molto ricco e piena interoperabilità con Java: puoi usare tutto l'ecosistema esistente senza riscrivere nulla.
Lo incontri quasi sempre per via di Apache Spark, che è scritto in Scala e ha trascinato il linguaggio nel mondo dei big data. Ma per usare Spark oggi PySpark è spesso la scelta più comune, e questo va tenuto presente prima di investire tempo.
I limiti sono concreti: compilazione lenta, impliciti che rendono il codice opaco se abusati, una comunità divisa tra stili, la frattura tra Scala 2 e Scala 3 e un Kotlin che ha occupato lo spazio del Java più moderno.
Chi dovrebbe impararlo: chi lavora già, o vuole lavorare, nel data engineering su JVM, dove Spark, Kafka e il resto dell'infrastruttura parlano la stessa lingua. Per tutti gli altri ci sono strade più corte.
Per capire dove si colloca rispetto agli altri linguaggi, il quadro completo è in tutti i linguaggi di programmazione. Se invece stai costruendo le basi, trovi i percorsi strutturati nei corsi.
Contenuto redatto con l'assistenza di strumenti di intelligenza artificiale e rivisto dalla redazione di Codegrind, che ne è responsabile. Hai trovato un errore? Scrivici.