Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
11
Help us understand the problem. What is going on with this article?

More than 3 years have passed since last update.

@koriym

BEAR.SundayとDDD

アプリケーション設計

マニュアルのチュートリアルの記事などではリソースのリクエストメソッドで直接SQLを操作していますが、実際にはアプリケーションをどのように設計、実装するかはアプリケーション開発者の仕事です。

この記事はコンテキスト境界、ディレクトリ構成について考えるのフォローアップ記事で、BEAR.SundayでDDDを導入するときにどのような構成になるかを考えます。

PHP DDD Cargo Sample

PHP DDD Cargo Sampleとはエリック・エヴァンスのドメイン駆動設計で紹介されているパターンを実際に使用して作られたPHPのサンプルアプリケーションです。

このサンプルはPSR-7とPSR-15を使ったzend-expressive + Doctrine ORMで構成されていますが、これをBEAR.Sundayで利用する事を想定します。

DDD Compoentsフォルダ

まず、アプリケーションのトップディレクトリcargograph-traversalというDDDコンポーネントのフォルダを設置します。それぞれのコンポーネントはsrc/tests/ディレクトリを持っていてそれぞれプロジェクトとして独立しています。PHPの名前空間も独自に保持します。

image.png

autoloadのためにcomposer.jsonを編集します。

composer.json
"autoload": {
        "psr-4": {
            "MyVendor\\MyProject\\": "src/",
            "Codeliner\\CargoBackend\\"  : "ddd/cargo/src",
            "Codeliner\\GraphTraversalBackend\\"  : "ddd/graph-traversal/src"
        }
    }

後述するように独立したパッケージにしてもいいでしょう。

DDD src

image.png

DDDコンポーンネントのsrcフォルダは上記のようにディレクトリが分けられています。詳細はPHP DDD Cargo Sampleをご覧ください。

DDDコンポーンネントは原則、フレームワークアグノスティック、つまりBEAR.Sundayの特定の機能に依存しないように作成します。フレームワークの機能に依存してDDDを構築するのではなく、DDDコンポーネントに依存してBEAR.Sundayフレームワークを利用します。

UIレイヤー

image.png

サンプルのようにUIを全てJSで行えばBEAR.SundayはもちろんPHPからの依存をなくすことも出来ます。詳しくはJavascript UIをご覧ください。

HTTP Action

Cargoのルートを取得するHTTP Actionのコードは以下のようなものです。

final class GetCargo implements MiddlewareInterface
{
    /**
     * @var BookingService
     */
    private $bookingService;

    public function __construct(BookingService $bookingService)
    {
        $this->bookingService = $bookingService;
    }

    public function process(ServerRequestInterface $request, DelegateInterface $delegate): ResponseInterface
    {
        if (null === $trackingId = $request->getAttribute('trackingId')) {
            return new EmptyResponse(404);
        }

        try {
            $cargoRoutingDto = $this->bookingService->loadCargoForRouting($trackingId);

            return new JsonResponse($cargoRoutingDto->getArrayCopy());
        } catch (CargoNotFoundException $e) {
            return new EmptyResponse(404);
        }
    }
}

このアクションをBEAR.Sundayのリソースにインジェクトして利用することもできますが、Resourceのメソッドで同様の記述をする事も検討してみましょう。

上記のPSR-7/15対応のHTTP ActionはBEAR.Sundayでは以下のようになります。

final class Cargo extends ResourceObject
{
    /**
     * @var BookingService
     */
    private $bookingService;

    public function __construct(BookingService $bookingService)
    {
        $this->bookingService = $bookingService;
    }

    public function onGet(string $trackingId = null): ResourceObject
    {
        if (! $trackingId) {
            $this->code = 404;

            return $this;
        }
        try {
            $cargoRoutingDto = $this->bookingService->loadCargoForRouting($trackingId);
            $this->body = $cargoRoutingDto->getArrayCopy();

            return $this;
        } catch (CargoNotFoundException $e) {
            $this->code = 404;

            return $this;
        }
    }
}

また第3の選択肢としてBEAR.SundayをPSR7のmiddlewareでそのまま動作させることもできます。

BEAR.Sundayネイティブの記述はAPIのドキュメントの自動生成や優れたリソースキャッシュを使うか、他のフレームワークとの協調を重視してPSR対応にするかはトレードオフで、アプリケーション開発者の選択です。

終わりに

この記事で紹介したのはアプリケーションから可能な限りフレームワーク依存を取り除き、フレームワークのバージョンや密結合したコンポーネントからロックされないDDDのアプリケーションの可能性です。「BEAR.SundayでDDD」 ..ではありません。

dddフォルダ内のアプリケーションは独立したpackageとしてprivateなpackagistレポジトリに登録して複数のアプリケーション(例えば管理画面)から利用可能でしょう。分割されたアプリケーションはユースケースに応じて組み合わせるようなこともできるし、それぞれバージョンを持たして内部の互換性を担保しつつ疎にすることが出来ます。

"分散型の大きな泥だんご"になることなく、アプリケーションを分割可能にし、モノリスの良さを持ちつつ、マイクロサービスが持つメリットをかなりの程度を享受できるような構成が可能ではないでしょうか。

そういう大きな希望で今年のカレンダーを締めくくりたいと思います。作成してくれたkuma_nanaさん、執筆してくれたkaliboraさん、kawanamiyuuさん、記事を読んでくれた皆さん、BEAR.Sundayをいつも使ってくれている国内外の開発者の皆さん、今年もありがとうございました。

image.png

大好きなクマのぬいぐるみの「日曜日」は、なんにもしゃべらないし、だきついてもこない。ぼくのことをどう思ってるんだろう…

アクセル・ハッケ - クマの名前は日曜日

11
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
11
Help us understand the problem. What is going on with this article?