Vai al contenuto principale
TiConsiglio

Riassunto · 3997 Assistenti Informatici – RIPAM

Dispensa - Sistemi, reti e sviluppo software - Assistente informatico_Concorso 3.997 posti

Contenuto a fini di studio e autovalutazione, generato con il supporto dell'AI e revisionato dalla Redazione. Può contenere imprecisioni. Le informazioni hanno carattere divulgativo e non sostituiscono la normativa vigente né gli atti ufficiali cui occorre sempre fare riferimento.

Capitoli completati: 0 su 9

Clicca sul titolo di un capitolo per chiuderlo o riaprirlo; spunta "fatto" quando lo hai completato (il segno resta salvato su questo dispositivo).

1. Sistemi operativ: Windows e Linux – interfaccia, comandi e gestione file

Un sistema operativ (SO) e' un software di base che gestisce le risorse hardware e fornisce servizi di base ai programmi applicativi. Tra i SO piu' diffusi per i personal computer troviamo Microsoft Windows e le distribuzioni GNU/Linux. Entrambi offrono un'interfaccia grafica (GUI) e una o piu' interfacce a riga di comando (CLI) che consentono all'utente di interagire con il file system, avviare processi e amministrare le periferiche.

Architettura e interfaccia grafica di Windows. Windows e' una famiglia di ambienti operativi prodotta da Microsoft dal 1985. Le versioni piu' recenti (Windows 11, Windows Server 2019, Windows IoT Core) sono basate su un kernel della famiglia Windows NT, caratterizzato da un'architettura a microkernel ibrido. L'interfaccia grafica e' sempre stata un componente essenziale: la metafora della scrivania (Desktop) comprende icone, barra delle applicazioni, pulsante Start, menu, barra di stato e finestre sovrapponibili. La shell grafica principale e' File Explorer (noto anche come Esplora risorse), che permette di navigare gerarchicamente le cartelle, visualizzare le proprieta' dei file e avviare le applicazioni con un doppio click.

Windows supporta numerose combinazioni di tasti di scelta rapida. Tra le piu' note troviamo ALT + TAB per passare da una finestra all'altra, WINDOWS + TAB per aprire il visualizzatore di attività in forma tridimensionale, e CTRL + ALT + CANC per accedere al menu di sicurezza (opzioni di arresto, cambio utente, gestione task). Per catturare lo schermo e' possibile usare WINDOWS + MAIUSC + S. La barra delle applicazioni, posta in basso, contiene i collegamenti ai programmi piu' usati e le icone dei programmi in esecuzione; le opzioni per minimizzare, massimizzare o chiudere una finestra si trovano in alto a destra.

Per la gestione dei file da riga di comando Windows mette a disposizione cmd.exe, la shell tradizionale della famiglia Windows NT, e Windows PowerShell, una shell avanzata basata su .NET che consente di eseguire script complessi e di gestire oggetti del sistema. Con cmd.exe e' possibile usare comandi classici come dir (elenca il contenuto di una cartella), cd (cambia directory), copy, move e del. PowerShell estende queste funzionalita' con cmdlet come Get-ChildItem, Set-Location e Remove-Item, offrendo un modello orientato agli oggetti.

File system di Windows. Il file system nativo e' NTFS (NT File System), progettato per le versioni NT della famiglia Windows. NTFS supporta permessi di sicurezza, journaling e collegamenti simbolici. Per supportare dispositivi rimovibili e compatibilita' con sistemi piu' vecchi, Windows utilizza anche FAT, FAT32 e la variante ExFAT (conosciuta anche come FAT64) pensata per memorie flash. ReFS (Resilient File System) e' un file system introdotto da Microsoft per scenari di alta affidabilita'.

Architettura e interfaccia di Linux. Linux e' il nome comunemente usato per i sistemi operativi liberi che utilizzano il kernel Linux, costruiti in forma di distribuzioni che includono il kernel, le librerie GNU, le utility di base e un ambiente desktop. Il kernel Linux e' monolitico, ma supporta moduli caricabili che ne consentono l'estensione dinamica. Le distribuzioni piu' note includono Ubuntu (derivata da Debian), ma il kernel e' utilizzato anche in server, dispositivi embedded, mainframe e supercomputer.

Linux offre diverse shell testuali: la Bash (Bourne Again SHell) e' la piu' diffusa; altre includono sh (Bourne shell), csh (C shell), zsh, ksh (Korn shell) e dash (Debian Almquist shell). Queste shell permettono di digitare comandi, creare script e gestire processi. Tra i comandi di base troviamo ls (elenca file), cd (cambia directory), cp (copia file), mv (sposta o rinomina), rm (cancella), mkdir (crea directory) e rmdir (rimuove directory vuota). Il comando history restituisce gli ultimi comandi inseriti nella shell, come indicato nella fonte.

Per l'interfaccia grafica Linux utilizza ambienti desktop (Desktop Environment) come GNOME, KDE, Xfce e altri. Questi ambienti forniscono una scrivania con icone, pannelli, menu e gestori di finestre. L'equivalente di File Explorer e' il file manager integrato nell'ambiente desktop (ad esempio Nautilus in GNOME o Dolphin in KDE), che permette di navigare il file system, visualizzare le proprieta' dei file e avviare le applicazioni.

File system di Linux. Linux supporta una vasta gamma di file system per memorie di massa, tra cui Ext, Ext2, Ext3, Ext4 (stabile dal kernel 2.6.28), XFS, Btrfs, ReiserFS, Reiser4, JFS, ZFS, Btrfs, UFS, UFS2, UDF, ISO 9660 (con estensioni Rock Ridge e Joliet) e molti altri elencati nella fonte. La maggior parte delle distribuzioni monta automaticamente le partizioni al boot, rendendo disponibile il contenuto tramite un albero gerarchico (root "/"). Alcuni file system, come NTFS e FAT, sono accessibili tramite driver specifici, consentendo a Linux di leggere e scrivere su supporti formattati per Windows.

Gestione dei file in ambiente misto. Sia Windows che Linux offrono meccanismi per creare, spostare, rinominare e cancellare file e cartelle sia tramite interfaccia grafica sia tramite riga di comando. In Windows, l'operazione di drag and drop consente di spostare un file da una cartella all'altra trascinando l'icona con il mouse; la stessa operazione e' disponibile in Linux nei file manager degli ambienti desktop. Entrambi i sistemi supportano la creazione di collegamenti: Windows utilizza collegamenti (shortcut) visualizzati con una freccia ricurva, mentre Linux supporta hard link e symbolic link (creati con ln -s).

Comandi di navigazione e ricerca. In Windows, la barra di ricerca di Esplora risorse permette di filtrare i file usando pattern come *.pdf, restituendo tutti i documenti PDF presenti. In Linux, il comando find o l'uso di pattern di shell (ad esempio *.pdf) consente di ottenere risultati analoghi. Entrambi i sistemi mostrano il numero di file contenuti nella cartella nella barra di stato della finestra.

Gestione dei processi e delle finestre. Windows permette di passare da una finestra all'altra cliccando sull'icona nella barra delle applicazioni o usando ALT + TAB. La barra delle applicazioni mostra anche le icone dei programmi in esecuzione, consentendo di selezionare rapidamente la finestra desiderata. In Linux, la combinazione Alt+Tab (gestita dal gestore di finestre) offre una funzionalita' analoga. Inoltre, il comando cd - nella Bash riporta alla directory precedente all'ultimo cd, facilitando la navigazione.

