Aikido

1つのファイルに1つのクラスを使うべき理由:コードの構成とナビゲーションの改善

読みやすさ

ルール

ひとつ クラス につき ファイルにつき1クラス。
複数の クラス  a ファイル内の複数のクラス ファイル 作る コード
構成 不明確 そして しにくくする ナビゲートしにくい ナビゲートしにくくなります。

対応言語 45+

はじめに

複数のクラスを1つのファイルにまとめると、コードベースをナビゲートするときに特定のクラスを見つけるのが難しくなります。開発者は ユーザーリポジトリ という名前のファイルに埋もれていると、すぐに見つからない。 データベース を他の5つのクラスと並べることになる。これは最小サプライズの原則に反し、チームメンバーがクラスの定義を探すのに時間を浪費するため、開発が遅くなる。

なぜそれが重要なのか

コードの保守性:ファイルごとに複数のクラスがあると、責任の境界が不明確になる。あるクラスを修正する必要がある場合、開発者は関係のないクラスを含むファイルを開かなければならず、認識負荷が増加し、誤って間違ったコードを修正するリスクが高まります。

ナビゲーションと発見しやすさ:IDEやテキストエディタは、複数のクラスがファイルを共有している場合、正確な「定義への移動」を提供するのに苦労します。開発者は、必要なクラスに直接ジャンプするのではなく、ファイル内を検索することに時間を費やします。何百ものクラスがある大規模なコードベースでは、この問題はさらに深刻になります。

バージョン管理のコンフリクト:複数のクラスが1つのファイルを共有している場合、異なる開発者による異なるクラスへの変更はマージ・コンフリクトを引き起こします。ファイルを分けることで、各開発者が自分のファイルで作業するため、調整のオーバーヘッドなしに並行開発が可能になります。

コード例

非準拠:

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

なぜそれが間違っているのか: という名前の1つのファイルに、3つの無関係なリポジトリクラスが含まれている。 データベース.検索 注文リポジトリ にあることを知る必要がある。 データベース よりも OrderRepository.js.ファイルの変更は複数のクラスに影響し、不必要なマージの衝突を引き起こす。

✅ 準拠:

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

なぜこれが重要なのか: 各クラスを独自のファイルにすることで、ナビゲーションを予測しやすくする。IDEは直接 OrderRepository.js でクラスを検索することができます。1つのリポジトリへの変更が他のリポジトリに影響しないので、不要なマージ競合がなくなります。

結論

ナビゲーションを予測しやすくするために、ファイル名は含まれるクラスの後に付けます。この規約は、特定のクラスを素早く見つけることが重要な、大規模なコードベースにも適用できます。余分なファイルは、組織的な明快さを提供する価値があります。

よくある質問

ご質問は?

少人数のヘルパークラスやプライベートクラスはどうですか?

つの親クラスだけが使う小さなヘルパークラスは、それが本当に実装の詳細であれば、同じファイルに残すことができます。しかし、もしヘルパーが再利用されたり、20-30行を超えるような場合は、それらを取り出してください。あるパブリッククラスをサポートするためだけに存在するプライベートクラスは、妥当な例外です。

これはTypeScriptのインターフェースや型にも適用されるのか?

クラスで使用される型とインターフェースは、同じファイルに置くことができます。しかし、複数のファイルにまたがって使われる共有型は、それぞれの型定義ファイルに属します。重要なのは、その定義がそのファイルだけで使われるものなのか、他の場所で必要とされるものなのかということです。

Pythonのように複数のクラスが標準的に使われている言語についてはどうだろう?

Pythonの規約は異なりますが、原則はまだ適用されます: 関連するクラスがまとまりのあるモジュールを形成する場合はグループ化しますが、関連しないクラスを混在させることは避けます。UserとUserProfileを含むmodels.pyは理にかなっています。UserとUserProfileを含むmodels.pyは理にかなっています。

親クラスや子クラスなど、関連するクラスを整理するにはどうすればよいですか?

同じディレクトリ内の別々のファイルに置いてください。AnimalとDogの場合は、animals/Animal.jsとanimals/Dog.jsを使います。ディレクトリ構造は、1ファイルにつき1クラスを維持しながら、関連性を示します。この方が、関連するクラスを1つのファイルにまとめるよりもスケールが大きくなります。

クラスを抽出すると小さなファイルがたくさんできる場合は?

少数の大きなファイルよりも、多数の小さなファイルの方が望ましい。最近のIDEは何千ものファイルを効率的に扱います。ファイルシステムのナビゲーションは、大きなファイル内を検索するよりも速い。各クラスがどこにあるのかを正確に把握できるという明快さは、"ファイルが多すぎる "という認識よりも優れています。

まずは無料で体験

コード、クラウド、ランタイムを1つの中央システムでセキュアに。
脆弱性を迅速に発見し、自動的に修正。

クレジットカードは不要。