メインコンテンツへスキップ
カテゴリ: 原則
種類: ソフトウェア開発の原則
起源: ロバート・C・マーティン、アジャイルソフトウェア開発、2003年
別名: SRP、単一責任の原則
クイックアンサー — 単一責任の原則(SRP)は、各モジュール、クラス、関数が変更される理由を一つだけ持つべきであると主張するソフトウェア設計のガイドラインです。ロバート・C・マーティンが2003年の書籍『アジャイルソフトウェア開発』で明確に述べたSRPは、SOLID原則の一部であり、保守可能でテスト可能、かつ柔軟なソフトウェアシステムを構築するための基盤として機能します。

単一責任の原則とは

単一責任の原則は、ソフトウェアコンポーネントが一つの主要な責任または目的を持つべきであると述べる設計ルールです。クラスやモジュールが複数の責任を持つ場合、一つの責任への変更が意図せず他の責任に影響を与え、保守やテストが困難な脆弱なシステムが生まれます。
「クラスが変更される理由は一つだけでなければならない。」— ロバート・C・マーティン
この原則の名前は、各コンポーネントが一つのことをうまくやるべきというアイデアに由来しています。実際には、関心を別々のモジュールに分離することを意味します。例えば、ユーザー認証を処理するクラスは、表示用のデータフォーマットも行うべきではありません。これらはセキュリティとプレゼンテーションという二つの異なる責任です。表示フォーマットが変更された場合、認証ロジックに触れる必要があってはならず、その逆も同様です。

単一責任の原則を3つの深さで理解する

  • ビギナー: コード内の「変更される理由」を特定してください。ユーザー要件の変更が、複数の目的のためにクラスを修正することを強制する場合、そのクラスはおそらくSRPに違反しています。
  • プラクティショナー: 関数レベルでもSRPを適用してください。関数は一つのことを行うべきです。入力を出力に変換することです。関数の説明に「そして」を追加している自分に気づいた場合、それを分割することを検討してください。
  • アドバンスド: 「変更の軸」テストを使用してください。「ドメインXの要件が変更された場合、このクラスを修正する必要がありますか?」複数のドメインで「はい」の場合、そのクラスは複数の責任を持っています。

起源

単一責任の原則は、ロバート・C・マーティン(「アンクル・ボブ」としても知られる)によって、2003年の書籍『アジャイルソフトウェア開発:原則、パターン、プラクティス』で普及しました。マーティンは、SRPを後にSOLID原則として知られるようになる一連の五つの設計ガイドラインの一部として紹介しました。 この概念自体はマーティンの形式化以前から存在していました。無関係な機能を組み合わせることが保守の悪夢を生むことは、開発者によって長年認識されていたのです。しかし、マーティンがこの原則をテスト可能なルールに結晶化させました。クラスが変更される必要がある理由を数えるのです。一つ以上ある場合、そのクラスはSRPに違反しています。 この原則は、反復的開発と変化する要件への適応能力を強調するより広範なアジャイル運動とともに注目を集めました。アジャイルの文脈では、変更しやすいコードは価値があります。SRPは、無関係な関心間の結合を減らすことで、これを直接可能にします。

要点

1

保守性を向上させる

各コンポーネントが単一の責任を持つ場合、変更は局所化されます。開発者は、要件が進化したときにコードベースの一つの領域のみを理解し、修正する必要があります。
2

テスト性を向上させる

一つの責任を持つコンポーネントは、分離してテストするのが容易です。無関係なロジックや副作用に対処することなく、振る舞いを検証できます。
3

結合を減らす

責任を分離することで、疎結合のモジュールが生まれます。これにより、システムはより柔軟になり、コンポーネントを独立して再利用または置き換えることができます。
4

リファクタリングを容易にする

小さく焦点を絞ったクラスは、安全にリファクタリングするのが容易です。責任が明確に区別されている場合、無関係な機能を壊すリスクは最小限に抑えられます。

応用場面

クラス設計

