Aikido

Pourquoi utiliser une classe par fichier : améliorer l'organisation du code et la navigation

Lisibilité

Règle

Une classe par dossier.
Plusieurs classes dans a fichier fichier faire code
organisation peu claire et plus plus navigation.

Langues prises en charge : 45+

Introduction

Le fait de placer plusieurs classes dans un seul fichier rend difficile la localisation de classes spécifiques lorsque l'on navigue dans une base de code. Les développeurs qui recherchent des Référentiel d'utilisateurs ne le trouvera pas rapidement s'il est enfoui dans un fichier nommé database.js avec cinq autres classes. Cela viole le principe de moindre surprise et ralentit le développement, car les membres de l'équipe perdent du temps à rechercher les définitions des classes.

Pourquoi c'est important

Maintenabilité du code : La multiplicité des classes par fichier crée des frontières floues entre les responsabilités. Lorsqu'une classe doit être modifiée, les développeurs doivent ouvrir un fichier contenant des classes sans rapport, ce qui augmente la charge cognitive et le risque de modifier accidentellement un code erroné.

Navigation et découverte : Les IDE et les éditeurs de texte peinent à fournir des définitions précises lorsque plusieurs classes partagent un même fichier. Les développeurs perdent du temps à chercher dans les fichiers plutôt que d'accéder directement à la classe dont ils ont besoin. Cette situation s'aggrave dans les grandes bases de code comportant des centaines de classes.

Conflits de contrôle de version : Lorsque plusieurs classes partagent un fichier, les modifications apportées à différentes classes par différents développeurs créent des conflits de fusion. Les fichiers séparés permettent un développement parallèle sans frais de coordination, puisque chaque développeur travaille dans son propre fichier.

Exemples de code

❌ 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 };

Pourquoi c'est mal : Trois classes de référentiel sans rapport entre elles dans un seul fichier nommé database.js. Recherche de Référentiel de commande nécessite de savoir qu'il est dans database.js plutôt que OrderRepository.js. Les modifications de fichiers affectent plusieurs classes, ce qui crée des conflits de fusion inutiles.

✅ 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;

Pourquoi cela est-il important ? Chaque classe dans son propre fichier rend la navigation prévisible. Les IDE peuvent passer directement à OrderRepository.js lors de la recherche de la classe. Les modifications apportées à un référentiel n'affectent pas les autres, ce qui élimine les conflits de fusion inutiles.

Conclusion

Nommez les fichiers d'après la classe qu'ils contiennent pour une navigation prévisible. Cette convention s'applique à de grandes bases de code où il est important de trouver rapidement des classes spécifiques. Les fichiers supplémentaires valent la peine pour la clarté organisationnelle qu'ils apportent.

FAQ

Vous avez des questions ?

Qu'en est-il des petits cours d'aide ou des cours particuliers ?

Les petites classes d'aide utilisées uniquement par une classe mère peuvent rester dans le même fichier s'il s'agit vraiment de détails d'implémentation. Toutefois, si les classes d'aide sont réutilisées ou dépassent 20 à 30 lignes, il convient de les extraire. Les classes privées qui n'existent que pour soutenir une classe publique sont des exceptions raisonnables.

Cela s'applique-t-il aux interfaces et aux types TypeScript ?

Les types et les interfaces utilisés par une classe peuvent se trouver dans le même fichier. Toutefois, les types partagés utilisés dans plusieurs fichiers appartiennent à leurs propres fichiers de définition de type. La clé est de savoir si la définition est utilisée uniquement par ce fichier ou si elle est nécessaire ailleurs.

Qu'en est-il des langages tels que Python, dont la pratique courante consiste à utiliser plusieurs classes ?

Les conventions Python diffèrent, mais le principe reste le même : regrouper les classes apparentées si elles forment un module cohérent, mais éviter de mélanger des classes non apparentées. Un models.py avec User et UserProfile a du sens. Un utils.py avec vingt classes sans rapport ne l'est pas.

Comment organiser les classes apparentées, comme les classes parentales et enfantines ?

Placez-les dans des fichiers distincts dans le même répertoire. Pour Animal et Chien, utilisez animals/Animal.js et animals/Dog.js. La structure du répertoire montre les relations tout en conservant une classe par fichier. Cette méthode est plus efficace que celle qui consiste à regrouper des classes apparentées dans un seul fichier.

Que se passe-t-il si l'extraction de classes crée de nombreux petits fichiers ?

De nombreux petits fichiers sont préférables à quelques gros fichiers. Les IDE modernes gèrent efficacement des milliers de fichiers. La navigation dans le système de fichiers est plus rapide que la recherche dans de gros fichiers. La clarté de savoir exactement où se trouve chaque classe l'emporte sur la perception d'un "trop grand nombre de fichiers".

Obtenir la sécurité gratuitement

Sécurisez votre code, votre cloud et votre environnement d'exécution dans un système central.
Trouvez et corrigez rapidement et automatiquement les vulnérabilités.

Aucune carte de crédit n'est requise | Scanner les résultats en 32sec.