Ogni sviluppatore freelance, agenzia o consulente ha perso soldi su un progetto a causa di una stima sbagliata: troppo bassa per paura di perdere il cliente, troppo alta senza riuscire a giustificarla, o semplicemente errata perché le ore sono state indovinate a caso senza un processo reale dietro.
L'ho fatto per anni, e ogni volta mi dicevo "la prossima stima sarà più precisa". Ma continuavo a sbagliare: di solito ero corto sulle ore e finivo per lavorare in più senza guadagnarci nulla perché mi mancava un metodo reale per calcolare la quantità di lavoro necessaria a completare il progetto.
Così ho deciso che aveva bisogno di una definizione concreta.
Il problema non è la mancanza di metodi. Già all'università ho studiato modelli accademici per stimare i costi del software introdotti dagli anni '70: COCOMO, Function Points, le osservazioni nel Mythical Man-Month. Sono un'ottima base per avere una visione specifica, ma non sono quasi mai adeguati e, nella pratica, nessuno li usa davvero perché sono stati progettati per grandi aziende che stimano progetti pluriennali e multi-team, molto prima del panorama tecnologico attuale. Tradurli in un caso d'uso da sviluppatore solo o piccola agenzia è di solito uno spreco di tempo, e produce tipicamente un costo che non riflette la realtà.
Così ho costruito Project Estimator: uno strumento gratuito, local-only, che condensa questi modelli in una singola equazione che permette di definire tutti i parametri per popolare l'input matematico in pochi minuti.
Partendo dal concetto di Work Item (le cose concrete che vanno fatte) l'ho mappato su un albero.
Ogni Work Item è un nodo foglia e i genitori aggregano semplicemente i propri figli in sottogruppi di Work Item.
Ad esempio, un'integrazione front-end potrebbe richiedere di scrivere il componente visivo, una libreria per processare gli input e un'altra per comunicare con un sistema back-end. Questi sono tutti Work Item raggruppabili sotto il sottogruppo "Integrazione front-end".
In ogni caso, la stima reale avviene a livello di foglia, quindi dal punto di vista del calcolo si tratta di un approccio bottom-up.
L'equazione è:
Nominal = Base × Deliverable × Complexity × SkillGap × Kept + IntegrationHoursOgni fattore è una correzione separata a un unico input umano: baseHours, ovvero il numero di ore che il lavoro richiederebbe in condizioni ideali: uno sviluppatore competente, senza sorprese, che parte da zero. Tutto il resto si aggiusta attorno a questo parametro chiave.
Deliverable scala verso l'alto in base al livello di qualità richiesto, dal prototipo (nessun moltiplicatore) a mission_critical (massimo). La stessa feature può essere amplificata in ore a seconda della cura impiegata per rilasciarla. Una feature usa e getta richiede una frazione del tempo che richiede quando ha bisogno di osservabilità, integrazioni corrette, ridondanza, copertura di test e zero tolleranza per i fallimenti.
Complexity collassa 8 assi in un unico moltiplicatore usando una somma pesata con damping:
complexity = 1 + (Σ weight_i × (scale_i - 1) / 4) × dampingGli assi sono:
Il fattore di damping è ciò che impedisce al moltiplicatore di esplodere: molti assi a complessità moderata pesano più di un singolo asse al massimo, ma il risultato rimane limitato e ben stimato.
Questo moltiplicatore riflette bene come funzionano i progetti reali. Non ti preoccupi di una grande caratteristica per volta, ma di diverse caratteritiche medie che si compongono nel valore totale del lavoro che stai facendo.
Skill gap prende solo il gap peggiore tra tutte le skill richieste, non la media:
skillGap = 1 + coefficient × max(required - available, 0)La logica viene direttamente dal Mythical Man-Month: la competenza che manca di più detta il ritmo. Essere iper-qualificati su altri assi non compensa. L'esperienza conta, e la capacità di consegnare prodotti production-grade fin dal primo momento è qualcosa che un cliente dovrebbe sempre considerare un vantaggio concreto prima di scegliere un professionista piuttosto che un altro.
Kept è l'unico fattore sotto 1. Combina il riuso (il tuo codice riutilizzato) e l'offloading (lavoro delegato a un sistema esterno) in modo indipendente:
kept = (1 - reuseAvoided) × (1 - offloadAvoided)L'indipendenza è intenzionale: riusare il proprio componente e delegare parte del lavoro a un sistema esterno non azzera lo sforzo completamente. Questo è anche il motivo esatto per cui esiste il parametro integration hours, aggiunto fuori dal prodotto finale. Il costo di far comunicare un sistema esterno con il tuo è fisso, indipendentemente da quanto sia complesso il work item.
Questo è sempre qualcosa che tendiamo a sottostimare: il rischio che le cose non vadano bene. Non sto parlando di rischi come "il database di produzione esploderà". Sto parlando di cose come "il cliente adesso vuole una modifica nuova perché ha cambiato idea una volta uscita la prima versione". Questo, purtroppo, è uno schema fin troppo comune. Da professionisti tendiamo a pensare che il cliente sappia già cosa verrà fuori.
Un esempio reale: "Devo costruire una landing page con un form di contatto. Facilissimo". L'ho costruita, tutto bene. Una volta che il sistema è andato in produzione, il cliente era insoddisfatto del numero di email che riceveva e dell'assenza di un'interfaccia strutturata dove poterle vedere tutte senza usare un client email. Come persona tecnica, pensavo: "Ok, è il tuo spazio, con un'email dedicata solo a questa landing page, leggi le email e va tutto bene". No, invece. Il cliente voleva una UI per leggere le email ricevute. Questo è il tipo di cosa che si può considerare solo quando si affrontano i rischi separatamente dal work item stesso, perché i rischi non si manifestano necessariamente, e la soluzione è di solito un workaround rapido. Ma se nessun workaround è possibile, il work item ora aumenta drasticamente la quantità di lavoro, condizionando potenzialmente anche altri work item a cascata.
Per questo i rischi vivono in un modello separato. Un rischio è un evento incerto, non un task, e mescolare i due produce stime che sono o gonfiate (se ogni rischio si materializza sempre) o disoneste (se i rischi vengono ignorati del tutto).
Ogni rischio produce ore basate sulla probabilità residua dopo la mitigazione:
riskHours = residualFraction × impactHours + mitigationHoursLe ore di mitigazione sono il numero di ore necessarie a mitigare il rischio e si pagano sempre: se conti anche i rischi, spenderai tempo sugli aggiustamenti a prescindere.
Alla fine, ho comunque deciso di mantenere i rischi opzionali, con un toggle "includeInEstimate" che decide se il costo finale considera anche i rischi oppure se verranno fatturati a parte. La decisione è tua.
Concentrarsi solo sulle ore non è sufficiente: c'è valore nel lavoro che facciamo, ma anche per chi lo facciamo.
I 9 assi strategici producono un unico moltiplicatore di prezzo, basato su questi parametri:
Il centro è 3 ed è un valore neutro, il che significa che il parametro non condiziona il prezzo.
La decisione chiave qui è che la strategia è un valore aggiunto al progetto che non dovrebbe toccare le ore. Il lavoro è il lavoro. La relazione con il cliente è tutta un'altra cosa: tenendole separate, la stima è più onesta.
totalHours = nominalHours + riskHours
subtotal = totalHours × hourlyRate
after = subtotal × strategyMultiplier × (1 - discount) × (1 + margin)L'ordine è deliberato: la strategia agisce sul subtotale perché è una valutazione a livello di progetto, poi arrivano lo sconto commerciale e il margine. Sono parametri diversi pensati per considerazioni diverse.
Dopo numerosi lavori con clienti diversi che hanno finito per sottrarre molta energia a causa di stime errate, ho studiato una serie di modelli di costo per prezzare meglio i miei lavori. Dopo un po' di errori, avevo un'idea di quanto ogni progetto sarebbe dovuto costare perché alla fine del lavoro conoscevo davvero le ore spese. Così, ho ritoccato il modello finché non ho ottenuto esattamente quello che avrei dovuto guadagnare da tutte le attività sottostimate. Le stime sono risultate perfettamente allineate con quello che dovevo effettivamente fatturare al cliente.
Personalmente, oggi non comunico mai alcun prezzo a meno che non sia per un prodotto a prezzo fisso. Tutto il resto che coinvolge le mie mani, la mia mente, il mio tempo e la mia intuizione deve passare per questo modello matematico. Mi dà la certezza di non fare errori.
Lo strumento è completamente gratuito, senza registrazione e senza back-end: i tuoi dati non vengono mai registrati da nessuna parte.
Questo significa che non puoi portare le stime con te ovunque, ma restano sul tuo browser finché non decidi di cancellare i dati locali.
Tutte le stime precedenti vengono salvate come file JSON in IndexedDB, ma puoi facilmente esportare il PDF da inviare al cliente con un piano dettagliato di quanto costa ogni lavoro e puoi anche esportare il file JSON per riutilizzarlo in seguito, o semplicemente salvarlo nel browser.
Un'altra cosa utile è il pulsante in basso a destra che ti permette di copiare un prompt per gli LLM. Puoi descrivere facilmente il progetto all'LLM e ottenere un output JSON con tutti i dettagli pre-compilati sui work item, così da poter poi aggiustare tutto in base alla tua visione, alle tue skill e al tuo modo di lavorare.
Ecco il link: project-estimator.webround.net
Built with Webround: una piattaforma API-first per e-commerce e siti web che supporta codice React direttamente dal browser.