Il commento più utile è quello che non devi scrivere

C'è un momento nella vita di ogni sviluppatore in cui apre un file scritto sei mesi prima — magari da se stesso — e pensa: "chi ha scritto questa roba?"

La risposta, quasi sempre, sei tu.

Il problema raramente è la mancanza di commenti. Il problema è che il codice in sé non comunica nulla, e nessun commento può salvare una funzione chiamata doStuff() che accetta un parametro chiamato $x.

Partiamo da un principio semplice: il codice viene letto molto più spesso di quanto viene scritto. Lo leggi tu il giorno dopo, lo legge un collega, lo legge il tuo futuro te alle 23:00 mentre cerchi un bug in produzione. Ogni minuto investito a scegliere un nome chiaro ti ripaga con gli interessi.


Il metodo che si commenta da solo

Guarda questi due esempi e dimmi quale preferiresti trovare in un codebase legacy:

// Recupera il cliente per ID
function gc($i) {
    return $this->db->query("SELECT * FROM c WHERE id = ?", [$i]);
}
function getCustomerById(int $customerId): ?Customer {
    return $this->customerRepository->findById($customerId);
}

Il secondo non ha commenti. Non ne ha bisogno. Leggendolo sai:

Il primo ha perfino un commento, eppure ti dice meno. Perché il commento descrive l'intenzione, ma il nome gc e il parametro $i non ti dicono nulla se stacchi dal contesto.

La regola è semplice: il nome di un metodo dovrebbe descrivere cosa fa, non come lo fa.


Gli errori più comuni (che tutti abbiamo fatto)

Il parametro senza contesto

// ❌ Cosa rappresenta $flag? Un booleano? Un intero? Una stringa?
function processOrder($id, $flag) { ... }

// ✅ Ora è chiaro
function processOrder(int $orderId, bool $sendConfirmationEmail) { ... }

Con il secondo esempio non devi aprire il corpo della funzione per capire come chiamarla. Il nome del parametro è documentazione gratuita.

La variabile usa-e-getta

// ❌ Cosa contiene $data? Il mistero dell'universo?
$data = $this->getFromApi();
foreach ($data as $item) {
    // ...
}

// ✅
$products = $this->fetchProductsFromApi();
foreach ($products as $product) {
    // ...
}

Il booleano enigmatico

// ❌ True o false, ma cosa cambia?
updateUser($userId, true, false, true);

// ✅ Named arguments (PHP 8+), oppure un oggetto di configurazione
updateUser(
    userId: $userId,
    sendWelcomeEmail: true,
    requirePasswordChange: false,
    isActive: true
);

La classe tuttofare

// ❌ Manager di cosa, esattamente?
class UserManager { ... }

// ✅ Responsabilità singola, nome preciso
class UserRegistrationService { ... }
class UserAuthenticator { ... }
class UserProfileRepository { ... }

Quando i commenti servono davvero

Fin qui sembra che i commenti siano inutili. Non è così. Esistono due situazioni in cui un commento è prezioso:

Il perché, non il cosa. Il codice ti dice cosa fa, ma non sempre perché lo fa in quel modo. Se hai aggirato un bug di una libreria esterna, o hai scelto un algoritmo apparentemente strano per ragioni di performance, scrivilo:

// Usiamo array_chunk invece di array_slice perché con dataset > 10k
// elementi array_slice causa un memory spike documentato in PHP 8.1.
// Rimuovere quando upgradiamo a PHP 8.3. Vedi: [link issue]
$chunks = array_chunk($largeDataset, 500);

La regex. Le espressioni regolari sono l'eccezione universale a qualsiasi regola sul codice auto-documentante. Commentale sempre. Sempre.

// Valida formato telefono italiano: +39 seguito da 6-10 cifre
$pattern = '/^\+39[0-9]{6,10}$/';

L'arte del TODO: patch veloce, coscienza pulita

Capita a tutti: la pressione del deploy, il bug in produzione, la soluzione rapida che "sistemo domani". Il TODO è il tuo contratto con il futuro:

// TODO: questa query va ottimizzata con un indice su created_at.
// Al momento il dataset è piccolo ma con > 100k righe diventerà lenta.
// Priorità: media. Aggiunto il 2026-04-04.
$results = $this->db->query("SELECT * FROM orders WHERE created_at > ?", [$date]);

Un buon TODO ha tre elementi: cosa va fatto, perché è una patch temporanea, e quando è stato scritto. La data è fondamentale: un TODO senza data è un TODO eterno.

Strumenti come VS Code o PhpStorm evidenziano i TODO nel codice e ti permettono di listarli tutti. Usali come una coda di debito tecnico consapevole, non come cestino dove buttare le cose che non vuoi affrontare.

// FIXME: gestione errori assente, aggiungere try/catch prima del go-live
// HACK: soluzione temporanea per compatibilità con API v1, rimuovere dopo migrazione
// NOTE: questo comportamento è intenzionale, non toccare senza leggere il ticket #4521

La parte più difficile del progetto

Sai qual è stata la discussione più lunga nel mio ultimo progetto? Non l'architettura. Non la scelta del framework. Non l'ottimizzazione delle query.

È stata decidere se la colonna si chiamava user_id, userId, o id_utente. E se la tabella era customers o clients. E se la data di creazione era created_at, creation_date, o inserted_at.

Ridi, ma è una cosa seria. Una volta che un nome entra nel database, ci resta. Cambiarlo significa una migration, aggiornare tutti i modelli, tutti i repository, tutti i test, tutta la documentazione. I nomi del database sono tatuaggi: pensaci bene prima.

Alcune convenzioni che mi hanno salvato:


Conclusione: scrivi per chi legge, non per chi esegue

Il compilatore o l'interprete non si importa dei tuoi nomi. Esegue $x esattamente come esegue $customerId. Ma il tuo collega, il tuo futuro sé, chiunque erediti quel codice — loro si importano eccome.

Scrivere codice leggibile non è una questione estetica. È rispetto: per gli altri e per te stesso tra sei mesi. Ogni nome chiaro è un secondo risparmiato a qualcuno che prova a capire il tuo lavoro. Moltiplicalo per tutte le volte che quel codice verrà letto, e capisci perché vale la pena fermarsi un momento a scegliere il nome giusto.

Anche quando stai rinominando la colonna del database per la quarta volta.