単一責任の原則(SRP)とは?
AIに“迷わせない”境界の引き方を図とコードで解説!

公開日:
最終更新日:

イントロダクション:AIで速く作れる時代ほど、壊れるのも速い

「検証だけ直したはずなのに、保存や通知まで壊れた」。 AIリファクタリングで起きやすい事故の多くは、1つのクラスに責務が混ざっていることが原因です。

単一責任の原則(SRP)は、人間とAIの両方に“ここまでが担当範囲”を示す境界線です。 特にカプセル化と組み合わせると、触ってよい入口と変更してよい範囲が揃い、事故率が下がります。

1. SRPとは?責任=変更理由で考える

SRP(Single Responsibility Principle)は、 「1つのモジュールは、1つの変更理由だけを持つべき」という原則です。

  • 責任の見分け方:「何の都合で変更するか」を理由で分ける。
  • 実務での言い換え:「このクラスは〇〇だけ担当する」と1文で言える状態を作る。

メソッド数よりも、変更理由が混ざっていないかを見るほうが、SRP判断では実用的です。

2. AI時代にSRPが効く3つの理由

2-1. プロンプトの焦点を絞れる

SRPを守ると、AIへの依頼が短くなります。 「OrderValidatorのメール形式チェックだけ修正して」と書ける状態は、 AIの迷いとハルシネーションを減らす設計そのものです。

2-2. AIリファクタリングの影響範囲を封じ込められる

1クラス1責任なら、AIが内部を大きく書き換えても被害はその責任範囲にとどまります。 SRPは、「Aを直したらBが壊れた」を防ぐ防火壁として効きます。

2-3. AIが実装しやすいモジュール粒度を作れる

神クラス(アンチパターン)化の兆候は、「AIが1回の説明で処理を言い切れない」状態です。 人間が責任で分割し、AIへ小分け発注する流れにすると、品質と速度が安定します。

要するに、設計(分割)は人間、実装(中身)はAIの役割分担がSRPの実務形です。

3. 悪い例:責務が混ざった神クラス(アンチパターン)

検証・保存・通知・表示整形が1つに詰まっている例です。変更理由が複数あり、AI修正で巻き込み事故が起きやすくなります。

Before:OrderManagerが何でも担当している

class OrderManager {
	constructor(db, mailer) {
		this.db = db;
		this.mailer = mailer;
	}

	process(order) {
		// 1) 検証責務
		if (!order.email || !order.items || order.items.length === 0) {
			throw new Error('invalid order');
		}

		// 2) 永続化責務
		const saved = this.db.insert('orders', order);

		// 3) 通知責務
		this.mailer.send(order.email, '注文完了', 'ありがとうございます');

		// 4) 表示整形責務
		return {
			id: saved.id,
			message: `Order #${saved.id} completed`,
			totalLabel: `${saved.total.toLocaleString()}円`
		};
	}
}

// AIに「メール本文だけ敬語にして」と依頼したら、
// process() 全体を触って検証や返却フォーマットまで変えてしまうリスクがある。

壊れ方:通知修正のつもりが、検証条件やレスポンス形式まで巻き込む。 責務境界がないため、影響範囲を事前に縛れません。

4. 良い例:責務ごとに分割して依頼境界を明確化

Validator / Repository / Notifier / Formatter に分けると、AI依頼の単位もそのまま分割できます。

After:1クラス1責任で変更理由を分離

class OrderValidator {
	validate(order) {
		if (!order.email || !order.items || order.items.length === 0) {
			throw new Error('invalid order');
		}
	}
}

class OrderRepository {
	constructor(db) { this.db = db; }
	save(order) { return this.db.insert('orders', order); }
}

class OrderNotifier {
	constructor(mailer) { this.mailer = mailer; }
	sendCompleted(email) { this.mailer.send(email, '注文完了', 'ありがとうございます'); }
}

class OrderPresenter {
	toViewModel(saved) {
		return {
			id: saved.id,
			message: `Order #${saved.id} completed`,
			totalLabel: `${saved.total.toLocaleString()}円`
		};
	}
}

class OrderService {
	constructor(validator, repository, notifier, presenter) {
		this.validator = validator;
		this.repository = repository;
		this.notifier = notifier;
		this.presenter = presenter;
	}

	placeOrder(order) {
		this.validator.validate(order);
		const saved = this.repository.save(order);
		this.notifier.sendCompleted(order.email);
		return this.presenter.toViewModel(saved);
	}
}

AI依頼の例:OrderValidator.validate の電話番号チェックだけ追加」 「OrderRepository.save をトランザクション対応」 といった小分け発注ができ、不要な巻き込みを防げます。

