Aikido

Por que você deve usar uma classe por arquivo: melhorando a organização e a navegação do código

Legibilidade

Regra

Uma classe por arquivo.
Múltiplas classes em um único arquivo tornam a
organização do código pouco clara e mais difícil de navegar.

Linguagens suportadas: 45+

Introdução

Colocar múltiplas classes em um único arquivo dificulta a localização de classes específicas ao navegar por uma base de código. Desenvolvedores procurando por UserRepository não o encontrará rapidamente se estiver enterrado em um arquivo chamado database.js juntamente com outras cinco classes. Isso viola o princípio da menor surpresa e retarda o desenvolvimento, pois os membros da equipe perdem tempo procurando por definições de classe.

Por que isso importa

Manutenibilidade do código: Múltiplas classes por arquivo criam limites pouco claros entre as responsabilidades. Quando uma classe precisa de modificação, os desenvolvedores devem abrir um arquivo contendo classes não relacionadas, aumentando a carga cognitiva e o risco de modificar acidentalmente o código errado.

Navegação e descoberta: IDEs e editores de texto têm dificuldade em fornecer um "ir para a definição" preciso quando múltiplas classes compartilham um arquivo. Desenvolvedores gastam tempo procurando dentro dos arquivos em vez de pular diretamente para a classe de que precisam. Isso se agrava em grandes bases de código com centenas de classes.

Conflitos de controle de versão: Quando múltiplas classes compartilham um arquivo, alterações em classes diferentes por desenvolvedores diferentes criam conflitos de merge. Arquivos separados permitem o desenvolvimento paralelo sem sobrecarga de coordenação, pois cada desenvolvedor trabalha em seu próprio arquivo.

Exemplos de código

❌ Não-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 que está errado: Três classes de repositório não relacionadas em um arquivo chamado database.js. Procurando por OrderRepository exige saber que está em database.js em vez de OrderRepository.js. Alterações de arquivo afetam múltiplas classes, criando conflitos de merge desnecessários.

✅ Compatível:

// 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 que isso importa: Cada classe em seu próprio arquivo torna a navegação previsível. IDEs podem pular diretamente para OrderRepository.js ao procurar pela classe. Alterações em um repositório não afetam outros, eliminando conflitos de merge desnecessários.

Conclusão

Nomeie os arquivos de acordo com a classe que contêm para uma navegação previsível. Essa convenção se adapta a grandes bases de código onde encontrar classes específicas rapidamente é importante. Os arquivos adicionais valem a clareza organizacional que proporcionam.

FAQs

Dúvidas?

E quanto às pequenas classes auxiliares ou classes privadas?

Pequenas classes auxiliares usadas apenas por uma classe pai podem permanecer no mesmo arquivo se forem realmente detalhes de implementação. No entanto, se as classes auxiliares forem reutilizadas ou crescerem além de 20-30 linhas, extraia-as. Classes privadas que existem apenas para suportar uma classe pública são exceções razoáveis.

Isso se aplica a interfaces e tipos do TypeScript?

Tipos e interfaces usados por uma classe podem residir no mesmo arquivo. No entanto, tipos compartilhados e utilizados em múltiplos arquivos devem estar em seus próprios arquivos de definição de tipo. O ponto chave é se a definição é usada apenas por aquele arquivo ou se é necessária em outros lugares.

E quanto às linguagens como Python com múltiplas classes na prática padrão?

As convenções do Python diferem, mas o princípio ainda se aplica: agrupe classes relacionadas se elas formarem um módulo coeso, mas evite misturar classes não relacionadas. Um models.py com User e UserProfile faz sentido. Um utils.py com vinte classes não relacionadas não faz.

Como organizar classes relacionadas como classes pai e filho?

Coloque-os em arquivos separados dentro do mesmo diretório. Para Animal e Dog, use animals/Animal.js e animals/Dog.js. A estrutura de diretórios mostra relacionamentos enquanto mantém uma classe por arquivo. Isso escala melhor do que agrupar classes relacionadas em um único arquivo.

E se a extração de classes criar muitos arquivos pequenos?

Muitos arquivos pequenos são preferíveis a poucos arquivos grandes. IDEs modernas lidam com milhares de arquivos de forma eficiente. A navegação no sistema de arquivos é mais rápida do que a busca dentro de arquivos grandes. A clareza de saber exatamente onde cada classe reside supera a percepção de "arquivos demais".

Fique seguro agora

Proteja seu código, Cloud e runtime em um único sistema centralizado.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados da varredura em 32 segundos.