設計:ソフトウェア実装前の最後の作業
「オブジェクト指向でなぜつくるのか-第2版-」の第9章では、プログラミングの前段階の作業として、業務分析、要求定義、設計の3つが必要であると説明されていました。
業務分析で現実世界の業務を整理し、要求定義でコンピュータが肩代わりする仕事の範囲を定義した後に、それをソフトウェアでどう実現するかを決めるのが設計の作業になります。
設計の進め方やノウハウは実行環境やアプリケーションの性質ごとにバリエーションがあるため、それらに依存する部分を対象外とした一般的な考え方が、「オブジェクト指向でなぜつくるのか-第2版-」の第10章にて紹介されています。
この記事のゴール
- 保守性と再利用性を向上させる設計に必要な3つの考え方を理解する
保守性と再利用性を向上させる3つの考え方
設計で重要なことは要求定義どおりに正しく動かすことですが、その次に重要なことはソフトウェアの保守性と再利用性を向上させることです。なぜなら、以前とは違ってアプリケーションの規模が増大し、ソフトウェアの寿命も長くなったからです。
オブジェクト指向プログラミングのクラスやポリモーフィズム、継承といった仕組みは、ソフトウェアの保守性と再利用性を向上させるためのものですが、うまく使いこなさなければその効果は望めません。
そこで、保守性と再利用性を向上を目的とした設計の指針として、以下3つの目標を掲げると良いようです。
- 重複を排除する
- 部品の独立性を高める
- 依存関係を循環させない
重複を排除する
重複する機能があるだけで、ソフトウェアの規模が大きくなるため、テストが大変になりますし、理解もしづらくなります。さらには、変更時の修正漏れも深刻な問題として挙げられます。
そういった問題を発生させないためにも、設計の段階で機能の重複が起きないように気をつける必要もありますし、安易に「コピー&ペーストプログラミング」を行わないことも対策のひとつとなります。
そもそもこれまでの歴史で登場してきた サブルーチン やオブジェクト志向プログラミングの ポリモーフィズム ・ 継承 などは、コードの重複を削減するための仕組みでもあります。しっかりと先人たちの知恵を受け継いで、同じ苦しみを味あわないようにしたいところですね。
部品の独立性を高める
ソフトウェアの中身を理解するためには、まずはコードを読まなければなりませんが、数万行、数十万行に及ぶコードを全て理解することは非常に困難です。
こうした複雑なソフトウェアを理解しやすくするためには、まず最初のステップとしてコードを「分割する」ことが挙げられています。ソフトウェアを一枚岩として作るのではなく、複数のサブシステムや部品に分割して構成するということです。
さらに次のステップとして、分割したサブシステムや部品の 独立性を高める ことが挙げられています。独立性が高まれば、修正時の変更箇所の特定が容易になりますし、他機能への影響も最小限に抑えることができます。
こういった独立性を測る2つの尺度として、 凝集度 と 結合度 というものがあります。
-
凝集度
- 個々の部品の機能のまとまり度合いを評価する尺度
- 凝集度が強いほど良い設計と言える
-
結合度
- 部品間の結びつきの度合いを評価する尺度
- 結合度が弱いほど良い設計と言える
オブジェクト指向においては、1つのクラスに定義する機能の意味的なまとまりを強くし、クラス間のやりとりを少なくすることで良い設計ができるということになります。
依存関係を循環させない
ここでいう依存関係とは、ある部品が別の部品を利用していることを意味します。下の図をみてください。
この図は部品Aは部品Bに、部品Bは部品Cに、さらに部品Cは部品Aに依存していることを示しています。依存関係が循環していますね。
これは、部品Aは部品Bが、部品Bは部品Cが、部品Cは部品Aがなければ機能しないことを意味しているので、部品Aだけが必要なのときに部品Bと部品Cまでも必要になってしまいます。これでは再利用性が著しく低下してしまいます。
また、部品Aに変更を加えるときに、部品Aに依存している部品Cへの影響を調べなければなりません。さらにもしその影響により部品Cに変更が必要になった際は、部品Cに依存している部品Bの影響も調べなければならなくなります。これでは保守性が著しく低下してしまいます。
つまり、こういった依存関係の循環をなくせば、再利用性と保守性が向上することになります。
まとめ
保守性と再利用性を向上させる設計をするには、以下3つの考え方が重要である。
- 重複を排除する
- 重複を排除することで部品やコードが少なくなる。
- 結果テストが簡単になったり、機能変更時の修正漏れがなくなる。
- 部品の独立性を高める
- 独立性を高めれば、修正時の変更箇所の特定が容易になる。
- さらに他機能への影響も最小限に抑えられる。
- 依存関係を循環させない
- 依存関係の循環させないことで、個々の部品を切り出して使用できる。
- さらに他機能への影響を最小限に抑えられる。
所感
どれも基本的なことで当たり前だなと思う反面、気を抜くととやってしまいがちなことが書かれているという印象でした。
完全にコードが重複していなくても、似たようなロジックが書かれることもよくないなと、経験上思いました。似たようなロジックが複数あるときは、しばしば修正が漏れてしまいがちで、結果的にシステムの不具合を引き起こす原因になります。
また部品の独立性を高める方法として、 「private メソッドをたくさん作る」 ということも挙げられていて、個人的に忘れがちだなと思いました。
クラス内でした使われていないにも関わらず、 public なメソッドを作ってしまうと、それだけで「別クラスで呼ばれているのか?」と考慮しなくてはならなくなりますよね。ちょっと意識するだけで、その先の開発で起こりうる考え事を減らすことができるのだなと実感しました。