Aikido

Por qué deberías usar una clase por archivo: mejorando la organización y navegación del código

Legibilidad

Regla

Un clase por expediente.
Varias clases en clases en a único archivo archivo hacer código
organización poco clara y más difícil de navegar.

Idiomas compatibles: 45+

Introducción

Poner varias clases en un solo archivo dificulta la localización de clases específicas al navegar por una base de código. Los desarrolladores que buscan UserRepository no lo encontrará rápidamente si está oculto en un archivo llamado database.js junto con otras cinco clases. Esto viola el principio de la menor sorpresa y ralentiza el desarrollo, ya que los miembros del equipo pierden tiempo buscando las definiciones de las clases.

Por qué es importante

Mantenibilidad del código: Múltiples clases por archivo crean límites poco claros entre responsabilidades. Cuando una clase necesita modificación, los desarrolladores deben abrir un archivo que contiene clases no relacionadas, lo que aumenta la carga cognitiva y el riesgo de modificar accidentalmente código incorrecto.

Navegación y detectabilidad: Los IDEs y editores de texto tienen dificultades para proporcionar una función precisa de "ir a la definición" cuando varias clases comparten un archivo. Los desarrolladores dedican tiempo a buscar dentro de los archivos en lugar de saltar directamente a la clase que necesitan. Esto se agrava en grandes bases de código con cientos de clases.

Conflictos de control de versiones: Cuando múltiples clases comparten un archivo, los cambios en diferentes clases por parte de distintos desarrolladores crean conflictos de fusión. Los archivos separados permiten el desarrollo paralelo sin la sobrecarga de coordinación, ya que cada desarrollador trabaja en su propio archivo.

Ejemplos de código

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

Por qué es incorrecto: Tres clases de repositorio no relacionadas en un archivo llamado database.js. Buscando OrderRepository requiere saber que está en database.js en lugar de OrderRepository.js. Los cambios en los archivos afectan a múltiples clases, creando conflictos de fusión innecesarios.

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

¿Por qué esto importa? Cada clase en su propio archivo hace que la navegación sea predecible. Los IDE pueden saltar directamente a OrderRepository.js al buscar la clase. Los cambios en un repositorio no afectan a otros, eliminando conflictos de fusión innecesarios.

Conclusión

Nombra los archivos según la clase que contienen para una navegación predecible. Esta convención se adapta a grandes bases de código donde encontrar clases específicas rápidamente es importante. Los archivos adicionales valen la claridad organizativa que proporcionan.

Preguntas frecuentes

¿Tiene preguntas?

¿Qué hay de las pequeñas clases auxiliares o clases privadas?

Las pequeñas clases auxiliares (helper classes) utilizadas solo por una clase padre pueden permanecer en el mismo archivo si son realmente detalles de implementación. Sin embargo, si los auxiliares se reutilizan o superan las 20-30 líneas, extráigalos. Las clases privadas que existen solo para soportar una clase pública son excepciones razonables.

¿Esto se aplica a interfaces y tipos de TypeScript?

Los tipos e interfaces utilizados por una clase pueden residir en el mismo archivo. Sin embargo, los tipos compartidos utilizados en varios archivos deben estar en sus propios archivos de definición de tipo. La clave es si la definición se utiliza solo por ese archivo o si se necesita en otro lugar.

¿Qué hay de lenguajes como Python con múltiples clases en la práctica estándar?

Las convenciones de Python difieren, pero el principio sigue siendo válido: agrupe las clases relacionadas si forman un módulo cohesivo, pero evite mezclar clases no relacionadas. Un models.py con User y UserProfile tiene sentido. Un utils.py con veinte clases no relacionadas no lo tiene.

¿Cómo organizo clases relacionadas como clases padre e hijo?

Colóquelos en archivos separados dentro del mismo directorio. Para Animal y Dog, utilice animals/Animal.js y animals/Dog.js. La estructura de directorios muestra las relaciones mientras se mantiene una clase por archivo. Esto escala mejor que agrupar clases relacionadas en un solo archivo.

¿Qué ocurre si extraer clases crea muchos archivos pequeños?

Muchos archivos pequeños son preferibles a pocos archivos grandes. Los IDE modernos manejan miles de archivos de manera eficiente. La navegación por el sistema de archivos es más rápida que la búsqueda dentro de archivos grandes. La claridad de saber exactamente dónde reside cada clase supera la percepción de «demasiados archivos».

Asegúrate ahora.

Proteja su código, la nube y el entorno de ejecución en un único sistema central.
Encuentre y corrija vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.