(fonte: pexels.com)

Spesso sentiamo, impariamo e addirittura usiamo termini o frasi che non comprendiamo pienamente. Trovo che questo sia abbastanza comune all’interno della comunità di sviluppo software, che si tratti di RESTful Web APIs, metodologia Agile, Machine Learning, o qualche altro termine. Questa non è necessariamente una cosa negativa, ma è importante capire quando si conosce veramente qualcosa e quando se ne conosce solo il nome.

Per me, Systems Programming è uno di questi termini. Vorrei provare a spiegare, usando un linguaggio semplice, cosa significa.

Prima di poter capire cosa comporta la Programmazione dei Sistemi, dobbiamo prima capire cos’è un Sistema. Il software tende a rientrare in uno dei due campi, il software di sistema e il software applicativo.

Il software di sistema è il software per computer progettato per fornire una piattaforma ad altri software. Esempi di software di sistema includono sistemi operativi, software di scienza computazionale, motori di gioco, automazione industriale e applicazioni software come servizio.
… Tale software non è considerato software di sistema quando può essere disinstallato di solito senza influenzare il funzionamento di altri software.
– wikipedia.org

Il software di sistema è una piattaforma composta da programmi e servizi del sistema operativo (OS), comprese impostazioni e preferenze, librerie di file e funzioni utilizzate per le applicazioni di sistema. Il software di sistema include anche i driver dei dispositivi che eseguono l’hardware e le periferiche di base del computer.
– techopedia.com

Il software di sistema si riferisce ai file e ai programmi che compongono il sistema operativo del computer. I file di sistema includono librerie di funzioni, servizi di sistema, driver per stampanti e altro hardware, preferenze di sistema e altri file di configurazione. I programmi che fanno parte del software di sistema includono assemblatori, compilatori, strumenti di gestione dei file, utility di sistema e debugger.
– techterms.com

La definizione di Wikipedia è molto vaga su ciò che è considerato software di sistema finché fornisce servizi ad altre applicazioni. Tuttavia le altre due definizioni si concentrano puramente sul sistema operativo – driver, kernel, librerie e funzioni (pensate ai file header del kernel/libc e agli oggetti condivisi). Questo implica una stretta relazione con l’hardware. Se guardiamo un altro articolo di Wikipedia sulla programmazione dei sistemi vediamo:

La programmazione dei sistemi richiede un grande grado di consapevolezza dell’hardware.

L’articolo continua ad implicare che una parte fondamentale della programmazione dei sistemi è la necessità che le cose siano molto veloci. Questo ha senso perché avremmo bisogno di sapere molto sull’hardware. Ha anche senso che la velocità (prestazioni) sia una parte centrale della programmazione dei sistemi se è una piattaforma per altri software.

Se la parte più centrale della vostra applicazione (la “piattaforma” del software di sistema) è lenta, allora l’intera applicazione è lenta. Per molte applicazioni, specialmente in scala, questo sarebbe un motivo di rottura.

System Software in a Nutshell

Le citazioni di cui sopra e altre risorse mi hanno portato ai seguenti criteri per definire il software di sistema:

  • Fornisce una piattaforma per altri software da costruire sopra.
  • Si interfaccia direttamente o strettamente con l’hardware del computer per ottenere le prestazioni necessarie ed esporre astrazioni (come parte della piattaforma).

Cosa è e cosa non è software di sistema

Esempi di ciò che è software di sistema:

  • Kernel dell’OS
  • Driver
  • Bare Metal Hypervisors (es.g. Hyper-V e VM Ware ESXi)
  • Compilatori (che producono binari nativi) e debugger

Esempi di ciò che non è software di sistema:

  • Applicazione chat GUI (Slack, Discord, ecc)
  • Applicazione JavaScript basata sul web
  • Web Service API

Si noterà che mentre le Web Service API forniscono un servizio ad altri software, non interagiscono (tipicamente) con l’hardware per esporre astrazioni su di esso. Tuttavia ci sono applicazioni che rientrano in una zona grigia intermedia. Quelle che mi vengono in mente sono le applicazioni di calcolo ad alte prestazioni e il software embedded.

Le applicazioni di calcolo ad alte prestazioni (HPC), come il trading in tempo reale nelle borse, non espongono tipicamente una piattaforma, ma è comune per loro scrivere codice che si interfaccia direttamente con l’hardware. Un esempio potrebbe essere il bypassare lo stack di rete offerto dal kernel e implementare il proprio stack di rete che parla direttamente alla NIC (o alle NIC). In questo modo possiamo vedere come il software HPC condivida molte somiglianze con il software di sistema, interagendo direttamente con l’hardware al fine di fornire gli aumenti di prestazioni necessari.

Anche lo sviluppo del software embedded condivide molte somiglianze con il software di sistema, in quanto il codice è scritto per interfacciarsi direttamente con l’hardware. Tuttavia, qualsiasi astrazione fornita è tipicamente consumata dallo stesso software e non potrebbe essere considerata una piattaforma.

È importante notare le applicazioni che condividono somiglianze con la nostra definizione di software di sistema poiché probabilmente vedrete quelle applicazioni/lavori descritti in questi termini (software di sistema, ingegneri di sistema, ecc.)

Programmazione di sistemi (+ linguaggi)

(Photo by Roman Spiridonov on Unsplash)

Dopo aver definito i sistemi, possiamo ora definire la programmazione di sistemi come l’atto di costruire software di sistema usando linguaggi di programmazione di sistema. Abbastanza semplice, giusto?

