**Single Responsibility Principle(単一責任の原則)**は、Tom DeMarco の Structured Analysis and Systems Specification と、Meilir Page-Jones の The Practical Guide to Structured Systems Design で説明されている。この原則は次のようなものだ。
クラスを変更する理由は複数存在してはいけない
なぜこうする必要があるのか?
役割が単一なクラスの仕様要求が変化した場合、その変更部分は浮き彫りになり、どのように変化したのかわかりやすい。これは、ほとんどの人が納得するはなしではないだろうか。
しかし、役割が複数あると、その1つ1つが変更理由になってしまう。複数の変更理由によってクラスが変更されると、変更部分がぼやけてしまう。また、ある理由により変更した部分が、他の役割に影響してしまい、連鎖的に変更が必要になるなどといったケースが生じうる。これは もろい設計 にあてはまる。もろい設計がソフトウェア開発にどんな影響を及ぼすかは、前に書いた記事を参照されたい。
役割とはなにか?
「役割=変更理由」と定義している。この判断が非常に難しいケースも多々有る。
変更の理由が変更の理由たるのは、実際に変更の理由が生じた場合だけである
変化の兆候がないのにSRPを含めた原則を適用するのは賢明ではない。原則を適用することを目的にするのはナンセンスである。
結合している役割を見つけそれらを分離する作業は、ソフトウェア設計の本質である
非常に身にしみる言葉。
どのように分離するのか
たとえば、次のようなモデムインターフェースを考える。
interface Modem {
public void dial(String pno);
public void hangup();
public void send(char c);
public char recv();
}
最初の2つのメソッドは接続の開始と終了、すなわち接続管理の機能を持つ。後半の2つのメソッドはメッセージのやりとりに用いる。この2つの役割を分離すべきかどうかは今後このアプリケーションがどのように変更されるか次第。たとえば接続管理の機能が影響を受けるような変更がはいる場合は、send
と recv
のみを呼び出しているクラスをリコンパイル、リロードしなおさなければならない。もっとも単純にこの状態から打破するには、以下のように分離すればよい。ModelImplはその場しのぎではあるが、すべての依存関係が解消しているはずだ。
テスト主導の開発方法に従えば、設計に怪しい兆しが現れる前に、複雑な役割を持ったクラスは分離されるはずだ。なぜならば、複雑な役割をもったクラスのテストを書くのは非常に難しいからだ。しかしそれでもなお、「硬さ」や「もろさ」を感じる場合には Facade
や Proxy
などを使ってリファクタリングするとよいそうだ。
余談
アジャイル開発の奥義を読むまでは、SRPの名前からして、なぜ「クラスの役割は複数存在してはいけない」という原則ではないのかという疑問を持っていた。読んだ結果自分なりには、「変更」という観点に立ったときにはじめて「役割」ごとに分離する必要がでてくるから、「クラスを変更する理由は複数存在してはいけない」と主張しているのではないかと思った。
たしかに役割は1つのほうが、見通しがよいかもしれないが、複雑にはなる。変更がとうてい生じないような場所に関して、無駄に分離してコードを複雑にする必要がないという意味を込めたい場合、たしかに「クラスを変更する理由は複数存在してはいけない」のほうがよい言葉だと感じた。この解釈自体は、完全に自分が読んだ感想なので、なにか間違っているなどの指摘がある方はコメントいただけるとありがたい。