Gestione della sicurezza e dei permessi. Windows utilizza il modello di sicurezza basato su ACL (Access Control List) integrato in NTFS, mentre Linux utilizza permessi di lettura, scrittura ed esecuzione per proprietario, gruppo e altri, oltre a meccanismi avanzati come SELinux o AppArmor (non descritti nella fonte, ma menzionati come parte del contesto di gestione). Entrambi i sistemi permettono di definire gruppi di utenti (ad esempio gli amministratori di Windows o il gruppo sudo in Linux) per delegare diritti di backup, installazione o modifica di configurazioni.

Conclusioni. Windows e Linux condividono l'obiettivo di fornire un'interfaccia intuitiva per l'utente e potenti strumenti a riga di comando per l'amministratore. Windows si distingue per la sua interfaccia grafica uniforme, le API Windows e il supporto nativo a NTFS, FAT, FAT32, ExFAT e ReFS. Linux, invece, offre una maggiore varietà di file system (Ext4, XFS, Btrfs, ZFS, ecc.), una scelta ampia di shell testuali (Bash, sh, csh, zsh, ksh) e ambienti desktop modulari. La conoscenza delle principali combinazioni di tasti, dei comandi di base e delle differenze nei file system consente di gestire efficacemente i file, le cartelle e i processi su entrambi i sistemi, facilitando lo sviluppo software e l'amministrazione di reti e server.

2. Reti e protocolli di comunicazione – topologia, bit‑rate e dispositivi

La suite di protocolli Internet, comunemente indicata con la sigla TCP/IP, e' una famiglia di protocolli di rete legati da dipendenze d'uso su cui si basa il funzionamento logico della rete Internet. I due protocolli piu' noti della suite sono il Transmission Control Protocol (TCP) e l'Internet Protocol (IP). Il modello di architettura a strati della suite e' lo standard de facto nell'ambito delle reti dati, in contrapposizione allo standard de iure rappresentato dal modello OSI.

Nei primi anni settanta del XX secolo la Defense Advanced Research Project Agency (DARPA) finanziò l'Universita' di Stanford e la BBN (Bolt, Beranek and Newman) per lo sviluppo di un insieme di protocolli di comunicazione da utilizzare per reti a commutazione di pacchetto. Fu in questo contesto che nacque l'Internet Protocol Suite. Il protocollo IP provvede a fornire il sistema di indirizzamento dei nodi terminali della rete, assegnando a ciascuno un nome univoco formato da quattro gruppi di cifre. Il protocollo TCP, posto al livello immediatamente superiore, gestisce il flusso dell'informazione tra due nodi, offrendo servizi di gestione del flusso, della congestione e di affidabilita' del trasporto.

Gli ideatori di questi protocolli, Robert Kahn e Vinton Cerf, svilupparono lo standard per la trasmissione di pacchetti via rete nel 1973. Entrambi hanno ricevuto il 2004 A.M. Turing Award e, nel 2005, la Presidential Medal of Freedom. I protocolli della suite sono di pubblico dominio fin dall'inizio e hanno ottenuto un elevato successo grazie alla loro apertura e alla diffusione di Internet.

La suite TCP/IP puo' essere descritta mediante una schematizzazione a livelli. Il modello Internet prevede quattro livelli: livello di applicazione, livello di trasporto, livello di rete e livello di accesso alla rete. In alcuni approcci ibridi il livello di accesso viene suddiviso in livello fisico e livello di collegamento, portando a cinque livelli. Il livello di trasporto comprende TCP per le applicazioni che richiedono un servizio orientato alla connessione (posta elettronica, file sharing) e UDP per le applicazioni in tempo reale (online gaming, streaming audio e video), dove la velocita' di trasmissione ha la precedenza sull'affidabilita'.

Il modello OSI, standardizzato nel 1984 come ISO 7498, definisce sette livelli: fisico, data link, rete, trasporto, sessione, presentazione e applicazione. Sebbene il modello OSI sia lo standard de iure, nella pratica la suite TCP/IP si e' imposta come standard de facto grazie alla sua semplicità e alla diffusione capillare.

Per quanto riguarda la topologia di rete, le LAN (Local Area Network) possono adottare diversi schemi di interconnessione sia a livello fisico sia di data link. Tra le topologie piu' comuni troviamo la topologia a bus, a stella, ad anello e la topologia magliata (mesh). La scelta della topologia dipende da fattori quali la scalabilita', la tolleranza ai guasti e il costo di cablaggio.

Il bit‑rate delle reti locali e' determinato dalla tecnologia di trasmissione adottata. La tecnologia Ethernet, dominante per le LAN, supporta velocita' di 1 Gbit/s e, con cablaggi adeguati (CAT5e o superiore), anche 10 Gbit/s. Per le reti wireless, la famiglia di standard IEEE 802.11 (Wi‑Fi) prevede versioni con velocita' crescenti, ma la descrizione dettagliata delle versioni non e' necessaria per la comprensione dei concetti di base.

Dal punto di vista dei dispositivi di rete, una LAN tipica comprende:

Switch: dispositivo di commutazione a livello di data link (livello 2 OSI). Lo switch identifica i dispositivi collegati mediante gli indirizzi MAC e inoltra i pacchetti solo alla porta di destinazione, riducendo il dominio di collisione. Puo' operare in modalita' half duplex (trasmissione o ricezione alla volta) o full duplex (trasmissione e ricezione simultanee). Gli switch di fascia alta offrono funzionalita' di gestione, supporto al protocollo Spanning Tree (per evitare loop), Shortest Path Bridging, VLAN (802.1Q), mirroring delle porte e Quality of Service (QoS).

Router: dispositivo di livello di rete (livello 3 OSI) che instrada i pacchetti tra subnet diverse, traduce indirizzi IP privati in indirizzi IP pubblici e collega la LAN a reti esterne (Internet). Il router-gateway mappa la sottorete locale con un indirizzo pubblico, consentendo l'accesso a servizi esterni quali posta elettronica, stampa e file sharing.

Load balancer: dispositivo che distribuisce il traffico in ingresso tra piu' server, migliorando la disponibilita' e le prestazioni dei servizi.

Firewall, proxy e sistemi di rilevamento delle intrusioni (IDS): dispositivi di sicurezza che filtrano il traffico, controllano l'accesso alle risorse e monitorano eventuali comportamenti anomali.

Le LAN piu' semplici si basano su uno o piu' switch collegati a un router, eventualmente a un modem analogico o ADSL per l'accesso a Internet. Le LAN piu' complesse prevedono collegamenti ridondanti, protocolli di spanning tree per il reinstradamento in caso di guasto, QoS per la gestione differenziata del traffico e VLAN per la segregazione logica del traffico.

Le reti locali possono essere interconnesse mediante collegamenti dedicati, servizi di telefonia o tramite Virtual Private Network (VPN) che sfruttano meccanismi di tunneling e cifratura per garantire la riservatezza dei dati. A seconda della distanza geografica e dei requisiti di sicurezza, una LAN può evolvere in una Metropolitan Area Network (MAN) o in una Wide Area Network (WAN).

In sintesi, la comprensione delle topologie, del bit‑rate e dei dispositivi di rete e' fondamentale per progettare, implementare e gestire infrastrutture di comunicazione affidabili. La suite TCP/IP fornisce il modello di riferimento per il trasporto dei dati, mentre gli standard IEEE 802 definiscono i primi due livelli del modello OSI (fisico e data link). La combinazione di questi standard, insieme a dispositivi come switch, router, firewall e meccanismi di QoS, consente di realizzare reti scalabili, sicure e ad alte prestazioni, capaci di supportare le esigenze sia delle piccole reti aziendali sia delle grandi infrastrutture globali.

