Ogni progetto software prima o poi si imbatte in codice obsoleto, componenti contrassegnati come superati, sconsigliati o programmati per la rimozione. @deprecated annotazione in Java, l DeprecationWarning In Python, la barratura nel completamento automatico del tuo IDE, tutti questi sono segnali provenienti dal codice sorgente che qualcosa che stai utilizzando o gestendo è stato superato. Ignorare questi segnali accumula silenziosamente il rischio finché non viene rimossa una dipendenza, una patch di sicurezza non salta un'API obsoleta o un aggiornamento del framework non manda in crash tutto ciò che si basava ancora su qualcosa che è stato deprecato tre versioni principali prima.
Comprendere cosa significhi "deprecato", perché sia importante e come gestirlo in modo sistematico è una delle competenze di manutenzione più pratiche che un team di sviluppo possa acquisire. Questa guida offre una panoramica completa: definizioni chiare, confronto con termini simili, avvisi di deprecazione per i diversi linguaggi di programmazione e un approccio strutturato alla gestione delle dipendenze deprecate prima che si trasformino in problemi di produzione.
Smetti di scoprire gli ammortamenti in produzione
SMART TS XL superfici componenti obsolete prima che diventino incidenti.
Maggiori InformazioniChe cos'è il codice obsoleto?
Il codice obsoleto si riferisce a funzioni, metodi, API, librerie o interi componenti che sono ancora funzionanti ma il cui utilizzo è ufficialmente sconsigliato. Il codice continua a funzionare, si compila, si esegue e produce risultati, ma i suoi manutentori hanno segnalato che verrà rimosso in una versione futura, sostituito da un'alternativa migliore o semplicemente non sarà più mantenuto o aggiornato. Utilizzare codice obsoleto significa fare affidamento su qualcosa di cui i suoi responsabili hanno smesso di preoccuparsi.
La deprecazione è un meccanismo di comunicazione, non uno stato tecnico. Quando chi si occupa della manutenzione di una libreria contrassegna una funzione come deprecata, sta dicendo: "Questa funzione funziona ancora oggi, ma intendiamo rimuoverla e dovresti migrare a un'altra versione prima che ciò accada". Il tempo che intercorre tra l'avviso di deprecazione e la rimozione effettiva varia, potrebbe essere una versione principale o cinque anni, ma la direzione è sempre la stessa. Deprecato significa che verrà rimosso prima o poi.
Deprecated vs. Depreciated: la confusione ortografica
Queste due parole vengono spesso confuse e i correttori ortografici non sono d'aiuto perché entrambe sono parole inglesi reali con significati diversi.
Deprecato (nel software): contrassegnato come obsoleto, sconsigliato, destinato alla rimozione. Il termine corretto per il contesto software.
Deprezzato (in contabilità): il cui valore diminuisce nel tempo. Ad esempio, "l'hardware del server si è deprezzato in tre anni".
Se in un documento tecnico compare l'espressione "deprecated code", quasi sempre significa "deprecated code", ovvero codice obsoleto. L'autore ha utilizzato il termine contabile al posto del termine relativo al software. L'errore è abbastanza comune da comparire nei dati di Search Console per questo articolo. Nel software, si deve sempre utilizzare "deprecated".
Codice obsoleto vs. obsoleto vs. codice legacy vs. codice morto
Questi termini sono correlati ma descrivono stati diversi del codice. Confonderli porta a conversazioni imprecise e a decisioni errate in materia di priorità.
| Termine | Cosa significa | È stato rimosso? | È mantenuto? | Livello di rischio |
|---|---|---|---|---|
| deprecato | Ufficialmente sconsigliato, contrassegnato per la futura rimozione | No, ancora presente | No, la manutenzione è stata interrotta. | Medio, in crescita nel tempo |
| Obsoleto | Non più rilevante o applicabile; superato | A volte | Non | Media altezza |
| Eredità | Vecchio codice che funziona ancora e potrebbe essere ancora in produzione | No, ancora attivo | Raramente | Variabile, dipende dal tasso di variazione |
| Codice morto | Non è stato possibile contattarlo durante l'esecuzione. | No, ancora nella fonte | Non applicabile, non funziona mai | Rischio di migrazione/audit da basso a medio |
| Codice obsoleto | Codice che non è stato modificato da molto tempo ma non è formalmente deprecato. | Non | non chiaro | Medio, potrebbe nascondere delle supposizioni |
Deprecato vs. obsoleto: Deprecato è una designazione formale, qualcuno l'ha contrassegnato esplicitamente con @deprecated o ha emesso un avviso di deprecazione. Obsoleto è un termine più generico: il codice potrebbe ancora funzionare, ma non ha più un caso d'uso ragionevole, viste le alternative moderne. Tutto il codice deprecato diventa obsoleto prima o poi, ma non tutto il codice obsoleto è stato formalmente deprecato.
Codice obsoleto vs. codice rimosso : il codice obsoleto è ancora presente nel codice sorgente. Il codice rimosso è sparito. Il periodo di obsolescenza è l'intervallo di tempo tra i due stati, ovvero il tempo a disposizione per migrare prima che il codice smetta di funzionare.
Codice obsoleto vs. codice legacy : il codice legacy è un vecchio codice di produzione, spesso ancora attivamente utilizzato e mantenuto, scritto in un'era tecnologica precedente. Il codice obsoleto è specificamente contrassegnato per la rimozione. I programmi COBOL legacy che elaborano le transazioni quotidiane non sono obsoleti, sono legacy ma attivamente mantenuti. Una funzione API COBOL contrassegnata come obsoleta dal fornitore della libreria è obsoleta.
Deprecazione vs. dismissione : la deprecazione è un segnale tecnico all'interno di una codebase o di una libreria. La dismissione è una decisione operativa, che consiste nell'arresto di un servizio, nella rimozione dell'infrastruttura o nella fine del supporto per un prodotto. Un'API deprecata potrebbe continuare a funzionare per anni; un'API dismessa viene disattivata in una data specifica.
Come si presenta un avviso di deprecazione: avvisi in diverse lingue
Gli avvisi di deprecazione assumono forme diverse a seconda della lingua e degli strumenti utilizzati. Riconoscerli a prima vista è il primo passo per affrontarli.
Python: Avviso di deprecazione
python
import warnings
# Marking a function as deprecated
def old_function():
warnings.warn(
"old_function is deprecated, use new_function instead",
DeprecationWarning,
stacklevel=2
)
# original implementation
def new_function():
# improved implementation
pass
Python visualizza avvisi di deprecazione in fase di esecuzione. Il messaggio comune del compilatore è:
DeprecationWarning: old_function is deprecated, use new_function instead
Oppure per i pacchetti di terze parti:
DeprecationWarning: pkg_resources is deprecated as an API.
Use importlib.resources or importlib.metadata instead.
Java: annotazione @Deprecated
Giava
public class LegacyProcessor {
@Deprecated
public void processData(String input) {
// old implementation
}
// Replacement method
public void processDataV2(String input, ProcessOptions options) {
// new implementation
}
}
Il compilatore Java produce:
Note: SomeFile.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
JavaScript/TypeScript: JSDoc @deprecato
javascript
/**
* @deprecated Use fetchUserById() instead.
* This function will be removed in version 4.0.
*/
function getUser(id) {
// old implementation
}
// Modern replacement
async function fetchUserById(id) {
// new implementation
}
dattiloscritto
class ApiClient {
/** @deprecated Use post() with typed options instead */
sendRequest(url: string): Promise<any> {
// deprecated implementation
}
}
Gli IDE visualizzano getUser con una barratura ovunque venga chiamato e TypeScript @typescript-eslint/no-deprecated La regola lo segnala in CI.
C++: [[deprecato]] Attributo
cpp
// C++14 and later
[[deprecated("Use processV2() instead")]]
void process(int value) {
// old implementation
}
void processV2(int value, ProcessFlags flags = ProcessFlags::Default) {
// new implementation
}
I compilatori producono:
warning: 'process' is deprecated: Use processV2() instead [-Wdeprecated-declarations]
Swift: @disponibile con deprecato
veloce
@available(*, deprecated, renamed: "fetchUser(withID:)")
func getUser(id: String) -> User {
// old implementation
}
func fetchUser(withID id: String) -> User {
// replacement
}
Kotlin/Java: @Deprecato con ReplaceWith
Kotlin
@Deprecated(
message = "Use processItems() instead",
replaceWith = ReplaceWith("processItems(items)"),
level = DeprecationLevel.WARNING
)
fun handleItems(items: List<Item>) {
// deprecated
}
fun processItems(items: List<Item>) {
// replacement
}
Perché il codice obsoleto causa problemi reali
Il codice obsoleto non è solo una questione di manutenzione. Crea un rischio concreto e cumulativo su quattro dimensioni:
Vulnerabilità di sicurezza. Le API e le librerie obsolete non ricevono più patch di sicurezza. Una libreria obsoleta con una CVE non corretta rappresenta una vulnerabilità permanente; i manutentori hanno smesso di correggerla perché vogliono che tutti migrino. Le organizzazioni che utilizzano componenti obsoleti utilizzano, per scelta, codice notoriamente vulnerabile.
Interruzione delle dipendenze durante gli aggiornamenti. L'avviso di deprecazione esiste proprio perché la rimozione è imminente. Quando arriva l'aggiornamento principale che rimuove l'API deprecata, tutti i sistemi che ancora dipendono da essa smettono di funzionare simultaneamente, nel peggior momento possibile, durante un aggiornamento che avrebbe dovuto essere di routine.
Aumento della complessità della manutenzione. Il codice obsoleto richiede agli sviluppatori di mantenere contemporaneamente due modelli mentali: cosa fa il vecchio codice e cosa fa il nuovo equivalente. Ogni nuovo membro del team deve imparare quali parti del codice evitare e perché. Questa doppia complessità si accumula con ogni ulteriore componente obsoleto.
Accumulo di debito tecnico. Ogni dipendenza obsoleta rappresenta un'unità di debito tecnico. A differenza di altri tipi di debito, il debito derivante da codice obsoleto ha una scadenza: passa da "avviso" a "rotto" nel momento stesso in cui il componente obsoleto viene effettivamente rimosso.
Come gestire le dipendenze obsolete in un progetto software
Fase 1: Inventario di tutti gli ammortamenti
Eseguite una scansione sistematica anziché individuare i componenti obsoleti uno alla volta. La maggior parte degli strumenti offre metodi per visualizzare l'intero inventario:
bash
# Python: find all DeprecationWarning instances
python -W error::DeprecationWarning -m pytest
# JavaScript/Node.js: run with deprecation tracing
node --trace-deprecation app.js
# Java: compile with full deprecation details
javac -Xlint:deprecation *.java
# npm: find deprecated packages
npm outdated
npm audit
Fase 2: Classificazione in base al rischio
Non tutti gli ammortamenti richiedono un intervento immediato. Classifica ciascuno di essi:
| Priorità | Criteri | Action |
|---|---|---|
| critico | Libreria obsoleta e critica per la sicurezza; vulnerabilità CVE nota; rimozione nella prossima versione principale. | Emigrare immediatamente |
| Alto | Obsoleto nella versione principale corrente; avvisi attivi in CI | Programma per lo sprint corrente o il prossimo |
| Medio | Obsoleto ma ancora supportato per 2 o più versioni principali; nessun rischio per la sicurezza. | Aggiungi al backlog con la cronologia |
| Basso | Annotazione deprecata nel codice interno con bassa frequenza di modifica | Tracciare e affrontare durante il refactoring correlato |
Passaggio 3: Trova tutti gli utilizzi prima della migrazione
Prima di modificare un componente obsoleto, identifica tutti i punti in cui viene utilizzato. Modificarlo senza una mappa completa rischia di non individuare utilizzi che potrebbero causare problemi in modo silenzioso:
python
# Using grep for basic search
grep -r "old_function" src/
# Using ast-grep for code-aware search (TypeScript/JS)
ast-grep --pattern 'getUser($ID)' --lang ts
# Using ripgrep with file type filtering
rg "deprecated_method" --type java
Per codebase di grandi dimensioni, gli strumenti di analisi statica automatizzati producono una mappa completa dei riferimenti incrociati con maggiore precisione rispetto all'utilizzo manuale di grep, soprattutto per gli utilizzi indiretti tramite dispatch dinamico o ereditarietà.
Fase 4: Migrare in modo sistematico
Sostituisci gli usi obsoleti uno alla volta, convalidando ciascuno prima di passare al successivo:
python
# Before: deprecated
import imp
module = imp.load_source('mymodule', '/path/to/mymodule.py')
# After: replacement
import importlib.util
spec = importlib.util.spec_from_file_location('mymodule', '/path/to/mymodule.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
javascript
// Before: deprecated event property
document.addEventListener('keydown', (event) => {
const key = event.keyCode; // deprecated
});
// After: modern replacement
document.addEventListener('keydown', (event) => {
const key = event.key; // current standard
});
Passaggio 5: Aggiungere i gate di deprecazione al CI/CD
Impedire che nuovi utilizzi obsoleti entrino nel codice sorgente dopo la pulizia:
YAML
# .github/workflows/deprecation-check.yml
- name: Check for deprecated API usage (Java)
run: javac -Xlint:deprecation -Werror src/**/*.java
- name: Check for deprecated packages (Node)
run: npm audit --audit-level=moderate
- name: ESLint no-deprecated rule (TypeScript)
run: npx eslint --rule '{"@typescript-eslint/no-deprecated": "error"}' src/
Definizione di una politica di ammortamento
Le organizzazioni che gestiscono bene la deprecazione la considerano una questione di politica aziendale, non solo tecnica. Una politica di deprecazione definisce:
Chi può dichiarare obsoleto un'API? Un singolo sviluppatore non dovrebbe dichiarare unilateralmente obsoleta un'API interna ampiamente utilizzata senza una revisione da parte del team. Le decisioni di deprecazione dovrebbero coinvolgere i responsabili dei componenti che la utilizzano.
Durata del periodo di deprecazione. Un valore predefinito ragionevole: un ciclo di versione principale di preavviso prima della rimozione. Per le API pubbliche, due versioni principali. Per le API interne, un ciclo di rilascio.
Come vengono comunicate le funzionalità deprecate. Annotazioni nel codice, voci nel registro delle modifiche e notifica diretta agli utenti noti. Un avviso di deprecazione presente solo in un commento del codice passerà inosservato.
Cosa si intende per "rimosso"? Il codice viene eliminato? Spostato in un pacchetto opzionale separato? Nascosto dietro un flag di funzionalità? Definire chiaramente lo stato finale.
Modalità di documentazione del percorso migratorio. Ogni annotazione di deprecazione dovrebbe includere un riferimento al sostituto. @deprecated Use fetchUserById() instead è più utile di @deprecated.
Il codice obsoleto funziona ancora?
Sì, finché non smette di funzionare. Il codice obsoleto continua a funzionare normalmente fino alla versione in cui viene effettivamente rimosso. Questa è la caratteristica più pericolosa del codice obsoleto: crea un falso senso di sicurezza. I sistemi che utilizzano API obsolete da anni possono apparire stabili, mentre il rischio di un'improvvisa interruzione del funzionamento aumenta a ogni ciclo di rilascio.
La risposta alla domanda "è sicuro eseguire codice obsoleto?" è: dipende da quanto è vicina la data di rimozione e qual è il livello di sicurezza del componente obsoleto. Una funzione obsoleta in una versione minore di una libreria attivamente mantenuta, senza CVE note, presenta un basso rischio immediato. Una libreria di autenticazione obsoleta con una vulnerabilità non corretta e una data di fine vita annunciata, presenta un alto rischio immediato.
Come SMART TS XL Identifica il codice obsoleto nei sistemi aziendali
In un progetto monolingue, trovare il codice obsoleto si riduce all'utilizzo del flag del compilatore o della regola di analisi sintattica appropriati. In un ambiente aziendale che comprende COBOL, JCL, Java, Python e servizi moderni, è necessario individuare simultaneamente i componenti obsoleti di ciascun linguaggio, e le relazioni tra di essi sono importanti quanto le deprecazioni stesse.
SMART TS XL'S analisi statica del codice analizza ogni linguaggio nell'ambiente e individua contemporaneamente annotazioni deprecate, utilizzi API obsoleti e modelli di codice morto nell'intera codebase. Quando un copybook COBOL viene contrassegnato come obsoleto, SMART TS XL Identifica ogni programma che lo include. Quando un metodo dell'API Java viene deprecato, traccia ogni punto di chiamata in ogni servizio del portfolio.
La funzionalità di analisi dell'impatto fa un ulteriore passo avanti: prima di rimuovere qualsiasi componente obsoleto, genera un'analisi completa di ciò che tale rimozione influirà, specificando quali programmi, flussi di lavoro e servizi a valle saranno interessati, per ogni linguaggio di programmazione. In questo modo, la rischiosa domanda "cosa si romperà?" viene trasformata in un elenco strutturato e dettagliato di tutto ciò che deve essere validato prima di procedere con la rimozione.
La funzionalità di ricerca aziendale rende l'inventario interrogabile: trova ogni utilizzo di una specifica funzione obsoleta, ogni riferimento a un copybook obsoleto, ogni chiamata a un'API obsoleta, in pochi secondi, attraverso milioni di righe di codice in diversi linguaggi. Per i programmi di modernizzazione dei sistemi legacy, in cui l'inventario dei componenti obsoleti è il punto di partenza per determinare l'ambito della migrazione, questa funzionalità di ricerca sostituisce settimane di audit manuale con una query mirata.