Gestione del Cambiamento e Refactoring

La manutenzione costituisce la fase più lunga e costosa dell'intero ciclo di vita del software. Un sistema deve evolvere inevitabilmente o rischia di diventare inutile.

Le Cause Formali del Cambiamento

Le ragioni inevitabili per cui un sistema deve essere modificato:

  • L'emergere di nuovi requisiti durante l'utilizzo prolungato del sistema.
  • Cambiamenti nell'ambiente di business (nuove normative, fusioni aziendali, nuovi mercati).
  • La disponibilità di nuovi servizi (spesso più economici) da sfruttare (es. API di terze parti).
  • La necessità di riparare errori scoperti o migliorare affidabilità e performance.
  • L'obsolescenza dell'hardware o dei sistemi operativi e l'adozione di nuovi modelli di rilascio (es. passaggio al Cloud).
Struttura ed Elementi dei Sistemi Legacy

I Sistemi Legacy sono sistemi "ereditati", obsoleti ma critici per l'azienda. Riscriverli da zero comporta rischi altissimi di blocco del business. Sono composti da 4 elementi interdipendenti:

  • System hardware: L'hardware originale per cui il sistema è stato scritto, che potrebbe non essere più in produzione o supportato.
  • Support software: Il software di supporto obsoleto o non più aggiornato (vecchi compilatori, vecchi sistemi operativi o librerie deprecate).
  • Application software: I programmi applicativi veri e propri (scritti magari in COBOL o vecchie versioni Java) che forniscono i servizi aziendali essenziali.
  • Application data: I dati elaborati, spesso massivi, che possono essere inconsistenti o duplicati in file o database arcaici differenti.
Fattori di Valutazione per i Sistemi Legacy

Prima di decidere se mantenere, migrare o spegnere un sistema legacy, vanno valutati questi fattori ingegneristici:

  • Il linguaggio di programmazione usato e la disponibilità attuale di compilatori/interpreti aggiornati.
  • La presenza di un sistema di Configuration management per tracciare storicamente le versioni dei componenti.
  • L'esistenza di Test data e registri di test di regressione per validare le nuove funzionalità in sicurezza.
  • Le Personnel skills: la disponibilità nel mercato di personale con le competenze tecniche necessarie per mantenere quel sistema specifico.
Code Smells e Refactoring vs Reingegnerizzazione
  • Code Smells (Puzze del Codice): Segnali d'allarme nel codice sorgente che indicano un problema di progettazione profondo. Esempi: Codice duplicato o Classi e Metodi troppo grandi (violando la Coesione).
  • Refactoring: Il processo di pulizia e miglioramento della struttura interna del codice senza alterarne il comportamento esterno (il software fa la stessa cosa, ma il codice è più manutenibile). Serve per ridurre il debito tecnico ed è supportato dai test automatici.
  • Reingegnerizzazione: Una riscrittura e ri-progettazione profonda del sistema, spesso necessaria per migrare un Sistema Legacy verso architetture moderne (es. dal Monolite ai Microservizi in Cloud).
L'Impatto dell'AI nella Manutenzione (TuringBots)

L'Intelligenza Artificiale funge da Refactoring Agent e Legacy Translator per combattere il debito tecnico:

  • Spiegazione automatica: Decifrazione del codice legacy obsoleto e difficile da capire ("Explain this code").
  • Legacy Translation: Traduzione automatica del vecchio codice in architetture e linguaggi moderni (ad esempio, la conversione diretta di una codebase da Java 8 a Java 21).
  • Refactoring intelligente: Suggerimento mirato di pattern di refactoring applicabili per ripulire la struttura del codice accumulato.

Software Reuse (Riuso del Software)

Reinventare la ruota scrivendo ogni componente da zero è economicamente insostenibile e introduce nuovi bug. L'ingegneria del software moderna si basa sull'assemblaggio intelligente di pezzi già pronti.

Open Source, Glue Code e Dipendenze Transitive
  • Componenti COTS e Open Source: Pezzi di software pronti all'uso (librerie grafiche, database). Oggi oltre l'80% del codice di una nuova app è scritto da altri (scaricato via Build Tools come Maven).
  • Glue Code (Codice Colla): Quando si prendono componenti diversi, questi non "parlano" nativamente tra loro. Si scrive molto "codice colla" (implementando il pattern Adapter) per adattarne le interfacce.
  • Dipendenze Transitive ("software you don't even know"): Ogni dipendenza che includi volontariamente porta con sé una serie di altre dipendenze richieste dalla libreria stessa. Questo fa sì che il codice scritto da te sia una frazione minuscola del totale. L'albero delle dipendenze diventa complesso ed è vitale tracciarlo (es. usando la demo pratica del comando mvn dependency:tree).

Sicurezza della Supply Chain

Se il tuo software è composto per l'80% da librerie open source, sei responsabile della sicurezza di codice che non hai mai letto.

Il problema delle Dipendenze e la SBOM

Il caso Log4j ha dimostrato che una libreria vulnerabile nascosta nelle dipendenze transitive può compromettere server globalmente.

  • Software Bill of Materials (SBOM): È la "Distinta Base" del software. Un documento formale leggibile dalle macchine che elenca ogni componente e dipendenza. Permette di reagire istantaneamente alle vulnerabilità (Zero-day) senza rileggere milioni di righe di codice.
  • Struttura e Dettagli SBOM: Un documento SBOM contiene campi tecnici rigorosi: Component Name, Identificatori Unici (es. SPDXID), Version String, Component Hash (PackageChecksum per l'integrità crittografica), Author Name, e le Relazioni tra componenti (es. la gerarchia CONTAINS).
  • Operazioni sui Documenti SBOM: Un sistema maturo deve permettere operazioni di Consume View (lettura umana), Diff (comparazione tra versioni del software per notare aggiunte/rimozioni), Analyze (importazione in sistemi di sicurezza) e Transform (cambio di formato senza perdita di informazioni).
  • Licencing: La gestione delle licenze del software open source riutilizzato è un topic fondamentale. Oltre alla sicurezza, bisogna garantire la conformità legale per evitare sanzioni o l'obbligo di rendere pubblico il proprio codice proprietario (effetto virale di alcune licenze).
07 · Cloud AWS