3. Sicurezza informatica – minacce, autenticazione e difese

La sicurezza informatica comprende l'insieme dei mezzi, delle tecnologie e delle procedure tesi a proteggere i beni o asset informatici – impianti, reti, dispositivi, sistemi, applicazioni e servizi – garantendo le tre proprieta' fondamentali di confidenzialita', integrita' e disponibilita' (acronimo RID). Oltre a queste, in ambito informatico si considerano anche autenticita' e non ripudiabilita', che insieme alle tre proprieta' originali formano le cosiddette 3+2 proprieta' capaci di assicurare responsabilita' e affidabilita' dei sistemi.

Un elemento distintivo e spesso trascurato e' la differenza tra sicurezza informatica e sicurezza delle informazioni (InfoSec). La prima si concentra esclusivamente sugli asset digitali, mentre la seconda mira a proteggere l'informazione in tutte le sue dimensioni – organizzativa, fisica, ambientale e logica – e considera anche dati non digitali, come documenti cartacei o comunicazioni orali. Per questo motivo, la sicurezza informatica rappresenta una parte e un mezzo della sicurezza delle informazioni, ma non la sua finalita' completa.

Le organizzazioni che desiderano gestire in modo sistematico la protezione delle proprie informazioni possono adottare la norma internazionale ISO 27001. Questo standard definisce i requisiti per un Sistema di Gestione della Sicurezza delle Informazioni (SGSI) e prevede, tra le altre cose, la valutazione del rischio e la gestione del rischio come fase indispensabile di ogni pianificazione della sicurezza. La certificazione ISO 27001 e' aperta a enti di qualsiasi natura, settore e dimensione.

Per valutare la sicurezza di un asset informatico, e' necessario identificare minacce, vulnerabilita' e rischi associati. Le minacce possono derivare da attori interni o esterni e possono provocare danni diretti o indiretti che superano soglie di tollerabilita' economiche, politiche, sociali o di reputazione. Le vulnerabilita' sono debolezze intrinseche nei sistemi, nei processi o nelle persone che possono essere sfruttate dalle minacce per generare un rischio concreto.

Un aspetto cruciale della difesa e' l'autenticazione, ovvero il processo mediante il quale un sistema verifica l'identita' di un utente, di un dispositivo o di un altro sistema prima di concedere l'accesso alle risorse. I fattori di autenticazione sono tradizionalmente classificati in tre categorie: qualcosa che l'utente conosce (password o PIN), qualcosa che l'utente possiede (smart card, token, dispositivo crittografico) e qualcosa che caratterizza l'utente (impronta digitale, voce, retina). L'autenticazione basata esclusivamente su password e' considerata meno robusta rispetto all'autenticazione multifactore, poiche' le credenziali possono essere rubate, indovinate o intercettate. Tuttavia, nessuna tecnica offre una sicurezza assoluta: anche le soluzioni biometriche possono essere compromesse o non disponibili in tutti i contesti.

Nel contesto delle reti private virtuali (VPN), l'autenticazione assume un ruolo ancora piu' centrale. Una VPN consente il transito di dati privati attraverso reti pubbliche, ma per farlo in modo sicuro deve verificare l'identita' dell'utente, del dispositivo e del sistema prima di stabilire il tunnel crittografato. Le politiche di autenticazione per le VPN includono la definizione di criteri per l'autorizzazione degli accessi, la configurazione del client e la limitazione delle risorse in base alle necessita' operative. L'uso di VPN riduce la necessita' di collegamenti dedicati, ma richiede una gestione attenta delle credenziali e dei meccanismi di cifratura per prevenire attacchi di tipo man-in-the-middle o replay.

Un altro pilastro delle difese informatiche e' l'uso di protocolli di trasmissione sicuri, come HTTPS. HTTPS combina il protocollo HTTP con la cifratura TLS (o SSL) per fornire autenticazione del sito web, riservatezza dei dati scambiati e integrita' delle comunicazioni. La cifratura bidirezionale protegge sia le richieste URL, i parametri di query, le intestazioni e i cookie, impedendo a terzi di intercettare o modificare i contenuti. La fiducia in una connessione HTTPS si basa sulla verifica del certificato digitale rilasciato da un'autorita' di certificazione riconosciuta, sulla corrispondenza del certificato con il nome del dominio e sulla robustezza dell'algoritmo di cifratura impiegato.

Il firewall rappresenta la prima linea di difesa perimetrale di una rete. Si tratta di un componente hardware e/o software che filtra i pacchetti in transito tra due o piu' segmenti di rete, bloccando traffico non autorizzato e consentendo solo le comunicazioni esplicitamente ammesse. Sebbene originariamente fosse un dispositivo passivo, i firewall moderni possono svolgere anche funzioni di collegamento, di ispezione approfondita dei pacchetti e di integrazione con sistemi di autenticazione centralizzati.

La sicurezza dei programmi, sia a livello di sistema operativo che di applicazione, e' anch'essa fondamentale. Un programma sicuro deve essere privo di difetti che possano generare danni mortali o irreparabili al sistema. La verifica della sicurezza del software avviene mediante modelli basati sulla semantica (analisi del comportamento) o basati sul tipo di linguaggio (security-typed language). Inoltre, la gestione delle vulnerabilita' note, come le SQL injection, le cross-site scripting (XSS) o le remote code execution (RCE), richiede l'applicazione tempestiva di patch e l'adozione di pratiche di programmazione sicura, tra cui il filtraggio dei dati in uscita e la cifratura delle comunicazioni.

Infine, la difesa informatica non si limita alla tecnologia: elementi organizzativi, giuridici e umani sono parte integrante del quadro di sicurezza. La definizione di politiche di registrazione e monitoraggio degli eventi, la formazione degli utenti sulla gestione delle credenziali e l'adozione di standard normativi (come il GDPR per la protezione dei dati personali o l'HIPAA per le informazioni sanitarie) completano il modello di difesa. Solo attraverso un approccio integrato, che combina tecnologie robuste, processi ben definiti e consapevolezza degli attori coinvolti, e' possibile ridurre il rischio complessivo e garantire la resilienza dei sistemi informatici di fronte a minacce sempre piu' sofisticate.

4. Basi di dati relazionali – SQL, Oracle e modellazione E/R

Le basi di dati relazionali costituiscono il modello dominante per l'organizzazione e la gestione di grandi volumi di informazioni. Il modello relazionale, introdotto da Edgar F. Codd negli anni '70, si basa su tabelle (dette relazioni) composte da righe (tuple) e colonne (attributi). Ogni attributo possiede un nome univoco, un tipo di dato e un dominio di valori ammessi; le chiavi primarie garantiscono l'univocita' di ciascuna tupla, mentre le chiavi esterne stabiliscono collegamenti logici tra tabelle diverse.

Il linguaggio standard per interagire con questi sistemi e' Structured Query Language (SQL). SQL e' stato concepito nel 1974 da Donald Chamberlin nei laboratori IBM, inizialmente con il nome SEQUEL. Dopo una serie di prototipi (SEQUEL-XRM, SEQUEL/2) il linguaggio assunse la denominazione SQL per motivi legali. Il primo prototipo di implementazione, System R, fu utilizzato internamente da IBM e contribuì alla diffusione del linguaggio. Già nel 1981 IBM iniziò a commercializzare prodotti relazionali, culminando nel 1983 con il rilascio di DB2. Lo stesso anno l'ANSI adottò SQL come standard (SQL/86), seguito dalla ISO nel 1987. Successive revisioni (SQL/89, SQL/92, SQL/2003) hanno introdotto nuove funzionalita' senza mai raggiungere una piena uniformita' tra i diversi vendor.

