見出し画像

Patterns of Enterprise Application Architecture から学ぶ - Chapter 8

はじめに

こんにちは。ソフトウェアエンジニアのttokutakeと申します。

これはPatterns of Enterprise Application Architecureという本を読んでみて、自分が理解した内容を要約して書き起こしていくシリーズの8回目の記事です。今回でこのシリーズは最終回です。

間違っている部分などがありましたら、ご指摘いただけますと幸いです。

注意事項

  • 対象読者は主にWebアプリケーションのエンジニアです。

  • 本の内容をそのまま記載しているわけではありません。

    • 内容のすべてを記載すると情報量が多いように感じたので、省略している部分がそれなりにあります。

    • 自分自身の見解を述べている箇所もあります。

Chapter 8. Putting It All Together

この章では今までの内容を一気におさらいしていきます。

この本を通じていろいろなアドバイスがありましたが、これらのアドバイスは危険な贈り物であることをまずは理解しておきましょう。自分の直面する状況を解決するような銀の弾丸は存在しません。これらのアドバイスは自分の思考を刺激してくれるものであると考えるのが良いでしょう。

最終的には自分自身でアーキテクチャーを決定する必要があります。幸いなことの一つとして、その決定は永遠に刻まれるものではありません。アーキテクチャーの変更は難しく、そのコストも決して安くはないものですが、不可能ではありません。アーキテクチャーの変更時には以下の3つのテクニックがとても強力な味方となってくれます。

ドメインレイヤー

初めにすることは、ドメインロジックに対してどのアプローチを用いるかを決定することです。以下の3つをメインに考えましょう。

  • Transaction Script

  • Table Module

  • Domain Model

どれを用いるかはドメインロジックの複雑さによりますが、定量的な判断基準があるわけではありません。

Transction Scriptは最も単純なアプローチで、手続き的にドメインロジックを書くだけなので多くの人には取っつきやすいものです。その代わり複雑なビジネスロジックを扱うのには不向きです。特にコードの重複を発生させやすいという欠点が目立ちます。

Domain ModelはTransaction Scriptの対極に位置します。オブジェクト指向に慣れているのであれば、たとえシンプルなアプリケーションでもDomain Modelを用いることに苦労はありません。複雑なドメインロジックを一番うまく扱えるのはこのアプローチですが、学習に時間がかかるという欠点があります。またリレーショナルデータベースとの相性はよくありません。これについてはO/Rマッパーツールを用いて対応すると良いです。

Table Moduleは2つの方法の中間に位置します。Record Setを用いることを前提としてるため、リレーショナルデータベースとの相性は良いです。Record Setの扱いに特化したツールを備えている環境であれば、この方法を選択すると良いです。( .NET などの環境が該当するらしいのですが、現在もそうであるのかどうかは私自身が.NETに詳しくないため不明です。)

ドメインロジックに対するアプローチの決定は、アーキテクチャーの決定において一番重要です。より詳しい内容は こちら のブログ記事をご参照ください。

データソースレイヤー

まずはTransaction Scriptを選んだ場合についてです。直接データベースのロジックをTransaction Scriptに書いても良いですが、基本的には避けることをオススメします。Row Data GatewayかTable Data Gatewayを使うと良いでしょう。

どちらを選ぶかは開発する環境によります。Row Data Gatewayはレコードとオブジェクトが1対1に対応します。そのためアクセサーなどのインターフェースが明示的になるという利点があります。Table Data Gatewayはアクセサーなどの実装をしないのでコーディングする量は少なくて済むという利点があります。ただし、Record Setの構造に依存した暗黙的なインターフェースとなってしまいます。

データベーストランザクションについては簡単に扱うことができます。スクリプトがそのままデータベーストランザクションの範囲と対応するので、単にトランザクションで囲うだけで済みます。ただし、それでもLost UpdateやInconsistent Readを防げないケースがある場合は、Optimistic Offline Lockを実装する必要があります。

Table Moduleについては必然的にTable Data Gatewayを使うことになります。なぜならTable Moduleを用いるのは、そもそもRecord Setを扱うのに適した環境であるからです。