5. 境界の引き方:実務手順

  1. 変更理由を列挙する:「検証」「保存」「通知」「表示整形」など、理由単位で分解する。
  2. 責任ごとに入口を作る:各クラスに1つの主メソッドを置き、役割を1文で説明できる状態にする。
  3. 調整役を薄く置く:Serviceは流れの組み立てだけ担当し、個別ロジックを持たせない。
  4. AI依頼を責任単位で切る:「どのクラスの何だけ触るか」を必ず指定する。
  5. レビューで境界逸脱を止める:依頼外の責任まで変更していないかを最優先で確認する。

6. 図解:責務混在は燃え広がり、分割は防火壁になる

左は1つの箱に責務が混ざった状態、右は責務ごとに箱を分けて影響範囲を局所化した状態です。

責務混在(影響が広がる)

GodClass
  • 検証
  • 保存
  • 通知
  • 整形

1か所をAIが修正すると、同じ箱の別責務まで巻き込みやすい

責務分割(影響を封じる)

Validator
Repository
Notifier
Presenter

修正対象だけAIに渡せるため、被害をその箱の中に閉じ込めやすい

この図で言いたいことはシンプルで、責務が混ざると影響範囲が読めなくなり、責務を分けると修正範囲を制御できるという点です。

7. AIへの発注テンプレ:責任単位で小分け依頼する

悪い依頼(広すぎる)

注文処理をいい感じに改善して。
必要なら設計も直して。

境界がなく、AIが複数責務を同時に触りやすい依頼です。

良い依頼(責任で限定)

対象: OrderValidator.validate のみ
目的: 電話番号の形式チェックを追加
制約: Repository / Notifier / Presenter は変更しない
出力: 変更理由と差分を箇条書きで提示

責任単位で区切ると、AIの提案精度とレビュー効率が上がります。

8. AI生成コードのレビュー観点(短尺)

SRPレビューの最小チェック

[ ] 変更理由が1つに収まっているか
[ ] 依頼対象外のクラスまで差分が広がっていないか
[ ] Serviceに業務ロジックが再流入していないか
[ ] テストも責任単位で追加されているか

9. 分けすぎ注意:SRPのやりすぎを避ける

SRPは「細かく割ること」ではなく「変更理由で分けること」です。理由が同じ処理を分けすぎると、逆に追跡コストが上がります。

過剰分割の短い例

// どれも「メール本文を作る」という同じ変更理由なのに細切れ
class SubjectBuilder {}
class GreetingBuilder {}
class FooterBuilder {}
class SignatureBuilder {}

変更理由が同じなら1モジュールに寄せたほうが見通しは良くなります。

AIワンポイント

AIに依頼する単位は、そのまま責任の単位です。 1つの責任に絞るほど、生成コードの精度とレビュー速度は上がります。

  • 「直す理由が2つあるなら、クラスを分けるサイン」と覚える。
  • 依頼前に「どの責任を直すか」を1行で固定してから投げる。

まとめ:SRPはAIを迷わせない設計ガードレール

  • SRPは「1モジュール1変更理由」で境界を引き、AIへの指示を短く明確にする原則です。
  • 責務分割は、AIリファクタリング時の影響範囲を封じる防火壁になります。
  • 神クラス(アンチパターン)を避けて責任単位で小分け発注すると、品質と速度の両立がしやすくなります。

おまけ:コピペで使えるSRPチェックリスト

  • このクラスの責任を「〇〇だけ担当」と1文で言える。
  • 変更理由が2つ以上あるなら、分割候補として扱っている。
  • AI依頼文に「対象クラス」「触らない範囲」「出力形式」を明記している。
  • 修正後の差分が、対象責任の範囲内に収まっている。
  • Serviceが調整役に留まり、検証・保存・通知を抱え込んでいない。
  • 分割しすぎて、同じ変更理由のクラスが散らばっていない。

このページの著者

もちもちみかん(システムエンジニア)

社内SEとしてグループ企業向けの業務アプリを要件定義〜運用まで一気通貫で担当しています。

経験:Webアプリ/業務システム

得意:PHP・JavaScript・MySQL・CSS

個人実績:フォーム生成基盤クイズ学習プラットフォーム

詳しいプロフィールはこちら!  もちもちみかんのプロフィール

もちもちみかん0系くん
TOPへ

もちもちみかん.comとは


このサイトでは、コーディングがめんどうくさい人向けのお助けツールとして、フォームやCSSをノーコードで生成できる、
 もちもちみかん.forms
 もちもちみかん.css1
 もちもちみかん.css2
と言ったジェネレーターを用意してます。

また、このサイトを通じて、「もちもちみかん」のかわいさを普及したいとかんがえてます!