Beh, c’è una cosa che abbiamo saltato, i linguaggi. La gente spesso parla dei linguaggi di programmazione di sistema in modi come “X è grande, è veloce, compilato e un linguaggio di programmazione di sistema”. Ma siamo tutti d’accordo su cosa sia un linguaggio di programmazione di sistemi?

Viste le nostre definizioni di sistemi, definirei i criteri per un linguaggio di programmazione di sistemi come:

  • Compilato in binario nativo
  • Può essere costruito senza dipendenze da altri software (incluso un kernel)
  • Caratteristiche prestazionali simili ad altri linguaggi di programmazione di sistemi

Disclaimer: Questa è la mia definizione. Poiché non esiste un criterio prestabilito, sto ricavando una definizione da ciò che ha senso per me dato il contesto in cui ho definito il software di sistema.

Compilare in binario nativo

Se un linguaggio non può compilare in un eseguibile che sia direttamente interpretabile dalla CPU allora, per definizione, è in esecuzione su una piattaforma (es. JVM, Ruby VM, Python VM, ecc.). Ci possono essere alcune argomentazioni da fare qui, ma per semplicità penso che questo sia un criterio adatto.

Nessuna dipendenza

L’argomento è simile alla compilazione su un binario nativo. Se il linguaggio richiede sempre che qualche altro software sia presente per essere eseguito, allora è in esecuzione su una piattaforma. Un esempio di questo è Go e la sua libreria standard inclusa. Richiede il supporto del sistema operativo per eseguire azioni di base come l’allocazione della memoria, lo spawning dei thread (per le goroutine da eseguire), per il suo poller di rete integrato, e altre azioni. Mentre è possibile reimplementare queste funzioni di base, ciò crea una barriera all’uso in questo contesto ed è facile immaginare perché non tutti i linguaggi, anche quelli che compilano binari statici, sono intesi come linguaggi di programmazione di sistema.

Caratteristiche di prestazione simili

Questa è un po’ una scappatoia. Tuttavia, è per dire che all’interno del sistema di linguaggi tipicamente classificati come linguaggi di programmazione di sistema, non ci dovrebbero essere grandi (ordine di grandezza) differenze nelle caratteristiche di prestazione. Per caratteristiche mi riferisco esplicitamente alla velocità di esecuzione e all’efficienza della memoria.

Il golden standard per il confronto è C e/o C++ come è spesso rappresentato nei benchmark comparativi, che misurano la velocità di esecuzione in quanti ordini di grandezza i linguaggi sono più lenti di C/C++.

Nominandone alcuni

I linguaggi che vengono in mente immediatamente, data la definizione di cui sopra sono C e C++. Ma ci sono anche linguaggi più recenti come Rust e Nim che riempiono questa nicchia. Infatti, c’è già un sistema operativo scritto interamente in Rust (RedoxOS) e un kernel in Nim (nimkernel).

Parliamo di Go

Prima ho accennato al fatto che Go potrebbe non rientrare nella famiglia dei “linguaggi di programmazione dei sistemi”. Tuttavia, proprio come non tutte le applicazioni si adattano bene al software applicativo e al software di sistema, nemmeno i linguaggi lo fanno.

Spesso le persone chiamano Go un linguaggio di programmazione di sistemi e anche golang.org è citato come:

Go è un linguaggio generico progettato con la programmazione di sistemi in mente.

Tuttavia, anche questa non è una dichiarazione esplicita che Go è un linguaggio di programmazione di sistemi, semplicemente che è progettato con questo in mente. Trovo che si trovi piuttosto nel mezzo.

Sebbene Go compili in binari nativi, contenga utili concetti di basso livello (puntatori raw/unsafe, tipi nativi come byte e int32, e supporto all’assemblaggio in linea), ed è relativamente performante; ha ancora alcune sfide da superare. Go viene fornito con un runtime e un garbage collector.

Un runtime significa che il bootstrapping/sovrascrittura del runtime sarà richiesto per funzionare in ambienti senza kernel. Questo entra maggiormente nell’implementazione interna del linguaggio, che potrebbe cambiare nelle versioni future. I cambiamenti richiedono ulteriore lavoro di bootstrapping man mano che il linguaggio si evolve.

Un garbage collector (GC) significa che Go è limitato in quali domini applicativi può essere usato o che il GC deve essere disabilitato e sostituito con una gestione manuale della memoria. Nel caso in cui il GC non possa essere sostituito, il dominio in tempo reale (definito da operazioni che devono essere completate entro determinati limiti di tempo e/o le prestazioni sono misurate in nano-secondi) non potrebbe rischiare i tempi di pausa non deterministici di un GC.

Software per sistemi distribuiti

Con il crescente parlare di sistemi distribuiti, e applicazioni come Kubernetes che diventano molto popolari, si sente un sacco di nuovo vocabolario che (se dobbiamo essere onesti) la maggior parte di noi non capisce del tutto.

Fino a questo punto, ho visto i termini programmazione dei sistemi e ingegneri dei sistemi usati in contesti in cui ciò che intendevano veramente era programmazione dei sistemi distribuiti e ingegneri dei sistemi distribuiti.

Abbiamo definito il software di sistema, i linguaggi di sistema e la programmazione dei sistemi in questo post. Tuttavia, quando parliamo di sistemi distribuiti, il significato di sistema cambia. E mentre non ho intenzione di immergermi nelle differenze specifiche qui (principalmente perché ho ancora bisogno di afferrarle meglio io stesso), è importante che facciamo queste distinzioni mentali e usiamo un discorso più preciso quando possiamo per evitare confusione a coloro che stanno ancora imparando lo spazio.

Articles

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.