関心の分離 - 変更理由が違うコードを混ぜない

初級 | 5分 で読める | 2026.06.14

公式ドキュメント

関心の分離(Separation of Concerns)は、変更理由が異なるコードを混ぜないという設計原則です。

入力、業務判断、DB保存、画面表示、ログには別々の変更理由があります。1つの関数に詰め込むと、小さな仕様変更でも全体へ影響します。

混ざった例

async function createOrder(request: Request) {
  const body = await request.json();
  if (body.quantity < 1) throw new Error("Invalid quantity");

  const total = body.price * body.quantity;
  await db.query("INSERT INTO orders ...");
  console.log("order created");

  return new Response(JSON.stringify({ total }));
}

この関数はHTTP、入力検証、価格計算、DB、ログ、応答形式を同時に扱います。

変更理由で分ける

UI・業務ルール・データアクセスを変更理由ごとに分け、明示的なinterfaceで接続する図

class PlaceOrder {
  constructor(private readonly orders: OrderRepository) {}

  async execute(input: PlaceOrderInput) {
    const order = Order.place(input);
    await this.orders.save(order);
    return order;
  }
}

ControllerはHTTPとの変換、Orderは業務ルール、Repositoryは永続化を担当します。DB変更はRepository、価格ルール変更はDomainへ閉じ込めやすくなります。

凝集度と結合度

  • 凝集度: 同じ目的の処理が1か所へまとまっている度合い
  • 結合度: ある部品が別の部品の詳細へ依存する度合い

良い分離は、同じ変更理由をまとめて凝集度を高め、明示的なinterfaceで結合度を下げます。ファイルを分けても、互いの内部状態へ直接触れていれば分離できていません。

分けすぎを避ける

1行ごとに関数やclassを作ることが目的ではありません。分割しすぎると、処理を追うために多くのファイルを移動することになります。

次の質問で境界を探します。

  1. このコードは何のために変わるか
  2. 一緒に変わる処理はまとまっているか
  3. 別の理由で変わる処理が混ざっていないか
  4. 境界を越える値と依存関係が明確か
  5. 分割によって変更やテストが実際に簡単になるか

重複コードがあるだけで、すぐ共通化もしません。見た目が同じでも変更理由が異なる処理をまとめると、片方の変更がもう片方を壊します。

まとめ

  • 関心とはコードの目的や変更理由
  • 変更理由が異なる処理を境界で分ける
  • 同じ目的をまとめ、内部詳細への依存を減らす
  • ファイル数ではなく、変更とテストが局所化したかで判断する
  • 分けすぎや早すぎる共通化も避ける

層として分ける例はレイヤードアーキテクチャ、依存方向まで含む構成はクリーンアーキテクチャを参照してください。

参考リソース

← 一覧に戻る
PR
PR
PR
PR