

DDDをベースに web
アプリケーションの設計を進めていて、DBの停止状態（メンテナンス等による一時休止）をどのレイヤーでチェックし、停止時/非停止時で処理を分岐させたら良いか悩んでいます。

私の理解だと、「DBMSの稼働状態、また状態による処理の分岐」はアプリケーションレイヤーが持つべき責務で、これらの処理はコントローラー等に実装するのがいいと思ってます。ただ、実際にDBの状態をチェックし処理を分岐させる必要があるのは、リポジトリー経由でモデルを生成/保存するタイミングであり、リポジトリーを呼び出す際にコントローラー側でいちいち
DB の状態をチェックするというのは、DRY の観点からも良くないと感じています。リポジトリーに「DB
の状態をチェックせずに呼び出してはいけない」という事前条件を付与するのは、かなり危険です。

この観点から、DataBase の抽象クラスをインフラアーキテクチャレイヤーに作成し、リポジトリーに渡す設計を考えました。Database
の具象クラスはアプリケーションレイヤーに実装します。

以下 PHP を例にとって実装例を挙げます。

インフラアーキテクチャレイヤー

[code]

    namespace sample\infra;
    abstract class Database {
      public function __construct() {
        if($this->is_maintenance()) {
          throw new \Exception;
        }
      }
    
      abstract protected function is_maintenance();
    }
    
[/code]

アプリケーションレイヤー

[code]

    namespace sample\application;
    class HogeMasterDatabase extends \sample\infra\Database {
      protected function is_maintenance() { /* */ }
    }
    class HogeSlaveDatabase extends \sample\infra\Database {
      protected function is_maintenance() { /* */ }
    }
    
    class HogeController {
      public function read() {
        $slave = new HogeSlaveDatabase; //ここの例外はRouter等でキャッチする
    
        $repository = new \sample\domain\HogeRepository($slave);
        $hoge = $repository->fetch($id);
    
        // カウンターをインクリメント
        try {
          $master = new HogeMasterDatabase;
          $repository = new \sample\domain\HogeRepository($master);
          $factory = new HogeFactory($hoge);
          $factory->setCounter(++$hoge->getCounter());
          $repository->update($factory->create());
        } catch (\Exception $e) {
          // masterがメンテナンスの時は無視する
        } 
      }
    }
    
[/code]

ドメインレイヤー

[code]

    namespace sample\domain;
    class Hoge {
      private $counter;
    
      public function getCounter() {
        return $this->counter;
      }
    }
    class HogeRepository {
    private $db;
    
      public function __construct(\sample\infra\Database $db) {
        $this->db = $db;
      }
    
      public function fetch($id) { }
      public function update(Hoge $model) { }
    }
    
[/code]

こういったケースでは、どう設計&実装すべきでしょうか。アドバイスを頂けると嬉しいです。


CC BY-SA 3.0
2015-02-27T03:30:41.917
7186
2015-11-09T02:57:47.357
2015-03-05T06:13:50.570
8583
question
php ドメイン駆動設計
DDDにおいてDBの停止状態をチェックするのはどのレイヤーか


DBの例外等をどのレイヤーで扱うのかは、アプリケーションのポリシーにもよりますが、少なくともドメインレイヤーのリポジトリで直接管理することはないでしょう。何らかのユースケースにおいて管理されることになると思います。このユースケースがどのレイヤーに属するものなのかは、ここでは問いません。

データベースの状態については、おそらくアプリケーション全体にわたって共通した振る舞いが必要になると思います。質問に書かれているような個々のコントローラに条件分岐を書くアプローチ以外に、さまざまな選択肢があります。

  * 横断的関心事としてAOPで実装する (参考 [Ray.Aop](https://github.com/ray-di/Ray.Aop/blob/develop-2/README.ja.md))
  * テンプレートメソッド（デザインパターン）を基底クラスに用意して使う
  * フレームワークのコントローラ実行フローに組み込む

質問に書かれているコードのように、master/slaveごとの判定等ある程度の手続きがある場合は2つ目のテンプレートメソッドが分かりやすいかと思います。

最近のPHPではClosureが使えますので、DB状態に依存するような処理をClosureで定義して渡すようなやり方も可能です。似たようなことをやる例として、フレームワークLaravelのトランザクションブロックのための仕組みが参考になるかと思います。

  * [Database Transactions](http://laravel.com/docs/5.0/database#database-transactions)
  * [framework/Connection.php at 5.0 · laravel/framework](https://github.com/laravel/framework/blob/5.0/src/Illuminate/Database/Connection.php#L438)

P.S. この内容は、ドメイン駆動設計とは関係無く、アプリケーションまたはフレームワークの設計一般に関する質問かと思います。


CC BY-SA 3.0
2015-03-08T08:36:43.023
7607
2015-03-08T14:45:32.083
2015-03-08T14:45:32.083
5444
5444
7186
answer


DDDを実践するに当たって、まず実装の詳細から入りすぎているように思います。DDDでは、設計や実装の詳細よりまず「ユビキタス言語」を語ってみることが大事です。

「DBの停止状態」という状況に対して、ビジネスドメインのユビキタス言語はどういったことを語るのでしょうか？
DBが停止するということは、ドメインで行われている行為に何らかの影響が出るはずですが、その影響をユビキタス言語はどう語るのでしょうか？

DBの停止はユビキタス言語の中では全く予期していない出来事で、そのときの振る舞いは完全に未定義でしょうか？
だとしたら、それはドメインの関心事ではないので、インフラ層でチェックしてシステムエラーをアプリケーション層に投げればいいでしょう。

もしユビキタス言語がその状況について語る何らかの言葉を持っているなら、それはドメイン層の関心事なのでドメインモデルの中に組み込むべきです。


CC BY-SA 3.0
2015-03-12T01:03:49.513
7808
2015-03-12T01:03:49.513
244
7186
answer


リポジトリの実装クラス内でチェックすればよいとおもいます。レイヤーとしてはインフラストラクチャになると思います。


CC BY-SA 3.0
2015-11-09T02:57:47.357
18557
2015-11-09T02:57:47.357
13179
7186
answer