一般的に普及してるレイヤードパターンの設計はソフトウェア設計として破綻しているよという話
medium.com
理由
- レイヤーというのは何らかを抽象化したものをさすが、レイヤー化することが抽象化したことにはならない
- 一般的に普及してるレイヤー化は機能依存していて、テスト容易性も可読性も拡張性も下げている
一般的に普及してるレイヤー化というのは、例えば以下のようなレイヤーに分けることをいっている
- プレゼンテーション層
- アプリケーション層
- データ層
OSIの7階層との違い
抽象度は、大きな処理の流れを簡潔に表したものが「抽象度が高く」、より具体的な処理の流れを表したものは「抽象度が低い」
OSIの7階層はその定義通りに抽象度で階層わけされている
一般的なレイヤー化をもう一度見ると、このように階層わけされているわけではない
プレゼンテーション層 は アプリケーション層 の大きな処理の流れを関係に表したものではないからだ(他の層もしかり)
つまり、「レイヤー」という名前がついているが「レイヤー」じゃない残念な感じになっているよねと
なんて呼ぶ?
OSIの7階層よりも、レイヤードデザインパターンの「レイヤー」の方が市民権を得ているので、OSIの7階層のようなレイヤーに別の言い方をしたい
そこでこれを「Strata」と呼ぶことにする
関数型プログラミングではすでに「Stratified Design」という階層化の名前が使われており、そこから引用したとのこと
一般的なレイヤー分けの依存関係
一般的なレイヤー分けは上位レイヤーに依存している
これをよく制御の反転や依存関係の反転のような原則を用いたりして、設計上は抽象レイヤーのみに依存しているように見えるが、実装ではモックや依存注入などのツールが必要で完璧には覆い隠せていないことが多い
また、依存注入などを使うと全体が見えなくなるので迷子になりがち
コードで表すとこうなり
public static void Main(string[] args) {
var data = new DataLayer();
var business = new BusinessLayer(data);
var presentation = new PresentationLayer(business);
presentation.Show();
}
それぞれのテストに依存するレイヤーのオブジェクトが必要になる
Stratified Design
Stratified Designでは以下のように実装する
public static void Main(string[] args) {
var data = new Data();
var business = new Business();
var presentation = new Presentation();
var app = new App(presentation, business, data);
app.Run();
}
各レイヤーはどこにも依存しておらず、最後のnew App
でアプリケーションの最上位層を表している
中を覗くと
public void Run() {
var text = presentation.Ask_for_text();
var n = Count_words(text);
presentation.Display_word_count(n);
}
このようになっており、プロセス全体の概要を把握できるようになっている
さらに、Count_words
や、Ask_for_text
、Display_word_count
の詳細を知らなくても実行できるようになっている
そして、詳細をみても同じような構造になっている(さらに抽象化された関数があり入れ子になっている)
図にするとこう
ノードの関数は詳細な関数を「統合」しているだけで、リーフの関数に「ロジック」がある状態になっている
これを統合操作分離原則 (Integration Operation Segregation Principle: IOSP)というらしい