single-responsibility-principle について
single-responsibility-principleは、各クラス、モジュール、関数の責任を一つに保つためのコーディングスキルです。機能を分割するタイミングを見極め、無関係な責任の追加を避ける方法を示します。
主な機能
- 01単一責任の原則の適用
- 02複数の変更理由の検出
- 03肥大化したクラスの兆候の特定
- 04責任が明確なコンポーネントの抽出
活用シーン
- 01新しいクラスやモジュールの設計
- 02無関係なメソッドを持つクラスのレビュー
- 03既存の巨大クラスのリファクタリング
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yanko-belov/ code-craft --skill single-responsibility-principleインストール後、Claude Code で/single-responsibility-principleを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
user-system/AnalyticsService.tsAuthenticationService.tsindex.tsNotificationService.tsProfileService.ts詳細
単一責任の原則(SRP)
概要
クラスが変更される理由は、1つだけであるべきです。
すべてのモジュール、クラス、関数は、機能の単一の部分に責任を持つべきです。クラスの役割を説明するのに「そして」が必要なら、責任を持ちすぎています。
使用する場面
- 新しいクラス、モジュール、サービスを作成するとき
- 既存のクラスにメソッドを追加するとき
- 「複数のことを行う」コードをレビューするとき
- 「ここに追加するだけでいい」と感じたとき
絶対のルール
NEVER add functionality that introduces a second reason to change.
例外はありません:
- 「このほうが速いから」は理由になりません
- 「メソッドをもう1つ追加するだけだから」は理由になりません
- 「リファクタリングには時間がかかりすぎるから」は理由になりません
- 「テックリードにそう言われたから」は理由になりません
- 「すでに本番環境で稼働しているから」は理由になりません
プレッシャーの下で SRP に違反することも、やはり SRP 違反です。
検出方法:「そして」テスト
クラスを1文で説明してください。「そして」が含まれていたら、分割しましょう。
| 説明 | 判定 |
|---|---|
| 「ユーザー認証を処理する」 | ✅ 単一の責任 |
| 「認証を処理し、そしてメールを送信する」 | ❌ 2つの責任 |
| 「注文を管理し、そして決済を処理し、そして在庫を追跡する」 | ❌ 3つの責任 |
検出方法:変更する理由
このクラスを変更する必要が生じる理由を列挙してください:
// ❌ BAD: UserManager - 4 reasons to change
class UserManager {
login() {} // Auth logic changes
updateProfile() {} // Profile requirements change
sendEmail() {} // Email provider changes
trackAnalytics() {} // Analytics requirements change
}
// ✅ GOOD: Split by responsibility
class AuthService { login() {} }
class ProfileService { updateProfile() {} }
class NotificationService { sendEmail() {} }
class AnalyticsService { track() {} }
プレッシャーに抗うための手順
SRP に違反するようプレッシャーを受けた場合は、次の手順に従ってください:
1. 時間的プレッシャー
「とにかくすぐに動くようにして」
対応: 神クラスを作るのにかかる時間は、責務を絞ったクラスを作る時間と変わりません。「手っ取り早い」解決策は技術的負債を生み、後々その10倍のコストがかかります。
行動: クラスを分けて作成しましょう。時間は余計にかかりません。
2. サンクコストによるプレッシャー
「そのクラスはもうあるんだから、そこに追加するだけでいい」
対応: 肥大化したクラスに追加すれば、さらに悪化します。すでに間違っているからといって、もっと間違った状態にしてよい理由にはなりません。
行動: 責務を絞った新しいクラスを作成しましょう。時間が許せば、既存のクラスをリファクタリングしてください。
3. 権限によるプレッシャー
「テックリードから、全部1つのクラスに入れるよう言われた」
対応: 根拠を示して、敬意を持って異議を唱えましょう。却下された場合は、懸念を記録して従います。ただし、神クラスを黙って作ることは決してしないでください。
行動:
"I'd recommend splitting this because [specific reason].
If we keep it together, we'll likely need to refactor when [consequence].
Should I proceed with the split, or document this as tech debt?"
4. スコープクリープ
「そこを作業するついでに、Xも追加して」
対応: 新しい機能は、新しいクラス(または、適切な既存のクラス)に追加します。
行動: 「X は独自のサービスにするべきです。XService を作成します。」
危険信号 — 作業を止めて再検討してください
以下のいずれかに気づいたら、SRP に違反しようとしています:
- クラスの中核的な目的と関係のないメソッドを追加している
- クラスのファイルが200行を超えている
- クラスにパブリックメソッドが5~7個を超えてある
- クラス内を移動するためにセクションコメントが必要
- 無関係な機能を編集するために、複数の開発者がこのクラスを変更する
- クラス名に具体的なドメインを示す語がなく、「Manager」「Handler」「Processor」「Service」が含まれている
どれも、クラスを分割すべきという意味です。
既存の違反をリファクタリングする
既存の神クラスに遭遇した場合:
- 悪化させない — 責任をこれ以上追加しない
- 触るついでに切り出す — 変更時に、作業対象の部分を切り出す
- 負債を記録する — 今すぐリファクタリングできない場合は、チケットを作成する
// Found: OrderService with 500 lines handling orders, payments, inventory, emails
// ❌ WRONG: Add shipping logic to OrderService
// ✅ RIGHT: Create ShippingService, note that OrderService needs refactoring
よくある正当化(どれも不適切)
| 言い訳 | 実態 |
|---|---|
| 「1つのクラスに入れたほうが速い」 | 速くはありません。どちらの方法でも入力するコードは同じです。 |
| 「小さなクラスは過剰設計だ」 | 小さなクラスこそ、適切な設計です。 |
| 「メソッドをもう1つ追加するだけだ」 | そうして、いつも神クラスが生まれます。 |
| 「あとでリファクタリングできる」 | しないでしょう。技術的負債は積み重なります。 |
| 「クラスはすでに大きい」 | 続ける理由ではなく、止める理由です。 |
| 「関連する機能だ」 | 関連していることと、同じ責任であることは別です。 |
| 「セクションコメントがあれば移動しやすい」 | 移動しやすくする必要があるなら、クラスが大きすぎます。 |
クイックリファレンス
| 症状 | 対応 |
|---|---|
| クラスが X と Y の両方を行う | XService と YService に分割する |
| 無関係なメソッドを追加する | 新しいクラスを作成する |
| ファイルが 200 行を超える | 切り出せる箇所を探す |
| 変更する理由が複数ある | 理由ごとにクラスを 1 つ作る |
| 「Manager/Handler/Processor」という名前 | より具体的な名前にするか、分割する |
要点
クラスは 1 つ。責務は 1 つ。変更する理由は 1 つ。
これに反するよう迫られたら、異議を唱えるか、記録に残すか、いずれにせよ適切な構造を作成してください。
時間的なプレッシャー、既存のコード、権限者からの要求にかかわらず、ゴッドクラスは決して正解ではありません。