1. Teoria SCM (Source Control Management)

Il controllo di versione è la spina dorsale dello sviluppo collaborativo. Gestire il codice in team richiede sistemi robusti per prevenire perdite di dati e risolvere sovrapposizioni.

Centralizzato vs Distribuito
  • Centralizzato (SVN): Un unico server centrale contiene la history del repository. Ogni sviluppatore scarica solo l'ultima versione dei file. Operazioni come commit o l'analisi della history richiedono una connessione costante al server. Se il server cade, nessuno può lavorare.
  • Distribuito (Git): Ogni client possiede una copia locale completa (clone) dell'intero repository, con tutta la history. Le operazioni sono istantanee e offline. La sincronizzazione (push/pull) avviene solo quando necessario verso un server condiviso (es. GitHub o GitLab).
Snapshot vs Delta
  • Sistemi Delta-based (SVN): Memorizzano solo le differenze (delta) tra la versione base di un file e le sue modifiche successive. Per ricostruire la versione attuale, il sistema deve sommare tutti i delta.
  • Sistemi Snapshot (Git): A ogni commit, Git scatta una "fotografia" (snapshot) di come appare l'intero file system in quel momento. Se un file non è cambiato, Git memorizza un semplice collegamento alla versione precedente. Questo rende Git incredibilmente veloce nel checkout e nel branching.
Gestione Conflitti: Copy-Modify-Merge

I vecchi sistemi usavano il modello Lock-Modify-Unlock (un file poteva essere modificato da una sola persona alla volta bloccandolo globalmente). Git usa il Copy-Modify-Merge: tutti possono modificare copie locali in parallelo senza bloccare nessuno. Quando avviene un push, se due sviluppatori hanno toccato la stessa riga, Git segnala un conflitto e delega allo sviluppatore il compito di risolvere manualmente la sovrapposizione prima di completare la merge definitiva.

2. Strategie di Branching (Workflow)

Come organizzare il lavoro in team quando decine di sviluppatori contribuiscono in contemporanea allo stesso repository.

Gitflow

Un workflow molto strutturato, ideale per prodotti enterprise con cicli di rilascio lenti e pianificati.

  • Usa rami a lunga vita: main (solo codice in produzione stabile) e develop (integrazione continua delle nuove feature).
  • Le nuove funzionalità nascono isolatamente nei feature branches e poi confluiscono in develop.
  • Prima di un rilascio, si crea un release branch per il collaudo e il bugfixing dell'ultimo minuto.
  • Per problemi critici scoperti in produzione, si aprono rami hotfix direttamente dal main.
Trunk-Based Development

Il workflow moderno preferito dalle metodologie agili DevOps e dal Cloud Native.

  • Tutti gli sviluppatori committano e fondono codice frequentemente (anche più volte al giorno) direttamente su un unico ramo principale (chiamato main o trunk), o su feature branch di brevissima vita (poche ore).
  • Elimina i blocchi organizzativi e il "Merge Hell" (la difficoltà immane di unire rami vecchi di settimane).
  • Prerequisito vitale: Lavorare tutti su main richiede una suite di test automatizzati rigorosi (CI/CD) per garantire che il codice sia sempre "deployable". Spesso si usano i Feature Toggles per nascondere agli utenti reali funzionalità ancora non finite.

3. Continuous Integration & Code Analysis

La Continuous Integration serve a mitigare il rischio di integrazione tardiva e la complessità di integrare codice sviluppato in isolamento per troppo tempo.

Motivazioni e Tool

Integrare frequentemente il codice (almeno una volta al giorno) permette di rilevare tempestivamente i bug, riducendo l'"Integration Hell".

  • Strumenti Storici e Attuali: Hudson e il suo fork Jenkins sono stati i pionieri open-source, basati su server standalone. Bamboo è la soluzione enterprise di Atlassian. Oggi il mercato si sta spostando su soluzioni cloud-native integrate direttamente nella piattaforma di repository, come GitLab CI/CD e GitHub Actions.
Analisi Statica e SonarQube

