Un gestionale scritto su misura in PHP è spesso il sistema più importante di un’azienda e anche quello meno documentato. Gestisce ordini, magazzino, fatture, rapporti con i clienti; è stato sviluppato in anni diversi da persone diverse, gira su una versione di PHP fuori supporto da tempo e nessuno sa dire con precisione quanto costerebbe portarlo su PHP 8. Quando arriva il momento di chiedere un preventivo, le cifre ricevute possono differire di molto tra un fornitore e l’altro, e nessuna delle due parti sa davvero spiegare perché.
In questo articolo non diamo cifre, perché qualunque numero senza l’analisi del codice sarebbe inventato. Spieghiamo invece quali fattori determinano tempi e costi, come si misurano, quale metodo di stima usiamo per esprimere l’incertezza in modo onesto e quali rischi fanno saltare più spesso i preventivi. Alla fine trovi le domande con cui leggere una proposta, la nostra o quella di un altro fornitore.
Perché le stime a occhio falliscono
La stima più comune nasce così: si guarda il numero di file o di righe, lo si confronta con un progetto simile e si applica un coefficiente. Funziona male per due motivi. Il primo è che la quantità di codice dice poco sul lavoro da fare: diecimila righe scritte con PDO e classi ordinate migrano in fretta, mille righe che usano mysql_* in ogni pagina e concatenano query a mano richiedono molto più tempo. Il secondo è che una parte importante del lavoro non sta nel codice: sta nelle integrazioni, nei dati e nelle regole che solo chi usa il gestionale conosce.
Una stima utile deve quindi separare ciò che si può misurare da ciò che si può solo scoprire, e dichiarare l’incertezza invece di nasconderla in un numero unico.
I fattori che contano
Quello che si misura sul codice
- Distanza tra le versioni. Da PHP 7.4 a PHP 8 cambiano soprattutto il comportamento di alcune funzioni, i confronti tra stringhe e numeri e la gestione degli errori. Da PHP 5.x il salto comprende anche la rimozione delle estensioni
mysqlederegin PHP 7.0, e quella dieach()ecreate_function()in PHP 8.0. - Densità dei problemi. Conta quante occorrenze ci sono e soprattutto quanto sono sparse: una funzione deprecata chiamata in un solo punto si corregge una volta, la stessa funzione copiata in duecento pagine richiede duecento correzioni e duecento verifiche.
- Librerie ed estensioni. Ogni libreria inclusa a mano va identificata, confrontata con l’originale e aggiornata o sostituita. Lo stesso vale per estensioni PHP non più disponibili.
- Struttura. Logica, HTML e query mescolati nello stesso file rendono più costose sia le correzioni sia i test.
Quello che si scopre con le persone
- Regole di business non documentate: arrotondamenti, sconti particolari, eccezioni per singoli clienti, calcoli che “funzionano così da sempre”.
- Integrazioni: scambi di file con banche e corrieri, invio delle fatture elettroniche, sincronizzazioni con un e-commerce, script eseguiti da cron di cui nessuno ricorda l’esistenza.
- Dati: tabelle in latin1 mescolate a tabelle in utf8, date salvate come testo, query che funzionano solo con modalità SQL permissive. Da MySQL 5.7 la modalità predefinita è più rigorosa e include
ONLY_FULL_GROUP_BY, quindi spesso la migrazione di PHP coincide con quella del database. - Test e collaudo: chi può verificare che il gestionale si comporti come prima, con quali dati e in quanto tempo.
Misurare prima di stimare
La prima fase di ogni nostro progetto di migrazione è un’analisi del codice reale, con numeri ricavati dagli strumenti. Qualche comando di esempio, da lanciare su una copia del codice:
# Quanti file PHP e quante righe, escluse le librerie di terze parti
find . -name '*.php' -not -path './vendor/*' | wc -l
find . -name '*.php' -not -path './vendor/*' -print0 | xargs -0 cat | wc -l
# In quanti file compaiono funzioni rimosse in PHP 7.0 e 8.0
grep -rlE '\bmysql_[a-z_]+\(' --include='*.php' . | wc -l
grep -rlE '\b(ereg|eregi|split)\(' --include='*.php' . | wc -l
grep -rlE '\b(each|create_function)\(' --include='*.php' . | wc -l
# Analisi di compatibilità con PHPCompatibility (dalla 8.0 in poi);
# la copertura delle versioni più recenti dipende dalla versione installata
vendor/bin/phpcs -p --extensions=php --standard=PHPCompatibility \
--runtime-set testVersion 8.0- --report=summary .
Il report riassuntivo dice quanti errori e avvisi ci sono e in quali file si concentrano. Integrato con PHPStan e con una prova di Rector su una parte del codice, permette di separare le correzioni automatizzabili da quelle manuali. Abbiamo descritto gli strumenti nell’articolo su analisi statica con PHPCompatibility, PHPStan e Rector.
Accanto all’analisi del codice servono un inventario delle integrazioni (cosa entra, cosa esce, con quale formato e con quale frequenza), una verifica del database e qualche intervista con chi usa il gestionale ogni giorno. Sono loro a sapere quali funzioni sono critiche e quali non vengono aperte da anni.
Il metodo: stima a tre punti per fase
Per esprimere l’incertezza usiamo una tecnica nota e semplice, la stima a tre punti. Per ogni fase del lavoro si indicano tre valori: ottimistico (O), se tutto va come previsto; più probabile (M); pessimistico (P), se si verificano i problemi ragionevolmente prevedibili. La stima della fase si calcola come media pesata (O + 4M + P) / 6, e la differenza tra P e O dice quanto quella fase è incerta.
Le fasi tipiche di una migrazione di un gestionale custom sono queste:
- analisi e inventario: codice, integrazioni, dati, ambienti;
- adeguamento automatico: le correzioni che strumenti come Rector applicano in modo meccanico, da rivedere comunque;
- correzioni manuali: logica, librerie da sostituire, accesso al database;
- test e collaudo: test automatici sui flussi critici e verifica da parte degli utenti;
- dati e rilascio: conversioni del database, configurazione del server, passaggio in produzione e periodo di stabilizzazione.
Nell’esempio, costruito con valori di fantasia, le correzioni manuali e il collaudo hanno gli intervalli più ampi. È quello che succede quasi sempre: sono le fasi in cui pesano le regole non documentate e le integrazioni. Il valore della stima a tre punti sta proprio qui. Mostra al committente dove si trova il rischio e indica dove conviene investire in analisi prima di firmare: ogni ora spesa a chiarire un’integrazione riduce l’intervallo della fase di correzione.
Il costo si ricava moltiplicando le stime per la tariffa, ma con un avvertimento: la somma delle stime pesate è un valore centrale e può essere superata. Un preventivo serio indica come vengono gestiti gli scostamenti, per esempio con una quota a corpo per le fasi ben misurate e una a consumo, con un limite concordato, per quelle incerte.
I rischi che fanno saltare i preventivi
Alcuni problemi ricorrono così spesso che vanno cercati esplicitamente in fase di analisi:
- codice morto e codice vivo confusi: si spende tempo a migrare pagine che nessuno usa, oppure si trascura uno script richiamato una volta l’anno per la chiusura di bilancio;
- librerie modificate localmente: aggiornare un generatore di PDF o un client di posta cancella correzioni fatte anni fa e mai documentate;
- comportamenti che cambiano senza errori: in PHP 8 il confronto tra un numero e una stringa non numerica dà un risultato diverso rispetto a PHP 7, e il codice continua a girare producendo esiti diversi;
- dati e codifiche: caratteri accentati che si corrompono nella conversione, date non valide rifiutate dalle modalità SQL rigorose;
- ambiente: percorsi assoluti, configurazioni di
php.inidate per scontate, invio di posta tramite il server locale; - collaudo sottodimensionato: se gli utenti non hanno tempo di verificare, i problemi emergono in produzione, quando costano di più.
Come ridurre l’incertezza prima di firmare
Il modo più efficace per ridurre l’intervallo di una stima è comprare informazioni prima di comprare il lavoro. In pratica:
- un’analisi iniziale a sé stante, con un risultato concreto (report, elenco dei problemi, stima per fase) utilizzabile anche con un altro fornitore;
- una migrazione pilota su un modulo rappresentativo, che misura la velocità reale e fa emergere i problemi tipici del progetto;
- test di caratterizzazione sui flussi critici prima delle modifiche, così che il collaudo diventi in parte automatico;
- una migrazione per moduli, quando l’architettura lo permette, invece di un unico passaggio finale.
Se il gestionale è esposto e la migrazione richiede mesi, nel frattempo va protetta la produzione. Il backport delle patch di sicurezza sul ramo di PHP in uso copre questo intervallo senza toccare l’applicazione; ne confrontiamo costi e tempi nell’articolo backport o migrazione.
Cosa deve contenere un preventivo
Un preventivo di migrazione va giudicato anche da come tratta l’incertezza. Prima di confrontare due proposte, verifica che entrambe rispondano a queste domande:
- su quale analisi si basa la stima, e se l’analisi è stata fatta sul codice reale;
- quale versione di PHP e di database sarà il punto di arrivo, e su quale sistema operativo;
- cosa è incluso e cosa è escluso: librerie da sostituire, conversione dei dati, nuove funzioni;
- quali ipotesi sono state fatte su integrazioni e collaudo, e cosa succede se si rivelano false;
- come vengono gestiti gli scostamenti e chi li approva;
- quali test vengono consegnati insieme al codice migrato;
- come si torna indietro se il rilascio in produzione non va a buon fine.
Una proposta che dà un prezzo fisso senza aver visto il codice sta scaricando il rischio da qualche parte: in esclusioni scritte in piccolo, in un collaudo ridotto o in una qualità più bassa del previsto.
Conclusioni
Tempi e costi della migrazione di un gestionale custom su PHP vecchio dipendono da due gruppi di fattori. Quelli misurabili sul codice, cioè distanza tra le versioni, densità delle funzioni rimosse, librerie e struttura, determinano la dimensione del lavoro. Quelli che si scoprono con le persone, cioè regole non documentate, integrazioni, dati e collaudo, determinano l’incertezza. Una stima affidabile parte da un’analisi del codice reale con strumenti come PHPCompatibility, esprime ogni fase con tre valori e rende visibile dove si concentra il rischio. Un’analisi iniziale, un modulo pilota e i test di caratterizzazione riducono l’incertezza prima di firmare, mentre il backport delle patch protegge la produzione durante i lavori. Se vuoi partire dall’analisi del tuo gestionale, scrivici.