Punti chiave:
L’articolo evidenzia che il refactoring di un’applicazione industriale è opportuno quando il costo e l’incertezza dei piccoli cambiamenti crescono più rapidamente del loro valore per l’azienda. È fondamentale distinguere il riordino della struttura da una modifica tecnica che incide sul processo o sulla sicurezza.
- Il refactoring di una vecchia applicazione riguarda la continuità della produzione, i costi e le responsabilità, non soltanto la qualità del codice.
- Il rischio aumenta quando la modifica incide sui segnali, sugli stati, sulla sequenza delle operazioni o sulle condizioni di transizione del processo.
- Modifiche apparentemente tecniche possono cambiare l’avvio, l’arresto, il reset degli errori, la reazione alla mancanza di alimentazione e la perdita di comunicazione.
- Se occorre riconfermare le sequenze o le reazioni dei circuiti di protezione, non si tratta più di semplice manutenzione del codice.
- Una rifattorizzazione sicura richiede la definizione dei limiti dell’intervento, dei criteri di accettazione e della valutazione dei rischi del processo.
Perché questo tema è oggi rilevante
Il refactoring di una vecchia applicazione industriale non è più una questione di estetica del codice o di comodità della manutenzione. Oggi è una decisione che riguarda la continuità produttiva, la prevedibilità dei costi e l’estensione delle responsabilità in capo al proprietario del sistema. In molti stabilimenti, le applicazioni di controllo, gli strumenti per gli operatori e i livelli di comunicazione sono stati sviluppati nel corso degli anni senza un’unica architettura coerente, spesso intorno a dispositivi, librerie e meccanismi di integrazione il cui supporto è limitato o già terminato. Una situazione del genere può essere tollerata per un certo periodo, ma solo fino al momento in cui ogni modifica successiva inizia a costare più della funzionalità stessa che dovrebbe introdurre. A quel punto la domanda non è più se intervenire sulla vecchia applicazione, ma se l’organizzazione ne controlli ancora il comportamento nelle reali condizioni di produzione.
L’importanza del tema deriva dal fatto che, nei sistemi industriali, il debito tecnologico si trasforma molto rapidamente in debito operativo. Se l’applicazione è difficile da riprodurre, dipende da singole persone, non dispone di test di regressione affidabili oppure la sua logica mescola funzioni produttive con funzioni legate alla sicurezza e alla diagnostica, ogni incidente avrà un costo superiore rispetto a un problema analogo in un sistema d’ufficio. La conseguenza non è soltanto il fermo impianto. Si aggiungono il costo del lavoro della manutenzione, il rischio di soluzioni provvisorie errate adottate sotto pressione, la difficoltà di dimostrare la dovuta diligenza dopo la modifica e il problema di distinguere ciò che era un guasto preesistente da ciò che è invece conseguenza dell’intervento del team di progetto. Per il manager e il proprietario del prodotto il criterio pratico è semplice: se il tempo e l’incertezza necessari per introdurre ulteriori piccole modifiche crescono più rapidamente del loro valore per il business, l’applicazione è entrata in una fase in cui la decisione di refactoring va presa consapevolmente, e non rinviata fino al primo guasto critico.
Gli errori più frequenti si verificano quando il refactoring viene trattato come una modernizzazione “senza impatto sul processo”, mentre in realtà modifica il modo in cui il sistema prende decisioni. Nella pratica basta un intervento apparentemente modesto: la sostituzione di un componente di comunicazione, la riorganizzazione della pianificazione dei task, la modifica della logica di buffering dei dati dei sensori oppure il riordino della sequenza di avvio dopo un riavvio. Sulla carta sono interventi tecnici di riassetto. In reparto, però, possono cambiare il momento di emissione di un segnale, l’ordine di rilascio degli interblocchi, la reazione alla perdita di comunicazione o il comportamento dell’applicazione dopo un’interruzione di alimentazione. È proprio qui che il tema del refactoring si collega alla valutazione del rischio della modifica: non si tratta di stabilire se il codice sia “migliore”, ma se dopo la modifica la macchina, la linea o la postazione continuino a comportarsi in modo prevedibile in condizioni normali, in presenza di anomalie e dopo il riavvio.
Un buon test della maturità della decisione consiste nel verificare se il team è in grado di tracciare il confine tra una modifica della struttura interna dell’applicazione e una modifica di una funzione rilevante per il processo o per la sicurezza. Se questo confine non può essere descritto a livello di segnali, stati e condizioni di transizione, il progetto è esposto a rischio indipendentemente dalla qualità dell’esecutore. In ambiente industriale sono particolarmente sensibili le situazioni in cui l’applicazione partecipa alla sequenza di avvio, arresto, reset dei guasti, conferma degli allarmi oppure interagisce con i sistemi di sezionamento dell’energia e con gli interblocchi. In questo momento non si pone più soltanto una questione di architettura software, ma anche di protezione contro l’avviamento inatteso e del fatto che l’analisi comprenda anche l’impianto elettrico, la logica di controllo e le dipendenze tra i dispositivi. È proprio questo il punto in cui un refactoring apparentemente locale smette di essere un compito informatico e diventa una modifica tecnica che richiede un processo decisionale completo.
Il richiamo ai requisiti normativi assume rilievo solo a questo livello, perché le norme non sostituiscono la decisione progettuale, ma ne organizzano il perimetro. Se la modifica può influire sulle condizioni di avvio, arresto, ripristino del funzionamento dopo un’anomalia oppure sulle misure di protezione, deve essere valutata come una modifica del rischio, non come semplice manutenzione del codice. Se l’intervento riguarda la logica che interagisce con il sezionamento dell’energia, con gli interblocchi o con la sequenza di accesso sicuro, si apre naturalmente anche l’ambito dei requisiti relativi alla protezione contro l’avviamento inatteso. Dal punto di vista della responsabilità, quindi, la questione principale non è tanto “se fare refactoring”, ma se l’organizzazione sia in grado di dimostrare di conoscere i limiti della modifica, di avere criteri di accettazione basati sul comportamento del processo e di saper distinguere tra il riordino del sistema e una modifica che richiede una valutazione completa del rischio, oltre al coordinamento con la progettazione dell’impianto e con le prove sul campo.
Dove più spesso aumentano costi o rischi
L’aumento maggiore dei costi nel refactoring di una vecchia applicazione industriale raramente dipende dal solo codice. Di norma il problema nasce da una classificazione errata della modifica: il team la considera un riordino della struttura del programma, mentre in realtà cambia il comportamento del sistema nel tempo, la sequenza delle operazioni oppure le condizioni di transizione tra stati. In ambiente produttivo, un errore di questo tipo ha conseguenze dirette sul progetto. Il cronoprogramma non corrisponde più alla reale portata dell’intervento, i test vengono pianificati sulla funzionalità informatica e non sull’andamento del processo, e la responsabilità del risultato si disperde tra manutenzione, automazione e fornitore del software. Il criterio pratico, in questo caso, è semplice: se dopo la modifica occorre confermare nuovamente la sequenza di avvio, arresto, ripresa del lavoro dopo un’anomalia oppure la reazione ai segnali provenienti dai circuiti di protezione, allora non si tratta più di un “refactoring sicuro” in senso organizzativo, ma di una modifica che può generare rischi per la produzione e richiedere un diverso iter di approvazione.
Un secondo ambito tipico in cui i costi crescono è la decisione progettuale presa senza un quadro completo delle dipendenze. Le vecchie applicazioni industriali sono spesso intrecciate con la configurazione del controllore, degli attuatori, della visualizzazione, dell’archiviazione dei dati e delle procedure operative. Nella documentazione tutto questo appare come un unico sistema, ma nella pratica si tratta di livelli sviluppati nel corso degli anni da team diversi. Un refactoring pensato per migliorare la leggibilità del codice o facilitarne la futura manutenzione può modificare senza che ce se ne accorga il significato dei ritardi, delle condizioni di blocco, dei valori predefiniti dopo il riavvio oppure delle modalità di gestione di un errore di comunicazione. La conseguenza non è soltanto una correzione tecnica, ma anche il costo dei fermi impianto, di prove aggiuntive sul campo e di discussioni sul fatto che il difetto esistesse già prima oppure sia stato introdotto dalla modifica. Per questo, prima di decidere, conviene valutare non tanto la dimensione dell’intervento quanto il numero e la criticità dei punti di interfaccia: quanti segnali, ricette, modalità operative e soluzioni tampone di esercizio dipendono dalla porzione di codice destinata alla revisione. Quanto più numerosi sono questi punti, tanto meno ha senso un refactoring fatto “già che ci siamo” nell’ambito di un altro incarico.
Nella pratica, i progetti particolarmente costosi sono quelli in cui il team scopre i requisiti reali solo durante la messa in servizio. Un esempio tipico è la revisione di un modulo sequenziale che, secondo la descrizione, “fa la stessa cosa, solo in modo più pulito”. Dopo l’implementazione, però, emerge che la versione precedente conteneva comportamenti non documentati che compensavano le imperfezioni dell’impianto: un breve mantenimento del segnale, una tolleranza rispetto al ritardo di un sensore, una specifica sequenza di reset dell’allarme oppure una condizione da cui dipende la possibilità di accesso per il servizio. Nel codice tutto questo poteva sembrare un errore o debito tecnico, ma per il processo era un elemento di stabilizzazione. Se il refactoring elimina questi meccanismi senza averne compreso la funzione, il costo si manifesta immediatamente: aumenta il numero di interventi dopo l’avviamento, si allungano i tempi di accettazione e diventa necessario ricostruire la logica sotto la pressione dell’operatività dell’impianto. Per questo la convenienza del refactoring va valutata anche in base alla possibilità di ricostruire il comportamento del sistema attuale. Se l’organizzazione non dispone di un registro eventi, di descrizioni affidabili delle modalità operative e di scenari di prova basati sul processo reale, occorre prima costruire una base di valutazione e solo dopo prendere una decisione sulla revisione.
Questo tema porta direttamente alla valutazione pratica del rischio delle modifiche quando l’intervento influisce sulle funzioni di protezione, sulle sequenze di accesso in sicurezza, sul comando del movimento degli attuatori oppure sul comportamento dell’impianto in caso di mancanza e ritorno dell’alimentazione. In questo ambito il costo dell’errore non si limita alle correzioni software, perché entra in gioco anche la responsabilità dell’autorizzazione alla messa in esercizio della modifica. Se l’applicazione interagisce con sistemi idraulici, pneumatici o con soluzioni come il comando a due mani, il confine tra refactoring e modifica tecnica diventa ancora più sottile e richiede di verificare che i presupposti progettuali delle misure di protezione non siano stati compromessi. Proprio qui è opportuno richiamare metodi strutturati di valutazione del rischio, compreso l’approccio applicato nella pratica sulla base di ISO/TR 14121-2 e, per i sistemi idraulici, anche i requisiti progettuali organizzati da UNI EN ISO 4413. Non si tratta di formalismo fine a sé stesso, ma di una semplice regola decisionale: se la modifica può incidere sulla sicurezza del processo o dell’operatore, il suo costo va calcolato insieme alla validazione, alle prove sul campo e al regime di responsabilità, e non esclusivamente in base al tempo di lavoro del programmatore.
Come affrontare il tema nella pratica
In pratica, la convenienza di refattorizzare una vecchia applicazione industriale non si valuta in base all’attrattiva tecnologica del cambiamento, ma in funzione della possibilità di ridurre al tempo stesso il rischio operativo e mantenere il controllo sull’implementazione. Per il manager e il product owner questo significa un semplice cambio di prospettiva: la domanda non è se “valga la pena riordinare” il codice, ma se lo stato attuale dell’applicazione ostacoli concretamente la manutenzione, i test, la correzione dei guasti oppure l’introduzione di ulteriori modifiche in modo conforme ai requisiti. Se la risposta è sì, il refactoring ha senso, ma solo entro un perimetro che possa essere separato dall’attività produttiva e valutato sulla base di effetti misurabili. Un buon criterio decisionale consiste nel confrontare due costi: il costo di lasciare l’applicazione nello stato attuale, comprendente fermi, tempi di diagnosi, dipendenza da singole persone e rischio di modifiche errate, e il costo di una ristrutturazione controllata con test, validazione e messa in servizio. Senza questo confronto, il progetto tende di solito a sfuggire al controllo, perché il team finanzia il riordino del codice con il budget destinato alle funzionalità, mentre la responsabilità per gli effetti sull’impianto resta indefinita.
Per questo la prima decisione non dovrebbe essere “riscriviamo” oppure “lasciamo così”, ma definire il confine della modifica. In un approccio maturo si separa la parte che riguarda esclusivamente la struttura del software da quella che incide sulla logica di processo, sulle sequenze di avviamento e arresto, sui modi operativi, sulla comunicazione con gli azionamenti e sul comportamento dopo un’interruzione dell’alimentazione. Questa distinzione ha conseguenze dirette sia sui costi sia sull’organizzazione. Una modifica limitata al livello di riordino del codice può essere gestita con un ciclo più breve e con un coinvolgimento minore del servizio di manutenzione. Una modifica che altera il comportamento della macchina o della linea richiede invece un piano di test sull’impianto, una finestra di intervento, una procedura di rollback e l’indicazione univoca di chi approva il rilascio all’esercizio. Conviene inoltre misurare non solo il tempo necessario per le attività di sviluppo, ma anche il tempo di ripristino del sistema dopo un tentativo non riuscito, il numero di aree coperte dai test di regressione e il tempo necessario per diagnosticare uno scostamento dopo l’avviamento. Sono questi gli indicatori che mostrano se il refactoring riduce davvero il rischio di progetto, e non soltanto migliora il comfort di lavoro del team di sviluppo.
Un esempio pratico tipico delle applicazioni di controllo meno recenti è il seguente: il codice contiene numerosi frammenti duplicati responsabili degli interblocchi di movimento, della gestione degli allarmi e delle transizioni tra modo manuale e automatico. Il team vuole uniformarli, perché l’assetto attuale rende più difficile lo sviluppo e genera discrepanze tra le postazioni. Una decisione del genere ha senso solo dopo aver verificato che l’uniformazione non modifichi le condizioni in cui un attuatore riceve il consenso al movimento e che, dopo il riavvio del controllore, non compaia una diversa sequenza di ripristino dello stato. Se l’applicazione controlla anche valvole, azionamenti o sistemi con energia accumulata, anche un refactoring apparentemente “interno” può rientrare nell’ambito della valutazione del rischio della modifica secondo ISO 12100 e richiedere un’analisi della protezione contro l’avviamento inatteso. In questo caso, una prassi ragionevole consiste nell’eseguire il refactoring per fasi: prima riprodurre il comportamento nell’ambiente di test, poi separare i moduli senza modificare la logica, quindi verificare sull’impianto con uno scenario di rollback già predisposto. Questo limita la responsabilità operativa e consente di interrompere l’implementazione prima che il problema si ripercuota sulla produzione.
Solo a questo punto serve un riferimento normativo, perché le norme non sostituiscono la decisione tecnica, ma aiutano a definire il momento in cui la modifica cessa di essere un’attività puramente software. Se il refactoring influisce sulle misure di protezione, sulle condizioni di accesso in sicurezza, sul sezionamento dell’energia oppure sul comportamento dei sistemi dopo l’arresto e il riavvio, rientra naturalmente nel campo di una valutazione pratica e strutturata del rischio della modifica, condotta anche con il supporto dell’approccio noto da ISO/TR 14121-2. Quando emerge il rischio di avviamento inatteso, occorre verificare non solo il codice in sé, ma anche la logica di sezionamento e di ripristino dell’energia, il che porta direttamente ai temi associati a ISO 14118. Se invece l’applicazione è collegata a sistemi idraulici o pneumatici, la valutazione non può trascurare i presupposti progettuali di tali sistemi, perché una sequenza di comando errata può comprometterne il funzionamento sicuro indipendentemente dalla correttezza del programma stesso; in tal caso diventa giustificato fare riferimento anche ai requisiti che disciplinano la progettazione dei sistemi idraulici. In pratica questo significa una cosa sola: a decidere l’estensione del refactoring non è l’eleganza della soluzione, ma il limite della responsabilità per il comportamento sicuro dell’impianto dopo la modifica.
A cosa prestare attenzione durante l’implementazione
L’implementazione del refactoring di una vecchia applicazione industriale è il momento in cui anche una decisione architetturale corretta può trasformarsi in un problema operativo. Il senso dell’intera iniziativa finisce nel punto in cui la modifica migliora il codice, ma peggiora la prevedibilità del funzionamento dell’impianto oppure estende la responsabilità del team oltre quanto è stato identificato e approvato. L’errore più frequente consiste nel trattare l’implementazione come una normale pubblicazione di una nuova versione. In ambiente produttivo conta non solo che l’applicazione funzioni, ma anche che dopo la modifica tutti gli stati transitori si comportino in modo identico: avviamento dopo mancanza di alimentazione, riavvio della comunicazione, ripristino delle ricette, gestione di allarmi, interblocchi e modi manuali. Il criterio pratico è semplice: se il team non è in grado di descrivere in modo univoco quali comportamenti devono rimanere invariati dopo l’implementazione, significa che non esistono ancora le condizioni per una messa in servizio sicura.
Nella fase decisionale che precede l’implementazione occorre distinguere tra una modifica tecnicamente reversibile e una modifica che, una volta messa in esercizio, crea un nuovo stato di riferimento e rende più difficile il ritorno alla situazione precedente. Questo ha effetti diretti sui costi e sulla pianificazione. Un refactoring che richiede l’aggiornamento simultaneo di controllori, visualizzazione, server dati e interfacce verso i sistemi di livello superiore non è più un singolo intervento di programmazione; diventa una modifica coordinata del processo produttivo con molteplici punti di possibile guasto. Per questo, prima dell’implementazione, conviene adottare un criterio di accettazione basato non sulla dichiarazione “i test sono stati superati”, ma sulla capacità di ritirare la modifica in modo controllato entro un tempo accettabile per il processo. Se non esiste una procedura di ripristino credibile, non ci sono nemmeno basi per affermare che il rischio sia sotto controllo. In pratica, è utile misurare non un’astratta “qualità dell’implementazione”, ma indicatori come il tempo necessario per ripristinare la versione precedente, il numero di interfacce dipendenti dalla modifica e il numero di funzioni la cui correttezza può essere confermata sull’impianto senza intervenire sulla produzione.
Un buon esempio è la situazione in cui il refactoring riordina la gestione delle eccezioni e dei messaggi di errore, ma allo stesso tempo modifica la sequenza di inizializzazione dopo il riavvio del sistema. Sul banco di prova tutto appare corretto, perché i dispositivi sono immediatamente disponibili e il processo non lavora sotto carico. In stabilimento, però, lo stesso codice può avviare la sequenza in un momento diverso rispetto a prima, con conseguente perdita di sincronizzazione con gli azionamenti, interpretazione errata dei segnali di pronto oppure arresto di un lotto di materiale in uno stato intermedio. Un episodio del genere non deve necessariamente significare un guasto in senso tecnico, ma genera costi di fermo, scarti, nuovo avviamento e un’ulteriore responsabilità nella decisione di riprendere il lavoro. È proprio qui che il tema del refactoring si trasforma in una valutazione pratica del rischio delle modifiche: non quando la modifica è grande, ma quando i suoi effetti non possono più essere confinati al solo livello software.
Il confine della responsabilità diventa ancora più netto quando l’applicazione influisce sulle funzioni di protezione, sulla logica di abilitazione del movimento, sulle sequenze di scarico, sull’arresto e sul riavvio dopo un’anomalia. In questi casi non basta più confrontare le versioni del codice né eseguire un test funzionale da parte dell’integratore. Serve una valutazione strutturata per verificare se la modifica cambia il livello di rischio e se non compromette i presupposti di funzionamento sicuro della macchina o dell’impianto. Questo è il momento naturale per entrare nell’ambito della valutazione del rischio secondo ISO 12100 e delle pratiche applicate alla valutazione del rischio delle modifiche, mentre nei casi più complessi può risultare utile l’approccio metodologico noto da ISO/TR 14121-2. Se l’applicazione controlla sistemi idraulici o pneumatici, occorre inoltre verificare che la nuova logica non modifichi le condizioni di controllo sicuro dell’energia e la sequenza dei movimenti; in tal caso assumono rilievo anche i requisiti di progetto propri di questi sistemi, e non solo la correttezza del programma in sé. Per il team di progetto questo significa una cosa sola: l’implementazione può considerarsi preparata solo quando l’ambito delle responsabilità tecniche, operative e di conformità è stato definito prima della messa in servizio, e non soltanto dopo il primo incidente.
Refactoring di una vecchia applicazione industriale: quando conviene e come realizzarlo senza rischi per la produzione?
Ha senso quando il costo e l’incertezza legati all’implementazione di piccole modifiche crescono più rapidamente del loro valore per l’azienda. È il segnale che il debito tecnologico sta iniziando a incidere sulla continuità della produzione e sui costi operativi.
Quando la modifica incide su segnali, stati, condizioni di transizione oppure sulle sequenze di avvio, arresto e ripresa del funzionamento. In tal caso non si tratta più soltanto di una questione di architettura, ma di una modifica tecnica che richiede una valutazione dei rischi.
Soprattutto nei casi in cui il comportamento del sistema varia nel tempo: pianificazione dei compiti, sequenza delle operazioni, logica di buffering, reazione in caso di perdita della connessione o di interruzione dell’alimentazione. Anche un intervento minimo può allora modificare la prevedibilità del funzionamento della macchina o della linea.
Occorre definire con chiarezza il confine tra una modifica della struttura dell’applicazione e una modifica di una funzione rilevante per il processo o per la sicurezza. I criteri di accettazione dovrebbero basarsi sul comportamento del processo e i test dovrebbero comprendere anche le condizioni di funzionamento normale, di anomalia e di riavvio.
Quando l’intervento riguarda la logica relativa all’avvio, all’arresto, al reset degli errori, agli interblocchi, al sezionamento dell’energia oppure all’accesso in sicurezza. In questi casi, la modifica va considerata una modifica del rischio, non un semplice intervento di manutenzione del codice.