Programmatore PHP senior freelance: cosa distingue davvero un senior da uno sviluppatore generico in una PMI italiana
Nell'aprile del 2024 mi ha contattò il CTO di una PMI italiana che sviluppa una piattaforma SaaS di gestione della fatturazione elettronica per commercialisti, con circa 15.000 professionisti attivi sulla piattaforma e picchi di utilizzo concentrati nei giorni di scadenza fiscale. Lo stack era moderno sulla carta - Laravel 10, PHP 8.2, MySQL 8.0 con repliche di lettura, Redis 7 per cache e sessioni, tutto containerizzato con Docker Compose su un server dedicato Hetzner AX52 - ma la piattaforma stava diventando inaffidabile proprio nei momenti in cui doveva funzionare meglio. L'endpoint API che generava lotti di 200 fatture elettroniche in formato XML conforme al tracciato del Sistema di Interscambio impiegava 8 secondi di risposta in condizioni normali, e saliva a 40-45 secondi nelle giornate del 15 e del 30 del mese quando tutti i commercialisti italiani spingono le fatture dei loro clienti in contemporanea.
Il CTO mi ha raccontato che nei tre mesi precedenti al suo contatto avevano ingaggiato due "programmatori PHP senior" freelance che avevano letteralmente fatto peggio. Il primo aveva passato due settimane a riscrivere il sistema di routing di Laravel con un'implementazione custom "più veloce", senza spostare di un millisecondo il tempo dell'endpoint incriminato. Il secondo aveva convinto il cliente a migrare da MySQL a PostgreSQL con l'argomento che "PostgreSQL è più performante", spendendo sei settimane di lavoro e introducendo tre bug di business logic nel ricalcolo dell'IVA sugli arrotondamenti - tempo dell'endpoint dopo la migrazione: invariato. Quando mi hanno chiamato, il cliente era alla terza iterazione, aveva già bruciato quarantacinquemila euro di consulenze e stava per commissionare un upgrade hardware dell'AX52 a un server di fascia superiore per "prendere tempo" in attesa della scadenza fiscale successiva.
Cinque giornate di lavoro dopo, distribuite su due settimane perché il cliente voleva fare deploy controllati, l'endpoint era a 280 millisecondi di mediana e 1.200 millisecondi al 99° percentile, con il 99,7% delle richieste sotto i due secondi anche durante il picco del 15 marzo. Stesso hardware. Nessun cambio di database. Nessun framework riscritto da zero. Nessuno dei precedenti interventi aveva affrontato il problema reale - ed è esattamente nel riconoscere qual è il problema reale che si misura la differenza tra un programmatore PHP senior vero e uno che ha vent'anni di esperienza accumulati facendo le stesse cose junior di sempre.
Cosa significa davvero "senior" quando parliamo di un programmatore PHP freelance, al di là del CV?
Un programmatore PHP senior freelance non è definito dagli anni di esperienza dichiarati nel curriculum, ma da un insieme molto specifico di capacità operative che si manifestano nei primi tre giorni di lavoro su un progetto reale. La definizione concreta che uso con i miei clienti PMI è questa: un senior vero sa rispondere alla domanda qual è il collo di bottiglia reale e perché non è dove sembra prima ancora di aprire l'editor, e sa distinguere tra interventi che producono valore misurabile e interventi che sembrano lavoro ma spostano zero metriche. Tutto il resto - la conoscenza dei design pattern, l'esperienza con framework specifici, la capacità di scrivere codice elegante - è condizione necessaria ma non sufficiente. Uno sviluppatore può avere scritto centinaia di migliaia di righe di Laravel in quindici anni e comportarsi comunque da junior strutturale, perché il tratto distintivo del senior non è quanto codice ha scritto, ma quanto codice è stato capace di non scrivere quando la situazione lo richiedeva.
Ci sono quattro segnali operativi che trovo sempre presenti nei veri senior e sempre assenti negli sviluppatori che ne usano solo il titolo. Il primo è la disciplina di profilare prima di ipotizzare. Il secondo è la capacità di leggere il debito tecnico di una codebase legacy e classificarlo per impatto di business, non per eleganza teorica. Il terzo è il coraggio di consigliare al cliente di non fare un refactor massivo quando il costo supera il beneficio misurabile. Il quarto è la capacità di subentrare su una codebase senza documentazione e produrre valore entro la prima settimana, invece di chiedere "documentazione completa prima di iniziare" come se esistesse davvero nelle PMI italiane.
Nei prossimi paragrafi ti racconto ciascuno di questi quattro segnali con esempi concreti di come si manifestano nel lavoro quotidiano, perché se stai cercando uno sviluppatore PHP senior freelance per la tua azienda, questi sono i criteri operativi con cui valutarlo durante il primo colloquio - prima ancora di firmare un contratto.
Segnale 1: profilare prima di ipotizzare, sempre
L'errore che accomuna tutti gli sviluppatori junior strutturali - indipendentemente dall'età anagrafica o dagli anni di CV - è aprire l'editor appena ricevono la descrizione del problema e iniziare a "ottimizzare" basandosi su ciò che credono sia lento. Sul cliente della piattaforma SaaS di fatturazione elettronica, i due freelance precedenti avevano fatto esattamente questo. Il primo era convinto che il problema fosse il routing Laravel "troppo lento" e aveva passato quattordici giorni a riscriverlo - con il risultato che il routing contribuiva per 3 millisecondi sui 8.000 del tempo totale dell'endpoint, cioè lo 0,04% del problema. Il secondo aveva dato la colpa al database MySQL e alla sua "inadeguatezza per workload complessi", spingendo una migrazione costosissima verso PostgreSQL - con il risultato che il problema era al 78% nel codice applicativo, non nel motore di database sottostante.
La regola che insegno sempre ai team nei primi trenta minuti di un intervento performance è una sola, senza eccezioni: prima profili con strumenti reali, poi parli e intervieni. Gli strumenti sono tre e sono gli stessi dal 2018. Per il backend PHP uso Blackfire come profiler, documentato in dettaglio nella guida ufficiale di SensioLabs, che produce una flame graph con la decomposizione del tempo speso in ogni chiamata di funzione e in ogni query SQL generata dall'applicazione. Per il database, lo slow_query_log di MySQL - documentato nella guida ufficiale di MySQL 8 nella sezione Server System Variables - impostato a 100 millisecondi come soglia per catturare ventiquattro ore di traffico reale. Per il frontend, quando rilevante, uso Lighthouse e WebPageTest. L'attivazione dello slow query log è l'unica cosa di rilievo da fare lato server e richiede quattro righe in /etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.1
log_queries_not_using_indexes = 1Sul cliente della piattaforma SaaS, in quarantacinque minuti di profiling Blackfire avevamo già la risposta che i due freelance precedenti non erano riusciti a trovare in dodici settimane di lavoro. Il 72% del tempo dell'endpoint veniva speso in 1.847 query identiche alla tabella invoice_lines generate da un classico pattern N+1 Eloquent in un foreach sui 200 preventivi del lotto, perché nessuno aveva pensato di eager-loadare la relazione lines sul Invoice model. Un altro 19% era in una singola query su tax_rates che selezionava senza indice composito su (country_code, tax_year, rate_type). L'ultimo 9% era distribuito in chiamate sincrone a SdI che in realtà potevano essere spostate in coda asincrona senza impatto funzionale per il commercialista che aspettava la risposta dell'interfaccia. Tre problemi, tre fix chirurgici - tutti invisibili al code review tradizionale, tutti evidenti in quarantacinque minuti di flame graph.
La differenza tra un programmatore PHP senior freelance vero e uno che usa solo il titolo si manifesta esattamente qui. Il senior sa che l'intuizione su "dove sta il problema" è sistematicamente sbagliata in sei casi su dieci, e che anche quando l'intuizione è giusta la priorità di intervento è sbagliata in otto casi su dieci. Solo il profiling reale, fatto su traffico di produzione e non su benchmark sintetici, permette di distinguere il collo di bottiglia che vale il 70% del tempo dal dettaglio estetico che vale lo 0,04%. Se il freelance che stai valutando non apre la conversazione con "fammi vedere i dati di produzione prima di proporre soluzioni", non è un senior.
Stai valutando un consulente PHP per un intervento su una tua applicazione critica e vuoi capire se ha davvero il metodo senior che sto descrivendo? Nel mio profilo professionale trovi il percorso concreto che porta a questo livello di competenza: vent'anni di interventi reali su piattaforme PHP in produzione, audit documentati, subentri su codice legacy senza documentazione, conformità a direttive come NIS2 e GDPR gestite in prima persona su progetti mission-critical.
Segnale 2: leggere il debito tecnico come fa un ingegnere finanziario, non come fa un purista
Il secondo segnale distintivo di un programmatore PHP senior è il modo in cui ragiona sul debito tecnico di una codebase legacy. Lo sviluppatore junior strutturale ha una reazione emotiva di fronte al codice brutto: lo classifica come "da buttare", propone riscritture complete, usa aggettivi come "spaghettificato" o "obsoleto" come se fossero argomenti tecnici. Il senior invece ragiona come un ingegnere finanziario: il debito tecnico è un prestito con un tasso di interesse implicito, e la domanda operativa non è quanto è brutto il codice ma quanto mi costa ogni mese in bug, in rallentamenti, in tempo di onboarding di nuovi sviluppatori, in rischio di sicurezza non mitigato.
Nella mia esperienza di audit su codice PHP legacy ho imparato a classificare il debito tecnico in quattro categorie con priorità di intervento molto diverse. La prima categoria è il debito che sanguina adesso: bug attivi in produzione, vulnerabilità sfruttabili documentate, query che rallentano le operazioni core del business. Questo debito ha priorità assoluta e va ripagato immediatamente, indipendentemente dall'eleganza del fix. La seconda è il debito che sanguinerà presto: versioni di PHP fuori supporto, librerie con CVE note, indici mancanti su tabelle che stanno per superare il milione di record. Questo debito va pianificato con timeline concrete - quando accade, non se accade. La terza categoria è il debito cosmetico: codice brutto ma funzionante, pattern non allineati con le best practice moderne, scelte architetturali che oggi faresti diverse ma che funzionano. Questo debito resta fermo fino a quando non coincide con un intervento di valore in quella zona del codice, perché toccarlo senza un motivo concreto introduce solo rischio di regressione. La quarta categoria è il debito immaginario: cose che sembrano debito a chi ha letto l'ultimo libro di Clean Code ma che in pratica non producono alcun costo misurabile. Questo debito non va toccato mai, perché il costo del fix supera sistematicamente il beneficio.
Sul cliente della piattaforma SaaS fatturazione elettronica, il CTO aveva un documento di "debito tecnico" preparato dal secondo freelance che conteneva ventitré voci. Tre erano nella categoria "sanguina adesso" - compreso il pattern N+1 che era esattamente il collo di bottiglia dell'endpoint. Cinque erano nella categoria "sanguinerà presto" - fra cui l'uso di MD5 per hash di password temporanee nel sistema di recupero credenziali, che è una vulnerabilità esplicitamente trattata nella categoria A02 Cryptographic Failures della OWASP Top 10 pubblicata ufficialmente dalla OWASP Foundation e non un dettaglio banale da avere in una piattaforma che tratta dati fiscali sensibili di 15.000 commercialisti. Le altre quindici voci erano miste fra cosmetica (nove) e debito immaginario (sei) - cose come "i controller hanno troppi metodi pubblici" o "usiamo ancora array_map in alcuni punti invece di collection Laravel". Il freelance precedente aveva proposto di affrontare tutte e ventitré le voci in un progetto di modernizzazione da sei mesi e ottantamila euro.
La mia proposta al CTO è stata diversa: fixare immediatamente le tre voci sanguinanti (due giorni di lavoro mirato), pianificare le cinque semi-urgenti nei successivi sessanta giorni con timeline concrete, lasciare le quindici voci miste esattamente dove erano fino a quando un intervento funzionale in quella zona non avesse reso economicamente sensato toccarle. Costo totale delle prime due categorie combinate: dodici giornate di lavoro distribuite su dieci settimane. Il criterio per decidere quale debito pagare è sempre lo stesso: quanto mi costa questo debito ogni mese in metriche concrete di business, e quanto costerebbe liberarmene adesso rispetto a lasciarlo fermo. Se hai un'applicazione PHP che ha accumulato anni di scelte architetturali diverse, il percorso di modernizzazione su codice PHP legacy che ho descritto in un articolo dedicato contiene il framework operativo che uso per distinguere le voci da affrontare subito da quelle da lasciare ferme.
Segnale 3: il coraggio di dire "non lo facciamo" quando il costo supera il beneficio
Il terzo segnale distintivo del senior è controintuitivo: è la capacità di dire al cliente non facciamolo quando un intervento proposto non produce valore misurabile, anche a costo di rinunciare a giornate fatturabili. Il freelance che ha bisogno di giustificare il proprio fatturato proporrà sempre l'intervento più grosso possibile, perché il suo incentivo economico nel breve è questo. Il senior che lavora con una prospettiva di carriera decennale sa che la reputazione di dire no ai progetti inutili vale economicamente molto più di sei mesi di fatturato su un refactor non necessario, perché genera riferimenti e collaborazioni future che un cliente soddisfatto di aver risparmiato risorse porta avanti per anni.
Il freelance che aveva proposto la migrazione da MySQL a PostgreSQL al cliente della piattaforma SaaS non stava necessariamente mentendo quando diceva che PostgreSQL è un database tecnologicamente più avanzato su molti aspetti. Stava mentendo quando diceva che questa scelta era la soluzione al problema specifico che il cliente aveva. PostgreSQL ha feature di query planner più sofisticate, ha un supporto nativo a JSON più maturo, ha opzioni di replica più flessibili. Nessuna di queste caratteristiche avrebbe risolto un problema N+1 applicativo generato in Eloquent, perché quel problema vive nel codice PHP, non nel database sottostante. La migrazione avrebbe sei settimane di sforzo ingegneristico e significativi rischi di regressione sul calcolo IVA - che poi si sono manifestati puntualmente - per affrontare un problema che si risolveva con tre righe di with() in un controller Laravel.
Lo stesso principio si applica ai rewrite massivi di codebase legacy. Ho visto PMI italiane spendere trecentomila euro per "riscrivere da zero" un gestionale PHP 5.6 funzionante ma datato, per poi ritrovarsi con una versione PHP 8.3 piena di bug di business logic nuovi che il sistema vecchio non aveva, perché il team di rewrite aveva dovuto reinterpretare centinaia di regole di business implicite nel codice originale senza averle mai discusse con gli utenti finali. In nove casi su dieci, il percorso razionale per una codebase legacy PHP 5.6 non è il rewrite completo ma la modernizzazione incrementale - aggiornamento di PHP minor version, refactor mirato dei moduli effettivamente toccati da nuove feature, fix delle vulnerabilità di sicurezza con priorità, introduzione graduale di test automatici sulle parti nuove. La modernizzazione incrementale di un gestionale PHP legacy senza rewrite completo che ho raccontato in un caso di studio dedicato mostra questo percorso concreto su un sistema di 93.000 righe portato in produzione senza alcun downtime.
Segnale 4: subentrare su codebase senza documentazione e produrre valore in una settimana
Il quarto segnale, forse il più difficile da riconoscere in un colloquio ma il più distintivo nella pratica, è la capacità di subentrare su una codebase senza documentazione. Quasi tutte le PMI italiane che hanno un'applicazione PHP in produzione da più di tre anni hanno una documentazione tecnica che va da "inesistente" a "disperatamente obsoleta". Il freelance che pretende di avere documentazione completa prima di iniziare sta essenzialmente rifiutando il lavoro, perché quella documentazione non esiste e non esisterà mai nei tempi di progetto tipici di una PMI.
Il metodo che uso sempre in questi casi è una sequenza molto precisa di quattro passi, pensata per produrre valore misurabile entro la prima settimana di lavoro anche su codice totalmente sconosciuto. Il primo passo è mappare il perimetro tecnico con uno script di audit che gira in quindici minuti e produce un inventario completo: versione di PHP, estensioni caricate, configurazione di OPcache e PHP-FPM, pacchetti di sistema, database con versione e dimensioni, tabelle più grandi, servizi systemd attivi, porte in ascolto, cron job di tutti gli utenti. Il secondo passo è attivare lo slow query log e Blackfire per ventiquattro ore di traffico reale, per costruire una mappa empirica di dove si spende tempo nella produzione vera, non di dove si pensa che si spenda tempo. Il terzo passo è un grep strategico sul codice per identificare i punti nevralgici: tutte le query SQL raw, tutti gli endpoint pubblici esposti nelle route, tutti gli accessi a variabili $_GET o $_POST non passati per form request, tutte le chiamate a exec, system, shell_exec (superficie di RCE latente), tutti gli include dinamici con variabili (superficie di LFI). Il quarto passo è parlare trenta minuti con chi usa l'applicazione quotidianamente - non con il CTO, ma con l'operatore del front-office che la usa otto ore al giorno e sa quali sono le tre cose che lo fanno bestemmiare ogni settimana.
Alla fine di questa prima settimana, un programmatore PHP senior freelance ha prodotto tre artefatti concreti che il cliente non aveva prima: un inventario tecnico scritto, una mappa empirica dei colli di bottiglia reali, e una lista prioritizzata di tre interventi ad alto ROI fattibili nei successivi quindici giorni di lavoro. Non una slide di "analisi preliminare" da consegnare in un meeting, ma documenti operativi che diventano la base di riferimento per tutto il lavoro successivo. Questo è il livello di output che separa chi fa consulenza senior da chi fa consulenza a ore.
Come valutare in fase di selezione: tre domande concrete da porre in colloquio
Se sei il titolare o il responsabile IT di una PMI italiana che deve scegliere un programmatore PHP senior freelance per un progetto importante, queste sono le tre domande operative che ti permettono di distinguere un senior vero da uno sviluppatore con anni accumulati ma approccio junior, in meno di venti minuti di conversazione.
La prima domanda è: come affronti un problema di performance su un'applicazione che non conosci? La risposta di un senior parlerà di profiling con strumenti specifici (Blackfire, Xdebug profile mode, slow query log), di misurazione prima di intervento, di distinzione fra benchmark sintetici e traffico reale. La risposta di un junior strutturale parlerà di "ottimizzazioni standard" da applicare, o peggio di tecnologie da cambiare prima di aver misurato. Se senti la parola "migreremo a tecnologia X perché è più performante" prima della parola "misureremo dove si perde tempo", hai la risposta.
La seconda domanda è: mi racconti un caso in cui hai consigliato al cliente di non fare un intervento che avevi proposto inizialmente, o di non farlo nelle modalità richieste? Un senior vero ha tre o quattro esempi concreti in memoria e te li racconta con nome del contesto anonimizzato, numeri di budget risparmiato, metriche prima/dopo. Un junior strutturale o ti dice che non gli è mai capitato (segnale rosso: ha sempre detto di sì ai clienti), oppure ti racconta un episodio vago senza dettagli quantitativi. La consapevolezza del proprio errore, e la capacità di correggersi, è un indicatore di seniority molto affidabile.
La terza domanda è: se ti passo credenziali di root su un server di produzione che non conosci, qual è la prima cosa che fai? Un senior risponde con "niente di distruttivo, apro prima una sessione tmux per non perdere lo stato in caso di disconnect, controllo l'uptime e i processi attivi in sola lettura, guardo i log dell'ultima settimana, chiedo chi altri ha accesso - prima di toccare qualunque cosa". Un junior strutturale ti risponde con una lista di "comandi standard di hardening" che farebbe subito, senza capire che su un sistema non suo la prima regola è non rompere l'ambiente di produzione che funziona, anche se potrebbe essere configurato meglio. La disciplina del non-intervento è una competenza senior tanto quanto la capacità di intervento.
Se stai cercando per la tua PMI italiana un profilo tecnico con queste caratteristiche, e vuoi valutare un intervento concreto sulla tua infrastruttura PHP o sulla tua codebase Laravel o Symfony, puoi contattarmi qui per una prima conversazione orientativa. Nel primo confronto telefonico, in meno di mezz'ora, riesco quasi sempre a capire se il problema che stai affrontando rientra nel mio perimetro di competenza - e se non ci rientra, te lo dico esplicitamente e ti indirizzo a figure più adatte quando le conosco. Il peggior servizio che un consulente senior può fare al cliente è accettare un lavoro che sa di non poter eseguire al livello necessario, e questo vale in particolare per gli interventi su infrastrutture critiche delle PMI italiane dove lo sbaglio di un consulente generalista può costare mesi di downtime o di dati compromessi - una dinamica che vedo ripetersi ogni volta che un cliente mi arriva dopo aver bruciato tempo e budget con profili che non erano adeguati al compito richiesto.