Le pipeline di CI moderne non si limitano a compilare il codice, ma includono fasi automatizzate di Analisi Statica (Static Application Security Testing).

  • SonarQube: È lo standard di mercato per la code quality. Analizza il codice sorgente per individuare vulnerabilità (Bugs), pattern di programmazione errati (Code Smells) e misurare la copertura dei test (Test Coverage).
  • Quality Gates: Regole booleane configurate in SonarQube (es. "Copertura Test > 80%"). Se il codice non supera il Quality Gate, la pipeline di CI/CD si blocca (fail) e il branch non può essere unito (merge) al ramo principale.

4. Maven Deep Dive

Maven non è solo un semplice scaricatore di librerie, ma un orchestratore potente dell'intero ciclo di vita (build lifecycle) del software Java.

Alternative Storiche e Moderne
  • Make: Il primissimo build tool, basato su Makefile (script shell-like). Estremamente flessibile ma considerato difficile da mantenere e da debuggare per progetti complessi.
  • Apache Ant: Nato in ambito Java, sostituiva i Makefile con file XML (build.xml). È estensibile tramite task ma, storicamente, mancava di un supporto nativo per la gestione automatica delle dipendenze (aggiunta solo dopo con Apache Ivy), costringendo a check-in manuali dei file .jar.
  • Gradle: L'alternativa moderna a Maven. Più veloce perché non forza un lifecycle rigido e definisce le dipendenze basandosi su grafi diretti aciclici (DAG) di task. È scritto in Groovy o Kotlin ed è diventato il tool di build predefinito per Android.
Build Lifecycle (Fasi di Build)

Maven definisce una sequenza ordinata e logica di fasi. Chiamando l'esecuzione di una singola fase, Maven eseguirà automaticamente in sequenza tutte le fasi precedenti ad essa nell'albero.

  • validate: Controlla che il progetto sia corretto (sintassi pom.xml) e tutte le info siano disponibili.
  • compile: Prende il codice sorgente (.java) e lo compila in bytecode (.class).
  • test: Esegue i test unitari usando framework standard (come JUnit) bloccando la build se un test fallisce.
  • package: Impacchetta il codice appena compilato e collaudato (es. in un archivio distributivo .jar o .war).
  • verify: Lancia test di integrazione pesanti sul pacchetto per verificarne ulteriormente la validità nel contesto reale.
  • install: Copia il pacchetto nel repository locale della macchina (nella cartella .m2) per renderlo utilizzabile come dipendenza da altri progetti Maven locali dello stesso sviluppatore.
  • deploy: Carica in modo sicuro l'artefatto compilato in un repository remoto o aziendale (es. Nexus, Artifactory) per la condivisione finale con l'intero team.
Gestione delle Dipendenze Transitive

Il meccanismo "transitivo" è il cuore del gestore di dipendenze. Se il tuo pom.xml richiede la libreria A, e chi ha sviluppato la libreria A ha indicato nel suo pom che ha bisogno della libreria B, Maven scaricherà automaticamente anche B nel tuo progetto.

Gestione Conflitti di versione: Spesso il modulo X scarica la libreria C in versione 1.0, mentre il modulo Y scarica la stessa libreria C in versione 2.0. Quale viene tenuta nel pacchetto finale? Maven applica algoritmi di mediazione, generalmente vince la "nearest definition": sceglie la dipendenza che appare più "vicina" alla radice nell'albero gerarchico delle dipendenze.

Indipendenza dall'IDE e Spotless
  • Indipendenza dall'IDE: Una regola ingegneristica fondamentale è che Maven deve essere l'astrazione finale della build. Un progetto deve potersi compilare, testare ed impacchettare correttamente da riga di comando (es. mvn clean install) senza alcuna dipendenza dalle configurazioni o dai plugin locali dell'IDE (IntelliJ, Eclipse, VS Code) di chi sta programmando. Questo garantisce che la build funzioni in modo deterministico anche sui server di Continuous Integration.
  • Formattazione automatica (Spotless): È vitale usare plugin Maven come Spotless per applicare e forzare uno standard di formattazione del codice unico per tutto il team. Questo evita che su Git si creino "rumori" e finti conflitti dovuti a semplici differenze di tabulazioni, spazi o fine riga introdotti dai vari IDE degli sviluppatori.

5. Virtualizzazione e Docker

I Container rappresentano la rivoluzione del deployment moderno, impacchettando il codice assieme a tutte le sue dipendenze di sistema in un formato standardizzato e portabile.

