以前、良い設計を会社に例えた話を体系的にまとまっている情報があったので、それをベースにQiitaに残します。
前提
- 分割可能な大規模システム
課題
- 抽象度が異なる要素が混在するシステム
- イメージとしてはOSI参照モデル
フォース
- レイヤに含まれるコンポネントは変更があっても、他のレイヤ/コンポネントに影響がない
- インタフェースは変更されてはならない
- システムの部分要素は交換が可能である
- システムの一部を交換することで再コンパイルされないことで、変更に対する許容を持たせる
- コンポネントの粒度に標準がない
- コンポネント境界はパフォーマンス低下を生む
- システムを分業できるようにする
解決策
- 解決策は単純で、システムを適当数のレイヤに分割し、それを重ねていくということ
静的側面
- レイヤコンポーネントをCRCカードなどで表現する
- レイヤJがレイヤJ-1を利用するだけ。各レイヤ間でそれ以上の依存関係はない。
- レイヤJが必ずしもユーザに近いわけではない。トップダウンアプローチにおいては、レイヤJはOSI参照モデルにおける第7層、レイヤJ-1は第6層を取る
動的側面
シナリオ1 (トップダウン・アプローチ)
- レイヤNに来たリクエストはそのレイヤだけでは対処できないため、レイヤN-1に支援してもらう
- 最上位層から最下位層、最下位層から最上位層というデータの流れ
シナリオ2(ボトムダウン・アプローチ)
- 動作は最下位層から始める
- リクエストではなく、「通知」されるという
- 通知に対してあ、最上位層まで1対1になる事が多い
- 上位層でコールバックとして実装する
シナリオ3・シナリオ4
- データが途中の層で止まって、再び呼び差しの層まで戻る。
- cacheされるというとわかりやすい感じ。
シナリオ5
- 2以上のレイヤスタックを持つ。リクエスト/通知に対して、レスポンスが別のレイヤを通して返ってくる...など。
実装
- 段階的詳細化という
手順
-
タスクをグループ化してレイヤとするための抽象の基準を定義する
- チェスに例えると、ゲームの基本的単位(ビショップなど)、基本的な動き(ビショップはどう動くか)、中期的な戦術(シチリア攻防)、ゲーム全体の戦略
-
抽象の基準にしたがって抽象レベルの数を決定する。
- レイヤが多すぎるとオーバヘッドが大きくなるぞ
-
レイヤに名前をつけて、タスクを割り振る
- ボトムアップアプローチはドメインの予見力がないと難しいから諸刃の剣である。気をつける。
-
サービスを仕様化する
- レイヤがまたがるコンポーネントはダメゼッタイ
- レイヤが提供する関数やエラータイプなど、言語に組み込んであるものを使用することが望ましい。
- 基盤レイヤは極力数を少なく。また、下位レイヤは上位レイヤよりサービスの数が多くなるはずである。プリミティブだと思ってても、変わることあるんやで。なおさらスリムにしておく。
-
1から4を繰り返す
- 特に1は、1から4をやらないと定義できないことがあるので、やる。
- コンポーネントやサービスからレイヤを割り当てると、絶対無理が出る。
- トップダウン・ボトムアップで繰り返すことで、より洗練される。「ヨーヨー開発」
-
各レイヤのインタフェースを決定する
- 経験則的に、レイヤJ-1はブラックボックスである方が良いらしい。
- ホワイトボックスでも、Reflectionパターンを用いれば良い...らしいが、あまり考えないようにする
-
個々のレイヤを構造化する
- レイヤ...ではなく、より実装に近い要素を思考する。例えば、デザインパターンを当てはめてみるなど。
-
隣接するレイヤ間の通信を仕様化する
- レイヤ間の通信はプッシュ型なのか、プル型なのか。
-
隣接するレイヤの結合を解除する。
- 例えば、下位レイヤは上位レイヤが誰であろうが構わない。コレは一方向による結合の関係になっている。
-
例外処理戦略を設計する。
- 下位レイヤで起こった例外は上位レイヤまで戻さないほうが良い
バリエーション
- リラックスレイヤシステム
- 継承によるレイヤ化
運用例
- 仮想マシン
- 最終的にはbinaryを実行する仮想マシンは、上位レイヤではそれを意識しない
- API
- 頻繁に利用される関数を纏めてあるもの。下位レイヤをカプセル化する役割もある
- 情報システム
結論
利点
- レイヤの再利用
- 標準化の支援
- 依存性の局所化
- 交換容易性
欠点
- 振る舞いの変更がカスケードする
- 下位レイヤの変更は上位レイヤが受け入れられない事が多い。
- イーサネットからATMに変更すると...
- 低い効率性
- オブジェクトの海になることがおおい
- 不必要な作業
- 1つのリクエストを行うために下位レイヤで同じような処理を繰り返すことがある。
- レイヤの粒度を決定することが困難である
- レイヤ数が多ければオーバヘッドが。少なければレイヤパターンの恩恵は受けづらくなる
超参考
- ソフトウェア・アーキテクチャ F.ブッシュマンら著