最後にDomain Modelを選んだ場合についてです。ビジネスロジックが比較的単純な場合はActive Recordが良いです。ドメインレイヤーとデータソースレイヤーを少し疎結合にしたいと思うならRow Data GatewayやTable Data Gatewayを使っても良いです。さらに複雑なビジネスロジックを扱うような場合はData Mapperがおススメです。その場合、並行処理の管理にはUnit of Workを用いることが推奨されます。

おまけとして、ストアドプロシージャーについて言及しておきます。ストアドプロシージャーを利用するのは基本的にはあまりオススメされていません。プログラムのソースコードと比較して管理が面倒になる可能性があり、複雑なロジックを管理するためのメカニズムが用意されていない場合が多いからです。またベンダーロックインされるので移植性もいまいちです。

データベースと同じプロセス上で実行されるので処理が速いという利点はありますが、パフォーマンスにおいて問題がない限りはストアドプロシージャーの利用は避けるとよさそうです。

データソースレイヤーについてのより詳しい内容は こちら のブログ記事をご参照ください。また、並行処理についてのより詳しい内容は こちら のブログ記事をご参照ください。

プレゼンテーションレイヤー

この本でいろいろ紹介はされていたのですが、プレゼンテーションレイヤーに関しては進化の激しい分野なので、直接的に参考になる部分は多くないと感じました。

私個人の意見としては、 Ruby on Rails のようなWebフレームワークや React のようなUIライブラリーなどを使って学ぶ中で、自分なりにパターンを把握していくのがこの分野においては良いのではないかと思います。

本に書かれている内容が気になる方は こちら のブログ記事をご参照ください。

Webサービス

アプリケーションを複数のWebサービスに分けることについてですが、それには慎重になる必要があります。Webサービスはアプリケーションのインテグレーションを加速させることは事実ですが、アプリケーションの構築を加速させるわけではありません。

必要がない限りは複数のWebサービスに分けるのは避けると良いです。もし必要になった場合は、Remote Facadeは複雑性を緩和する味方となってくれます。また同期的なRPCだけではなく、非同期メッセージングを用いることも検討すると良いです。

より詳しい内容は こちら のブログ記事をご参照ください。

ここについては最後に自分の意見を言うと、現在ではマイクロサービスアーキテクチャなどが台頭してきているように、複数のWebサービスに分けることが容易になるようなサービスやプラットフォームも登場しています。それでも複数に分けることが簡単だとはとても言えませんが…

巨大なモノリスアプリケーションの開発はそれなりに欠点も多くはらんでいます。特にCI/CDに時間がかかるという欠点は開発スピードを遅くする典型的な例です。なので、アプリケーションが成長すればするほど複数サービスに分ける必要が出てくると思います。

そして、サービスの分離について必要以上に怖がらなくてもよいと思います。自分がお世話になったシニアアーキテクトの方から教わったポイントを2点ここに示しておきます。

  • いきなり大きなサービスを分離するのは誰でも難しい。小さなサービスを作っていくことで、サービスを分離する練習をしていくとよい。

  • 失敗したってやり直せばよい。小さなサービスだったら失敗しても取り返しのつかない失敗にはならない。

もちろんこれらのアドバイスは事業の状況などによると思いますが、何かの参考になれば幸いです。

さいごに

今回はChapter 8. Putting It All Togetherについての紹介をしました。

説明が不足していたり、わかりにくいようなところがありましたら、お気軽にご連絡いただければと思います。

最後にお詫びしておくことがあります。実はこのシリーズを書いていく中で、Unit of Workについては具体的に紹介していませんでした。これは自分が実際に使うような場面が想像つかなかったため、まあいいかと思って紹介を省いてしまいました。Unit of Workを知りたい方は Unit of Work パターンと永続性の無視 | Microsoft Learn というドキュメントに詳しく書かれていましたので、よろしければそちらをご覧いただけたらと思います。

この記事が気に入ったらサポートをしてみませんか?