Aikido

Perché dovresti usare una sola classe per file: migliorare l'organizzazione e la navigazione del codice

Leggibilità

Regola

Una classe per file.
Più classi in un singolo file rendono l'organizzazione
del codice poco chiara e difficile
da navigare.

Linguaggi supportati: 45+

Introduzione

Inserire più classi in un unico file rende difficile trovare classi specifiche durante la navigazione in una codebase. Gli sviluppatori che cercano UserRepository non la troveranno rapidamente se è sepolta in un file chiamato database.js insieme ad altre cinque classi. Questo viola il principio della massima sorpresa e rallenta lo sviluppo poiché i membri del team perdono tempo a cercare le definizioni delle classi.

Perché è importante

Manutenibilità del codice: Più classi per file creano confini poco chiari tra le responsabilità. Quando una classe richiede una modifica, gli sviluppatori devono aprire un file contenente classi non correlate, aumentando il carico cognitivo e il rischio di modificare accidentalmente il codice sbagliato.

Navigazione e individuabilità: Gli IDE e gli editor di testo faticano a fornire un "vai alla definizione" accurato quando più classi condividono un file. Gli sviluppatori perdono tempo a cercare all'interno dei file anziché saltare direttamente alla classe di cui hanno bisogno. Questo problema si amplifica nelle codebase di grandi dimensioni con centinaia di classi.

Conflitti di controllo versione: Quando più classi condividono un file, le modifiche a classi diverse da parte di sviluppatori differenti creano conflitti di merge. File separati consentono uno sviluppo parallelo senza sovraccarichi di coordinamento, poiché ciascuno sviluppatore lavora sul proprio file.

Esempi di codice

❌ Non conforme:

// database.js
class UserRepository {
    async findById(id) {
        return db.users.findOne({ id });
    }
}

class OrderRepository {
    async findByUser(userId) {
        return db.orders.find({ userId });
    }
}

class ProductRepository {
    async findInStock() {
        return db.products.find({ stock: { $gt: 0 } });
    }
}

module.exports = { UserRepository, OrderRepository, ProductRepository };

Perché è errato: Tre classi di repository non correlate in un unico file chiamato database.js. La ricerca di OrderRepository richiede di sapere che si trova in database.js anziché in OrderRepository.js. Le modifiche al file influiscono su più classi, creando conflitti di merge non necessari.

✅ Conforme:

// UserRepository.js
class UserRepository {
    async findById(id) {
        return db.users.findOne({ id });
    }
}
module.exports = UserRepository;

// OrderRepository.js
class OrderRepository {
    async findByUser(userId) {
        return db.orders.find({ userId });
    }
}
module.exports = OrderRepository;

// ProductRepository.js
class ProductRepository {
    async findInStock() {
        return db.products.find({ stock: { $gt: 0 } });
    }
}
module.exports = ProductRepository;

Perché questo è importante: Ogni classe nel proprio file rende la navigazione prevedibile. Gli IDE possono saltare direttamente a OrderRepository.js quando cercano la classe. Le modifiche a un repository non influiscono sugli altri, eliminando conflitti di merge superflui.

Conclusione

Assegna ai file il nome della classe che contengono per una navigazione prevedibile. Questa convenzione è scalabile per codebase di grandi dimensioni in cui è fondamentale trovare rapidamente classi specifiche. I file aggiuntivi valgono la chiarezza organizzativa che offrono.

FAQ

Hai domande?

E per quanto riguarda le piccole classi di supporto o le classi private?

Le piccole classi di supporto utilizzate da una sola classe genitore possono rimanere nello stesso file se sono effettivamente dettagli di implementazione. Tuttavia, se gli helper vengono riutilizzati o superano le 20-30 righe, è consigliabile estraerli. Le classi private che esistono unicamente per supportare una classe pubblica rappresentano eccezioni ragionevoli.

Questo vale anche per le interfacce e i tipi in TypeScript?

I tipi e le interfacce usati da una classe possono trovarsi nello stesso file. Tuttavia, i tipi condivisi utilizzati in più file dovrebbero essere inseriti nei propri file di definizione dei tipi. Il criterio fondamentale è se la definizione sia utilizzata esclusivamente da quel file o se sia necessaria altrove.

E nel caso di linguaggi come Python, dove è una normale pratica avere più classi?

Le convenzioni di Python sono diverse, ma il principio di base rimane valido: raggruppa le classi correlate se formano un modulo coeso, evitando però di mischiare classi che non c'entrano nulla. Un file models.py con User e UserProfile ha senso, mentre un file utils.py con venti classi scollegate tra loro no.

Come posso organizzare classi correlate come quelle con relazione padre-figlio?

Inseriscile in file separati all'interno della stessa directory. Per Animal e Dog, usa animals/Animal.js e animals/Dog.js. La struttura delle directory evidenzia le relazioni pur mantenendo una sola classe per file. Questo approccio scala molto meglio rispetto all'inclusione di più classi correlate nello stesso file.

Cosa succede se l'estrazione delle classi porta alla creazione di molti file piccoli?

Molti file di piccole dimensioni sono preferibili a pochi file di grandi dimensioni. I moderni IDE gestiscono migliaia di file con estrema efficienza. La navigazione nel file system è più rapida rispetto alla ricerca all'interno di file enormi. La chiarezza di sapere esattamente dove si trova ciascuna classe supera di gran lunga la percezione di avere "troppi file".

Metti in sicurezza ora

Metti in sicurezza il tuo codice, il cloud e il runtime in un unico sistema centralizzato.
Trova e risolvi le vulnerabilità rapidamente e automaticamente.

Nessuna carta di credito richiesta | Risultati della scansione in 32 secondi.