SQL e' suddiviso in sottoinsiemi funzionali:

DDL (Data Definition Language) consente di creare e modificare lo schema del database (CREATE, ALTER, DROP).
DML (Data Manipulation Language) permette l'inserimento, l'aggiornamento e la cancellazione dei dati (INSERT, UPDATE, DELETE).
DQL (Data Query Language) comprende le istruzioni di interrogazione (SELECT) con clausole quali WHERE, GROUP BY, HAVING e ORDER BY.
DCL (Data Control Language) gestisce i permessi di accesso (GRANT, REVOKE).

Pur essendo stato progettato come linguaggio dichiarativo, SQL ha incorporato costrutti procedurali, tipi di dato definiti dall'utente e controlli di flusso, specialmente a partire dallo standard SQL:1999 (sezione SQL/PSM). Le critiche più frequenti riguardano la portabilita' limitata tra vendor diversi, la gestione dei valori NULL e una semantica a volte complessa.

Tra i sistemi di gestione di basi di dati (DBMS) che implementano SQL, Oracle rappresenta una delle soluzioni commerciali piu' diffuse. Oracle, come altri DBMS citati (IBM DB2, Microsoft SQL Server, MySQL, PostgreSQL, SQLite, ecc.), fornisce un'interfaccia a riga di comando e/o grafica per l'esecuzione di comandi SQL, supporta le estensioni standard e offre strumenti di amministrazione per la gestione di utenti, permessi e backup.

La progettazione di una base di dati relazionale segue diverse fasi. Dopo l'analisi dei requisiti, si passa alla modellazione concettuale, spesso mediante il modello E/R (Entity/Relationship). Questo modello semantico consente di rappresentare entita' (oggetti di interesse) e le loro relazioni, facilitando la traduzione in uno schema logico di tabelle. Successivamente, la normalizzazione viene applicata per ridurre la ridondanza e garantire l'integrita' dei dati. Le forme normali (prima, seconda, terza, BCNF, ecc.) definiscono criteri di decomposizione basati su dipendenze funzionali.

La decomposizione delle relazioni deve soddisfare due proprieta' fondamentali: la decomposizione senza perdita (che permette di ricostruire la relazione originale mediante join) e la conservazione delle dipendenze (che mantiene i vincoli di integrita' originari). Il teorema di perdita senza perdita afferma che, se l'intersezione tra gli insiemi di attributi delle relazioni decomposte e' una superchiave per almeno una delle due, la decomposizione e' senza perdita.

In alcuni contesti, soprattutto nei data warehouse, si ricorre alla denormalizzazione per migliorare le prestazioni di lettura. La denormalizzazione introduce copie ridondanti di dati o aggrega concetti correlati in un'unica tabella, aumentando la velocita' di interrogazione a scapito di una maggiore complessita' nella gestione degli aggiornamenti. Le strategie di denormalizzazione possono essere applicate a livello logico (tramite trigger o logica applicativa) o a livello fisico (mediante viste materializzate o indici speciali).

SQL fornisce inoltre meccanismi di controllo dell'accesso (DCL) e di gestione delle transazioni (COMMIT, ROLLBACK), garantendo le proprieta' ACID (Atomicita', Consistenza, Isolamento, Durabilita') tipiche dei sistemi relazionali. Nonostante l'emergere del movimento NoSQL, che promuove approcci alternativi per casi d'uso specifici, i database relazionali rimangono la soluzione preferita per molte applicazioni che richiedono integrita' rigorosa e query complesse.

In sintesi, la combinazione di SQL come linguaggio standard, di DBMS consolidati come Oracle e di metodologie di modellazione (E/R) e normalizzazione costituisce il fondamento tecnico per la progettazione, l'implementazione e la gestione efficace di basi di dati relazionali.

5. Programmazione – concetti, linguaggi (Python, Java, C) e strutture di controllo