複数の関心を処理するクラスを分割してください。例えば、ユーザーデータの検証、保存、表示を処理するUserクラスを、三つの焦点を絞ったクラスに分離してください。

関数抽出

大きな関数を小さな関数に分割してください。各関数は一つの変換または操作を実行すべきです。

モジュール構成

明確で単一の目的を持つモジュールにコードを整理してください。レポートモジュールはレポートのみを処理すべきであり、データ取得やフォーマットを処理すべきではありません。

API設計

各エンドポイントが特定の目的を果たすようにAPIを設計してください。複数のユースケースを処理する「万能」エンドポイントの作成を避けてください。

事例

2003年、ある金融サービス会社がトレーディングプラットフォームの大規模な改修に着手しました。元のコードベースには、検証、永続化、通知、レポート、リスク計算を処理する一枚岩の「Trade」クラスがありました。新しい通知チャネルの追加など、一つの側面への変更には、タイトな結合のためシステム全体のテストが必要でした。 チームはSRPを使ってリファクタリングし、Tradeクラスを五つの焦点を絞ったクラスに分割しました。TradeValidator、TradeRepository、TradeNotifier、TradeReporter、RiskCalculatorです。各クラスは単一の責任を持ち、独立して変更できました。 結果は顕著でした。以前は回帰テストの要件のため数日かかっていたバグ修正が、数時間で解決されるようになりました。新しい通知チャネルは、TradeNotifierクラスのみを修正することで追加できるようになりました。チームは、その後の1年間で新機能のデプロイまでの時間が40%削減されたと報告しました。 この事例はSRPの実践的価値を示しています。責任を分割する初期コストは慎重さを必要としますが、保守性と開発速度における長期的な利益は substantial です。

境界と失敗モード

SRPの最も一般的な誤用は、過度に熱心な分割です。メソッドごとにクラスを作成するのは、ナビゲートが困難なシステムを作ることで目的を損ないます。この原則は 凝集 についてです。関連するものをグループ化することであり、クラスサイズを恣意的に最小化することではありません。 もう一つの失敗モードは、責任の誤識別です。「変更される理由」は主観的な場合があります。クレジットカードと銀行振込の両方を処理するPaymentProcessorは二つの責任のように見えるかもしれませんが、両方のビジネスロジックが密接に絡み合っている場合、それらを分割することは複雑さを増す可能性があります。 境界条件。結合による変更のコストが、より多くのコンポーネントを管理するコストを上回る場合にSRPを適用してください。凝集した設計から始め、一つのクラスが複数の無関係な理由で変更されていることに気づいたときにSRPに向けてリファクタリングしてください。

よくある誤解

この原則は、コードの行数をできるだけ少なくすることではありません。一つの責任を完全に処理する500行のクラスは問題ありません。SRPはサイズではなく 凝集 についてです。
クラスが最も一般的な適用例ですが、SRPは関数、モジュール、サービス、アプリケーション全体など、すべてのレベルに適用されます。単一の明確な目的を持つべきです。
一部の開発者は、ファイルを増やしすぎることを恐れてSRPを避けます。しかし、現代のIDEとコード整理の実践により、多くの焦点を絞ったファイルをナビゲートすることは、複数の責任を持つ複雑なクラスを管理するよりも容易です。

関連コンセプト

単一責任の原則は、保守可能なソフトウェアを促進する設計原則のファミリーの一部です。

インターフェース分離の原則

クライアントは使用しないインターフェースに依存することを強制されるべきではありません。ISPは、インターフェースが焦点を絞っていることを保証することでSRPを拡張します。

オープン・クローズドの原則

ソフトウェアエンティティは拡張に対して開いており、修正に対して閉じているべきです。SRPは変更を分離することでOCPをサポートします。

KISSの原則

単純に保て。明確な責任を持つ単純なコードは、理解と保守が容易です。

一言で言うと

クラスが変更される必要がある複数の理由を特定したときにSRPを適用せよ。それを明確な目的を持つ焦点を絞ったコンポーネントに分割せよ。