CODE COMPLETE 上 第7章 高品質なルーチーン 7.2ルーチーンレベルでの設計
凝集度
cohesion: 強度とも言う
クラス設計においては凝集度はあまり関係ないが、ルーチーンの観点からは非常に重要。
凝集度とはルーチーン内の処理がどれだけ強く関連しているかを表す。
例えば、Cosine()という関数はルーチーンが一つの処理に徹しているので凝集度が高い。
CosineAndTan()は複数の処理が混ざっており、凝集度が弱い。一つのルーリーンは一つのことだけ処理できるようにするべき。
凝集度による効果
強い凝集度によって得られる効果は信頼性の向上。
凝集度の高いルーチーンのエラー発生率は50%だったのに対し、
凝集度の低いルーチーンのエラー発生率は82%だったという論文がある。
また、凝集度が低く密結合のルーチンのエラー発生率は凝集度が高く疎結合のルーチーンの7倍、修正コストは20倍になると報告されている。
段階別凝集度
- 機能的凝集度 良い 理想
- 情報的凝集度 ↑ 可能な限り小さく保つ
- 連絡的凝集度 ↑ 可能な限り小さく保つ
- 時間的凝集度 ↑ 可能な限り小さく保つ
- 手順的凝集度 ↑ 可能な限り小さく保つ
- 論理的凝集度 ↑ 可能な限り避けるべき
- 暗号的凝集度 悪い やっちゃだめ
上に行くほど良いとされています。
下に該当する関数はリファクタリングして、少しでも上の凝集度に寄せたほうがベター
機能的凝集度
ルーチーンの処理が一つだけ実行する場合。
sin(), GetCustomerName(), EraseFile()とかは一つのことしか実行しないと想像できる。
情報的凝集度
ルーチーンが決まった順番で実行しなければならない処理で構成され、それぞれの段階でデータを共有し、同時に実行したのでは機能を完全に達成できない場合。
例えば、APIでユーザ情報を取得し、描画する関数とか。
連絡的凝集度
ルーチーン内の処理で同じデータを使用するが、それ以外に関連性のない場合。
関数の引数として業務概要データを渡され、関数内で印刷する処理と、概要データを初期化する処理があったとする。
ここでは印刷する処理と、初期化する処理との間の共通点は同じデータを利用するということだけ。
時間的凝集度
タイミング的に近い処理を一つの関数にまとめたもの。
ログを初期化、DB初期化、ページ情報を取得、UIに表示みたいな一連の流れをすべて一つの関数にまとめたもの。
手順的凝集度
ルーチーンの処理が特定の順序で実行される場合。
ファイルのアクセス権を確認してから、書き込むとか。
論理的凝集度
複数の処理が一つのルーチーンに詰め込まれ、渡された制御フラグによっていずれかの処理が選択される場合。
暗号的凝集度
ルーチーン内の処理同士にそれとわかるような関係がない場合。
論理的凝集度、暗号的凝集度の使用は避ける。
低レベルの凝集度の関数を上レベルの凝集度に引き上げることを意識しながら関数を作るのが大事。