Un linguaggio di programmazione e' un sistema di notazione per la scrittura di programmi per computer. La descrizione di un linguaggio e' solitamente divisa in sintassi (la forma) e semantica (il significato), entrambe definite da un linguaggio formale. Alcuni linguaggi sono specificati da standard (ad esempio il linguaggio C e' definito da uno standard ISO), altri hanno un'implementazione dominante che funge da riferimento. La teoria dei linguaggi di programmazione studia la progettazione, l'implementazione, l'analisi, la caratterizzazione e la classificazione dei linguaggi.

Nel corso della storia, i primi tentativi di programmazione furono il linguaggio meccanico di Ada Lovelace e il Plankalkul di Konrad Zuse, pubblicato nel 1946 ma mai usato per programmare. La programmazione dei primi elaboratori avveniva in short code e poi in assembly, dove l'unica forma di controllo di flusso era il salto condizionato. Con l'avvento di linguaggi ad alto livello come Fortran (1957) e BASIC (1964) comparvero nuove strutture di controllo quali IF, WHILE, FOR, CASE e SWITCH, riducendo il ricorso a GOTO e rendendo il codice piu' leggibile.

Tra i linguaggi storici piu' influenti vi sono Lisp (1959), ALGOL (1960) e Simula (1967), quest'ultimo il primo a introdurre il concetto di oggetto software. Il Pascal (1970) fu il primo linguaggio strutturato a scopo didattico; dal BCPL nacquero B e poi C (1972), quest'ultimo divenne subito un grande successo. Smalltalk (1983) introdusse il paradigma object-oriented nella sua prima incarnazione matura, influenzando successivamente C++, Eiffel (1986) e Java (1995).

La programmazione orientata agli oggetti (OOP) prevede la definizione di classi che raggruppano dati (attributi) e procedure (metodi). I quattro meccanismi fondamentali dell'OOP sono incapsulamento, ereditarieta', polimorfismo e astrazione. L'incapsulamento separa l'interfaccia dalla implementazione, l'ereditarieta' consente di definire classi a partire da altre, il polimorfismo permette a client di utilizzare oggetti di classi diverse tramite una stessa interfaccia, e l'astrazione consente di lavorare con concetti ad alto livello senza curarsi dei dettagli di implementazione.

Python e' un linguaggio ad alto livello, orientato a oggetti, dinamico e fortemente tipizzato a run-time. Ideato da Guido van Rossum negli anni novanta, la sua sintassi si avvicina al pseudo-codice e utilizza l'indentazione per delimitare i blocchi di codice, eliminando la necessita' di parentesi graffe o parole chiave come begin/end. Python supporta multipli paradigmi, tra cui quello a oggetti e quello funzionale, e offre caratteristiche distintive quali variabili non tipizzate, overloading di operatori tramite delegati, slicing, list comprehension e un ricco assortimento di librerie standard. Il controllo dei tipi avviene a run-time, e la gestione della memoria e' affidata a un garbage collector. L'implementazione di riferimento e' CPython, scritta in C e Python; esistono anche Jython (basato su Java), IronPython (integrato con .NET) e PyPy (scritta in Python stesso).

Java e' un linguaggio ad alto livello, orientato agli oggetti e a tipizzazione statica, progettato per essere il piu' possibile indipendente dalla piattaforma hardware grazie alla compilazione in bytecode e all'esecuzione su una Java Virtual Machine (JVM). Creato a partire da ricerche dell'Universita' di Stanford negli anni novanta, il linguaggio nacque come Oak (1992) e fu rinominato Java per problemi di copyright. La sintassi di base (strutture di controllo, operatori, ecc.) e' pressoche' identica a quella del C, ma Java elimina caratteristiche complesse del C++ come l'aritmetica dei puntatori e l'ereditarieta' multipla, riducendo la probabilita' di bug. Java e' definito dal Java Language Specification; l'ultima versione al 17 settembre 2024 e' Java SE 23.

Il linguaggio C e' stato sviluppato a partire dal BCPL nel 1972. E' un linguaggio di programmazione strutturato, tipizzato staticamente, che ha influenzato numerosi linguaggi successivi. La sua sintassi prevede l'uso di parentesi graffe per delimitare i blocchi e di punti e virgola per terminare le istruzioni. C e' tipicamente compilato in linguaggio macchina, offrendo prestazioni elevate e un controllo fine sull'hardware.

Tutti i linguaggi di programmazione condividono concetti fondamentali: istruzioni, variabili e costanti, espressioni, strutture dati, strutture di controllo, sottoprogrammi (funzioni o metodi), input/output tramite canali standard e commenti. Le strutture di controllo permettono di governare il flusso di esecuzione del programma in base al risultato di un'espressione booleana. Tra le più comuni troviamo:

Strutture condizionali: IF (con eventuali ELSE e ELSEIF/ELIF) consente di eseguire blocchi di codice solo se una condizione e' vera. Alcuni linguaggi, come Python, non hanno costrutti SWITCH o CASE, ma forniscono costrutti equivalenti mediante IF-ELIF-ELSE.

Cicli iterativi: FOR, WHILE e DO...WHILE permettono di ripetere un blocco di istruzioni finche' una condizione rimane vera. In Python il ciclo FOR itera sugli elementi di una lista o di un iteratore, mentre WHILE continua finche' l'espressione booleana e' vera. C e Java offrono sia FOR tradizionali (con inizializzazione; condizione; aggiornamento) sia WHILE e DO...WHILE.

Strutture di salto: BREAK interrompe l'esecuzione del ciclo corrente, CONTINUE salta all'iterazione successiva, e RETURN termina l'esecuzione di una funzione restituendo un valore.

Oltre alle strutture di controllo, la programmazione moderna fa ampio uso di sottoprogrammi. In Python le funzioni sono definite con la parola chiave def, in Java con void o un tipo di ritorno, e in C con il tipo di ritorno seguito dal nome della funzione. Le funzioni favoriscono il riuso del codice e la modularita'.

Il codice sorgente e' tipicamente scritto in file di testo ASCII e modificato con editor di testo o ambienti di sviluppo integrati (IDE) che offrono funzionalita' avanzate quali evidenziazione della sintassi, completamento automatico e integrazione con compilatori o interpreti. Per essere eseguito, il codice sorgente deve essere tradotto in linguaggio macchina mediante compilazione (C) o interpretazione (Python). Java utilizza una combinazione: il compilatore genera bytecode, che viene poi interpretato o compilato just-in-time dalla JVM.

In sintesi, la programmazione si basa su un insieme di concetti comuni (variabili, espressioni, strutture di controllo, funzioni) che vengono espressi attraverso linguaggi specifici. Python offre semplicità, leggibilita' e flessibilita' grazie a una sintassi pulita e a un'ampia libreria standard; Java garantisce portabilita' e sicurezza tramite la JVM e un modello object-oriented rigoroso; C fornisce prestazioni elevate e controllo hardware, risultando la base di molti sistemi operativi e applicazioni embedded. La comprensione di questi concetti e delle loro implementazioni nei tre linguaggi e' fondamentale per affrontare lo sviluppo di software in ambito sia accademico che industriale.

6. Sviluppo web – HTML, form, accessibilita' e sicurezza HTTPS

Lo sviluppo di applicazioni web richiede una duplice attenzione: da un lato la corretta strutturazione dei contenuti (HTML, form, accessibilita') e dall'altro la protezione delle informazioni scambiate tra client e server. La sicurezza delle informazioni, come definita nella letteratura enciclopedica, non coincide con la sola sicurezza informatica. La prima si occupa dell'asset "informazione" nelle dimensioni organizzativa, fisica, ambientale e logica, mentre la seconda si rivolge agli asset informatici (impianti, reti, dispositivi, sistemi, applicazioni, servizi). Per garantire la riservatezza, l'integrita' e la disponibilita' (acronimo RID) delle informazioni, le organizzazioni possono adottare lo standard internazionale ISO 27001, che specifica i requisiti di un adeguato Sistema di Gestione della Sicurezza delle Informazioni (SGSI) e prevede, tra le altre cose, la valutazione e la gestione del rischio.

Nel contesto web, il protocollo che consente la comunicazione sicura e cifrata e' HTTPS (HyperText Transfer Protocol over Secure Socket Layer). HTTPS utilizza tipicamente la porta 443 e combina il protocollo HTTP con una connessione criptata basata su crittografia asimmetrica fornita dal Transport Layer Security (TLS) o dal suo predecessore Secure Sockets Layer (SSL). I requisiti chiave di HTTPS sono:

  • autenticazione del sito web visitato;
  • protezione della privacy (riservatezza o confidenzialita');
  • integrita' dei dati scambiati tra le parti comunicanti.

Il risultato e' una cifratura bidirezionale che impedisce a terzi di effettuare eavesdropping (ascolto segreto) o tampering (manomissione) dei contenuti. In pratica, HTTPS garantisce che l'utente stia comunicando esattamente con il sito web voluto, evitando attacchi di tipo man-in-the-middle.

Storicamente, le connessioni HTTPS furono progettate dalla Netscape Communications Corporation per supportare autenticazioni e comunicazioni crittografate, in particolare per le transazioni di pagamento online. Inizialmente il loro impiego era limitato a e-commerce, e-mail e transazioni sensibili all'interno di sistemi informativi aziendali. A partire dal tardo 2000 e nei primi anni 2010, HTTPS ha iniziato a diffondersi ampiamente per proteggere l'autenticita' delle pagine web, la sicurezza degli account utente e la privacy della navigazione.

Il funzionamento tecnico prevede che il browser, riconoscendo lo schema "https" nella URI, avvii una negoziazione TLS con il server. Durante questa fase il server presenta un certificato digitale firmato da una autorita' di certificazione (CA) preinstallata nel browser. Il client verifica che il certificato sia valido, che sia firmato da una CA di fiducia, che l'identita' indicata nel certificato corrisponda al nome di dominio richiesto e che il livello di cifratura sia considerato sufficientemente sicuro. Solo se tutti questi punti sono soddisfatti la connessione procede, altrimenti il browser segnala un avviso di sicurezza.

Le autorita' di certificazione più comuni (ad esempio Symantec, Comodo, GoDaddy, GlobalSign) sono preinstallate nei browser e costituiscono il punto di fiducia per la verifica dei certificati. Tuttavia, HTTPS non protegge gli indirizzi IP, i numeri di porta o altri metadati di livello TCP/IP: un osservatore può comunque dedurre l'IP del server, la porta utilizzata (spesso 443) e la quantità di dati trasferiti, ma non il contenuto della comunicazione.

Per rafforzare ulteriormente la protezione, le best practice raccomandano l'uso di HTTP Strict Transport Security (HSTS), che istruisce il browser a effettuare solo connessioni HTTPS verso il dominio specificato, prevenendo attacchi di tipo SSL stripping. Progetti come HTTPS Everywhere, sviluppati dall'EFF e integrati nel Tor Browser, promuovono l'adozione automatica di HTTPS su tutti i siti possibili, soprattutto in contesti di rete insicuri (WiFi pubblici, reti Tor).

La sicurezza dei programmi web, inclusi i form di input, dipende anche dalla corretta gestione delle vulnerabilita' note. La letteratura enciclopedica evidenzia che vulnerabilita' come SQL injection, cross-site scripting (XSS) e cross-site request forgery (CSRF) possono compromettere la riservatezza e l'integrita' dei dati se non vengono adeguatamente filtrate le informazioni in ingresso e se non si utilizza una cifratura adeguata (TLS/SSL). Pertanto, gli sviluppatori devono mantenere aggiornati i framework e le librerie utilizzate, applicare le patch di sicurezza e adottare pratiche di codifica difensive.

In sintesi, lo sviluppo web efficace combina una corretta strutturazione dei contenuti (HTML, form, accessibilita') con l'adozione di protocolli di trasporto sicuri. HTTPS fornisce autenticazione del server, riservatezza dei dati e integrita' della comunicazione, ed è supportato da un ecosistema di certificati, autorita' di certificazione e meccanismi aggiuntivi come HSTS. L'aderenza a standard internazionali (ISO 27001) e la gestione proattiva delle vulnerabilita' dei programmi completano il quadro di una strategia di sicurezza informatica robusta, capace di proteggere le informazioni sia in transito che a riposo, indipendentemente dal dispositivo o dalla rete utilizzata.

7. Gestione progetti software – metodologie, MVP, MPM e controllo qualità

L'ingegneria del software è la disciplina informatica che si occupa dei processi produttivi e delle metodologie di sviluppo finalizzate alla realizzazione di sistemi software. Essa nasce alla fine degli anni sessanta per rispondere alla crescente complessità dei prodotti e alla necessità di rigore e disciplina nelle grandi aziende. Dalla prima fase, in cui i programmi venivano scritti da una sola persona senza documentazione, si è passati a una fase in cui, dal 1965 al 1975, il software è pensato per più utenti e per sistemi real-time, con l'emergere di problemi di gestione e manutenzione.

Il concetto di ciclo di vita del software è centrale nell'ingegneria del software. Esso scompone l'attività di realizzazione in sottoattività coordinate: analisi, progettazione, realizzazione, collaudo, messa a punto, installazione, manutenzione ed estensione. Ogni fase è accompagnata da documentazione, che permette la tracciabilità e il controllo delle modifiche. Il controllo versione è una pratica fondamentale: ogni modifica al codice sorgente (o ad altri artefatti) è etichettata con un numero di versione e con il nome dell'autore, consentendo di tornare a stati precedenti in caso di problemi.

Nel corso degli anni sono stati proposti diversi modelli di ciclo di vita. Alcuni, come il modello a cascata, prevedono un ordine sequenziale delle fasi; altri, tipici delle metodologie agili, suddividono il lavoro in iterazioni brevi (di solito qualche settimana) che contengono tutti gli step necessari per rilasciare un piccolo incremento di funzionalità.

Le metodologie agile sono emerse nei primi anni 2000, ispirate al Manifesto per lo sviluppo agile del software (pubblicato nel 2001). Esse si contrappongono al modello a cascata proponendo un approccio meno strutturato, focalizzato sulla consegna frequente di software funzionante, su team piccoli, poli-funzionali e auto-organizzati, e su una comunicazione diretta con il cliente. Ogni iterazione deve includere pianificazione, analisi dei requisiti, progettazione, implementazione, test e documentazione, e il risultato, anche se non completo, viene rilasciato per raccogliere feedback e rivalutare le priorità.

Uno dei framework agili più diffusi è Scrum. Scrum, ideato da Ken Schwaber e Jeff Sutherland, si basa su tre pilastri (trasparenza, ispezione, adattamento) e utilizza meccanismi di controllo empirico. Il lavoro è organizzato in sprint (iterazioni tipicamente di due-quattro settimane) con ruoli ben definiti (Product Owner, Scrum Master, Development Team) e artefatti (Product Backlog, Sprint Backlog, Increment). Scrum enfatizza la responsabilità decisionale a livello operativo, riducendo la dipendenza da un approccio command-and-control.

Un altro approccio complementare è DevOps, che mira a integrare sviluppo (development) e operazioni (operations). DevOps nasce per rispondere all'interdipendenza tra sviluppo software e IT operations, favorendo la comunicazione, la collaborazione e l'automazione dei rilasci. Le aziende con rilasci frequenti (ad esempio Flickr, con dieci rilasci al giorno) hanno adottato DevOps per standardizzare gli ambienti di sviluppo, automatizzare il deployment continuo e migliorare affidabilità e sicurezza.

Nel contesto della gestione dei progetti, il concetto di Minimum Viable Product (MVP) è citato come abbreviazione di Minimum Viable Product. Sebbene la fonte non fornisca una definizione dettagliata, l'acronimo è riconosciuto come elemento di valutazione nei quesiti d'esame, indicando che il MVP rappresenta una versione ridotta del prodotto sufficientemente funzionale da poter essere rilasciata per raccogliere feedback iniziali.

Il termine MPM non è presente nella fonte enciclopedica fornita; pertanto, non è possibile fornire una descrizione basata su fatti verificati. Qualsiasi approfondimento su MPM dovrebbe essere ricavato da altre fonti, ma in questa dispensa ci limitiamo alle informazioni disponibili.

Il controllo qualità nei progetti software si realizza attraverso diverse pratiche. Il testing (collaudo) è una fase fondamentale del ciclo di vita, in cui il software viene verificato rispetto ai requisiti. L'ispezione e il debugging sono attività di verifica e correzione degli errori. Inoltre, il controllo versione permette di tracciare le modifiche e di gestire conflitti tra sviluppatori, riducendo il rischio di perdita di lavoro e facilitando il rollback in caso di bug.

Gli strumenti di controllo versione possono essere centralizzati (es. CVS, Subversion) o distribuiti (es. Git, BitKeeper). Nei sistemi centralizzati, tutti i cambiamenti sono gestiti da un server condiviso; nei sistemi distribuiti, ogni sviluppatore possiede un repository locale e le modifiche vengono scambiate in modo esplicito. Entrambi i modelli prevedono operazioni di check-in, check-out, update e merge, con meccanismi di risoluzione dei conflitti quando più sviluppatori modificano lo stesso file contemporaneamente.

Il processo di revisione (code review) è spesso integrato nei flussi di lavoro agile e DevOps: le modifiche possono richiedere l'approvazione di un revisore designato prima di essere aggiunte al repository principale. Questo approccio migliora la qualità del codice, favorisce la condivisione della conoscenza e riduce la probabilità di introdurre errori.

Infine, la documentazione rimane un elemento chiave. Anche se le metodologie agili privilegiano la comunicazione faccia a faccia rispetto alla documentazione estesa, la creazione di artefatti essenziali (ad esempio specifiche di requisito, diagrammi architetturali, piani di test) è necessaria per garantire la tracciabilità e la manutenzione a lungo termine del prodotto.

In sintesi, la gestione dei progetti software combina una serie di pratiche consolidate (ciclo di vita, controllo versione, testing) con approcci moderni (agile, Scrum, DevOps) e concetti di prodotto come l'MVP. L'adozione di queste metodologie permette di ridurre i rischi, migliorare la qualità e accelerare il time-to-market, rispondendo alle esigenze di un mercato sempre più competitivo e orientato alla rapidità di consegna.

8. Architettura hardware – CPU, memoria, periferiche e driver

Il termine architettura hardware indica l’insieme dei criteri di progetto che guidano la realizzazione di un computer. In questa accezione l’architettura comprende il processore (CPU), la memoria, i registri, i collegamenti tra di essi, la scheda madre, le schede di espansione e il case. Quando si parla di architettura di un calcolatore si intende quindi la descrizione logica dell’intero sistema, non soltanto la disposizione fisica dei componenti. Tale descrizione è distinta da quella del software, che invece fornisce le soluzioni logiche per risolvere problemi mediante programmi eseguibili.

Il processore è il cuore di calcolo del sistema: esegue le istruzioni del programma, manipola i dati nei registri e coordina le operazioni di I/O. L’architettura del processore è tipicamente indicata con termini come x86, CISC, RISC, 32-bit o 64-bit, pipeline, ecc. Oltre al set di istruzioni, il processore contiene componenti di supporto quali la Memory Management Unit (MMU), che svolge il ruolo fondamentale nella gestione della memoria virtuale.

La memoria di un computer è divisa in due classi principali. La memoria primaria (RAM) è quella direttamente accessibile dal processore per leggere e scrivere dati durante l’esecuzione dei programmi. La memoria secondaria (dischi, SSD, ecc.) è utilizzata per conservare dati in modo permanente e, nel contesto della memoria virtuale, per ospitare lo spazio di swap (in ambiente POSIX) o il file di paging (in ambiente Windows). La memoria virtuale è un’architettura di sistema capace di simulare uno spazio di memoria centrale maggiore di quello fisicamente presente, dando all’utente l’illusione di un enorme quantitativo di memoria. Il sistema operativo, mediante una combinazione di hardware e software, mappa gli indirizzi virtuali usati da un programma in indirizzi fisici reali. Questa traduzione è effettuata dalla MMU, che traduce gli indirizzi logici in indirizzi fisici, verifica la presenza della zona di memoria richiesta e, in caso di assenza, genera una page fault. Il kernel, a sua volta, gestisce la page fault caricando la pagina dallo spazio di swap nella RAM, eventualmente sostituendo una pagina già presente.

Il meccanismo di traduzione introduce un costo in termini di prestazioni. Il tempo medio di accesso alla memoria in presenza di memoria virtuale è dato dalla formula:

Tav = Tt + Ta + Tload × Pfault

dove Tt è il tempo di traduzione della MMU, Ta è il tempo di accesso alla memoria fisica, Tload è il tempo necessario a caricare una zona di memoria dallo swap e Pfault è la probabilità di incorrere in una page fault. Questo indica che, se la probabilità di page fault è bassa, l’overhead introdotto dalla traduzione è contenuto; al contrario, un’alta frequenza di page fault può penalizzare significativamente le prestazioni.

Esistono due principali modalità di implementazione della memoria virtuale. La memoria paginata suddivide sia lo spazio di indirizzi virtuale sia la RAM in blocchi di dimensione fissa (tipicamente 4 o 8 kilobyte). Ogni processo possiede una tabella delle pagine, che contiene per ogni pagina il numero di frame corrispondente, il bit present e il bit modified. Il bit present indica se la pagina è presente in RAM; se è 0 si genera una page fault. Il bit modified indica se la pagina è stata modificata, evitando di riscrivere su disco pagine non modificate durante lo swap. La traduzione da indirizzo logico a fisico avviene concatenando l’offset al numero di frame, operazione estremamente veloce in hardware.

La memoria segmentata, al contrario, si basa su una suddivisione logica del programma in segmenti funzionalmente omogenei. La MMU tiene traccia dei segmenti presenti e della loro posizione. Questo approccio riduce il ricorso allo swap grazie al principio di località, ma può provocare una frammentazione esterna, con spazi di memoria inutilizzabili troppo piccoli per essere allocati, richiedendo operazioni di compattazione.

Il kernel è il programma centrale del sistema operativo che controlla l’intero hardware e fornisce servizi ai processi. Tra le sue funzioni vi sono la gestione della memoria (inclusa la memoria virtuale), la pianificazione dei processi (scheduling), la gestione delle periferiche e la fornitura di chiamate di sistema. Il kernel può essere classificato in quattro categorie in base al grado di astrazione dell’hardware:

Kernel monolitici implementano una completa astrazione dell’hardware e includono tutti i driver e i servizi in un unico spazio di indirizzamento. Sebbene un bug in un modulo possa bloccare l’intero sistema, l’integrazione stretta rende questi kernel molto efficienti. Esempi sono i tradizionali kernel BSD e il kernel Linux, che può caricare moduli in fase di esecuzione.

Microkernel forniscono solo un insieme ristretto di astrazioni dell’hardware; le funzionalità aggiuntive, comprese le gestioni delle periferiche, sono realizzate da driver o server in spazio utente.

Kernel ibridi (o microkernel modificati) combinano le caratteristiche dei microkernel con alcune funzioni aggiuntive nel kernel per migliorare le prestazioni.

Esokernel rimuovono quasi tutte le astrazioni dell’hardware, limitandosi a garantire l’accesso concorrente, lasciando alle applicazioni la responsabilità di implementare le tradizionali astrazioni tramite librerie speciali.

I driver sono componenti software che fungono da interfaccia tra il kernel e le periferiche. In un kernel monolitico i driver sono parte integrante del kernel; in un microkernel, invece, i driver operano come server in spazio utente, comunicando con il kernel tramite meccanismi di IPC (inter-process communication). Il ruolo dei driver è quello di tradurre le richieste generiche del kernel (ad esempio, lettura o scrittura) in comandi specifici per il dispositivo hardware, gestendo anche le interruzioni generate dalla periferica.

Le periferiche (o dispositivi di I/O) includono unità di memorizzazione, schede di rete, tastiere, mouse, stampanti e altri componenti che estendono le capacità del computer. Il kernel, attraverso i driver, assegna a ciascuna periferica una porzione di risorse (intervalli di indirizzi, linee di interrupt, canali DMA) e ne controlla l’accesso in modo sicuro e coordinato. Questo isolamento è fondamentale per la sicurezza: la memoria virtuale, grazie all’isolamento dei processi, impedisce a un programma di accedere a regioni di memoria non autorizzate.

Il flusso operativo tipico di un sistema con memoria virtuale e driver è il seguente: un processo richiede l’esecuzione di un’istruzione che accede a un indirizzo virtuale; la MMU traduce l’indirizzo in fisico; se la pagina è presente, l’accesso avviene in RAM; se la pagina non è presente, la MMU genera una page fault; il kernel intercetta la fault, individua il driver di storage responsabile dello swap, carica la pagina dallo spazio di swap nella RAM e aggiorna la tabella delle pagine. Parallelamente, il kernel può delegare la gestione di una periferica (ad esempio una stampante) al driver corrispondente, che traduce le richieste di stampa in comandi hardware.

Le motivazioni che rendono indispensabili questi meccanismi sono molteplici. La memoria virtuale consente di superare i limiti fisici della RAM, migliorare la sicurezza tramite l’isolamento dei processi e condividere pagine di librerie tra più processi, riducendo il consumo complessivo di memoria. I driver, invece, permettono al sistema operativo di supportare una vasta gamma di dispositivi senza dover modificare il nucleo del kernel, favorendo la modularità e la portabilità. Infine, la classificazione dei kernel (monolitico, microkernel, ibrido, esokernel) riflette diversi compromessi tra prestazioni, complessità e sicurezza, consentendo di scegliere l’architettura più adatta al contesto d’uso, dal desktop tradizionale ai sistemi embedded o ai data center ad alta densità.

In sintesi, l’architettura hardware di un computer è il risultato dell’integrazione di CPU, memoria, periferiche e driver, orchestrati dal kernel. La memoria virtuale, tramite la MMU, fornisce un’astrazione fondamentale che rende possibile l’uso efficiente della RAM e dello spazio di swap, mentre i driver garantiscono che ogni periferica possa essere controllata in modo uniforme e sicuro, indipendentemente dalla sua natura specifica. Comprendere questi concetti è essenziale per chi sviluppa software di sistema, poiché ogni livello – dal set di istruzioni della CPU alle chiamate di sistema del kernel – influisce direttamente sulle prestazioni, sulla stabilità e sulla sicurezza dell’intero sistema.

9. Ripasso operativo – esercizi pratici e simulazioni d’esame

Il concetto di classe costituisce il fondamento della programmazione orientata agli oggetti. Una classe definisce un tipo di dato e permette la creazione di oggetti secondo le caratteristiche stabilite nella sua dichiarazione. Gli oggetti, una volta istanziati, sono gli elementi concreti del modello astratto definito dalla classe.

Una classe è composta da due componenti essenziali. Il primo sono gli attributi, analoghi ai membri di un record, cioè variabili e/o costanti che descrivono le proprieta' degli oggetti. Il valore iniziale di ciascun attributo viene assegnato mediante il costruttore, ovvero la procedura che viene invocata al momento dell'istanziazione. Il secondo componente sono i metodi, cioè le procedure che operano sugli attributi, modificandoli o restituendo informazioni derivanti dal loro stato.

Le relazioni di ereditarieta' consentono di creare nuove classi a partire da quelle esistenti. Una classe derivata eredita tutti gli attributi e i metodi della classe base e può estenderli aggiungendo nuove proprieta' o comportamenti. Questo meccanismo permette di modellare gerarchie concettuali in modo modulare, riducendo la ridondanza del codice.

Un paragone con la matematica, pur impreciso, aiuta a comprendere la natura della classe. In matematica un insieme può essere definito in modo intensivo, indicando le sue proprieta' piuttosto che elencandone gli elementi. Analogamente, una classe definisce le proprieta' comuni a tutti gli oggetti che ne saranno istanziati, ma non ne specifica il numero. Il numero di oggetti creati dipende dall'esecuzione del programma e può variare da zero a un valore limitato solo dalla memoria disponibile.

Questa analogia evidenzia anche la differenza tra la definizione di un insieme (che ha un numero di elementi intrinseco) e la definizione di una classe (che rimane un modello astratto, pronto ad essere realizzato). In termini pratici, la classe è paragonabile al progetto di un'infrastruttura: il progetto descrive le caratteristiche generali, mentre la realizzazione (gli oggetti) dipende dalla decisione di costruire o meno e dal numero di unità realizzate.

Nel contesto di un esame, la comprensione di questi concetti è fondamentale. Di seguito vengono proposti esercizi pratici che mirano a verificare la capacità di definire, istanziare e manipolare classi, nonché di utilizzare l'ereditarieta' per estendere funzionalita'.

Esercizio 1 – Definizione di una classe base
Scrivere la dichiarazione di una classe denominata Veicolo che contenga i seguenti attributi: marca (stringa), modello (stringa) e anno (intero). Definire inoltre un metodo descrivi() che restituisca una stringa formata dalla concatenazione di tutti gli attributi. Specificare il costruttore che inizializza gli attributi con i valori forniti al momento dell'istanziazione.

Esercizio 2 – Creazione di oggetti
Utilizzando la classe Veicolo definita nell'esercizio precedente, creare tre oggetti distinti rappresentanti tre veicoli diversi. Per ciascun oggetto, invocare il metodo descrivi() e verificare che la stringa restituita contenga i valori corretti degli attributi.

Esercizio 3 – Ereditarieta' semplice
Definire una classe Auto che erediti da Veicolo. Aggiungere alla classe Auto un nuovo attributo numeroPorte (intero) e un metodo descriviCompleto() che richiami il metodo descrivi() della classe base e aggiunga l'informazione sul numero di porte. Implementare il costruttore di Auto in modo da inizializzare sia gli attributi ereditati sia quello nuovo.

Esercizio 4 – Overriding di metodi
Modificare la classe Auto in modo che il metodo descrivi() venga sovrascritto (overridden) per includere anche il numero di porte, senza creare un nuovo metodo. Verificare che, chiamando descrivi() su un'istanza di Auto, la stringa restituita contenga tutte le informazioni richieste.

Esercizio 5 – Gerarchia multipla
Estendere ulteriormente la gerarchia creando una classe Camion che erediti da Veicolo e aggiunga gli attributi capacitaCarico (float) e numeroAssi (intero). Definire un metodo descriviCamion() che combini le informazioni ereditate con quelle specifiche del camion.

Esercizio 6 – Simulazione d’esame: analisi di un caso pratico
Un esaminatore fornisce la seguente descrizione: “Si deve modellare un sistema di gestione di una biblioteca. Ogni Libro ha titolo, autore e anno di pubblicazione. Alcuni libri sono Ebook e possiedono inoltre il formato file. Altri sono LibroCartaceo e hanno un numero di pagine. Si richiede di definire le classi, gli attributi, i metodi di descrizione e le relazioni di ereditarieta'.” Utilizzare le informazioni fornite per scrivere le dichiarazioni di classe, indicando chiaramente quali attributi sono ereditati e quali sono aggiunti dalle classi derivate.

Esercizio 7 – Costruttore e valori di default
Modificare la classe Veicolo in modo che il costruttore assegni un valore di default all’anno (ad esempio 2020) qualora non venga specificato. Verificare, mediante istanziazione di un oggetto senza fornire l’anno, che il valore di default venga correttamente assegnato.

Esercizio 8 – Metodi che modificano gli attributi
Aggiungere alla classe Auto un metodo cambiaNumeroPorte(nuovoNumero) che aggiorni l’attributo numeroPorte. Dimostrare, con un esempio pratico, che l’invocazione del metodo modifica lo stato interno dell’oggetto e che il metodo descriviCompleto() restituisce il valore aggiornato.

Esercizio 9 – Analisi di un errore comune
Un programmatore dichiara una classe Dispositivo con attributi marca e modello, ma dimentica di includere un costruttore. Spiegare, basandosi sulla definizione di classe, quale conseguenza avra' la mancata definizione del costruttore al momento dell’istanziazione di un oggetto.

Esercizio 10 – Riflessione sul modello astratto
Scrivere una breve risposta che confronti la visione della classe come modello astratto con l’analogia dell’infrastruttura descritta nella fonte. Evidenziare come la possibilita' di istanziare un numero arbitrario di oggetti renda la classe un modello flessibile rispetto a un progetto fisico.

Questi esercizi coprono tutti gli aspetti fondamentali descritti nella fonte: definizione di classe, attributi, costruttore, metodi, ereditarieta' e analogia con il modello astratto. La pratica costante su questi temi permette di consolidare la comprensione teorica e di affrontare con sicurezza le domande d’esame che richiedono la capacità di progettare e manipolare classi in modo corretto.

← Tutti i riassunti per questo concorso