Containers vs Macchine Virtuali (VM)
  • Macchine Virtuali (VM): Virtualizzano l'hardware. Includono sempre un intero sistema operativo "Guest" completo, che gira sopra un Hypervisor. Sono pesanti (Gigabyte), lente ad avviarsi e sprecano risorse per far girare processi OS ridondanti.
  • Containers: Virtualizzano il sistema operativo. Più container condividono lo stesso kernel del sistema operativo host, isolando solo lo spazio utente (filesystem, processi, rete). Sono leggerissimi (Megabyte), si avviano in millisecondi e massimizzano l'efficienza delle risorse.
Terminologia Docker
  • Image: È il pacchetto statico, immutabile, che contiene il codice, le librerie e gli strumenti necessari. Rappresenta i dati "a riposo" (template).
  • Container: È un'istanza viva e in esecuzione di un'Image. Può essere creata, avviata, fermata o distrutta.
  • Engine: Il software runtime di base (il demone Docker) installato sul server che ha il compito pratico di creare, eseguire e gestire i Container.
  • Registry: Un magazzino centralizzato (es. Docker Hub) dove vengono archiviate, versionate e distribuite le Image per essere scaricate e usate nei deployment.

6. Sicurezza della Supply Chain

Oggi nessuna azienda costruisce un software interamente da zero. I progetti moderni sono assemblaggi di decine di librerie scritte da terzi open-source. Questo apre a rischi catastrofici se uno di questi anelli della catena di fornitura (Supply Chain) viene compromesso.

Il caso Log4Shell (Vulnerabilità Sistemica)

A fine 2021, è stata scoperta una falla critica estrema (grado massimo, CVSS 10.0) in Log4j, la minuscola libreria di logging per Java usata dal 99% dei server mondiali. Un attaccante remoto poteva prendere il controllo totale del server inviandogli semplicemente una stringa di testo specifica. Siccome Log4j era inclusa come dipendenza transitiva ovunque, l'attacco ha colpito infrastrutture di Amazon, Apple, server di Minecraft, sistemi sanitari e banche centrali, dimostrando come la compromissione di un singolo nodo quasi invisibile dell'albero open-source possa mettere in ginocchio la rete globale.

SBOM (Software Bill of Materials)

Come ci si difende da rischi come Log4Shell? La soluzione metodologica promossa dallo standard di settore è l'adozione dell'SBOM. Come nei prodotti alimentari, è letteralmente la "lista degli ingredienti" del tuo software compilato. Consiste in un file o un database generato in automatico che elenca ricorsivamente tutti i componenti di terze parti inclusi, le loro versioni esatte e le rispettive licenze d'uso. Nel momento in cui nel mondo esplode una nuova falla "zero-day", un team di sicurezza può scansionare in 3 secondi la propria SBOM per capire inequivocabilmente se e in quale file del proprio vasto ecosistema risiede la libreria vulnerabile, senza dover scaricare, spacchettare o ricompilare il codice sorgente.

7. AI in DevOps

L'Intelligenza Artificiale Generativa non è più riservata solo ad assistere lo sviluppatore nell'IDE per generare righe di codice, ma sta impattando prepotentemente tutto il ciclo di vita DevOps e IT Operations.

DevOps TuringBots

Con il termine TuringBots si identificano gli assistenti autonomi (o semi-autonomi) basati su LLM che lavorano al fianco degli ingegneri dell'infrastruttura, riducendo esponenzialmente il Toil manuale per i seguenti scopi:

  • Generazione Infrastruttura As Code: Creare da zero complessi file Dockerfile o moduli di Terraform descrivendo la topologia di rete desiderata in puro linguaggio naturale conversazionale.
  • Fix delle Pipeline CI/CD: Di fronte al fallimento di una pipeline di build causato da centinaia di log criptici, i TuringBots diagnosticano all'istante l'errore analizzando l'output della build, individuando quale step o dipendenza ha bloccato il rilascio, proponendo o applicando il fix per il GitHub Actions yaml.
  • Semantic Commits: Rilevare in automatico le righe di codice effettivamente variate in uno snapshot locale (il "diff") e autogenerare istantaneamente il testo del git commit -m aderendo allo standard Conventional Commits aziendale.
05 · Modellazione & Design 07 · Cloud AWS