Kuchitama Tech Note

はてな記法がいつまでたっても覚えられないので、はてなダイアリーからマークダウンが使えるこっちに引っ越してきました。

Scala界隈でDDDが大いに盛り上がったのでログをまとめましたよ-その2

昨日に引き続き、ScalaJpのgitter.imで上がったDDDの話題の続きです。

scalajp/public - Gitter

なんか、昨日の記事はてブホットエントリしたみたいで、恐縮してます。

昨日あげた2/23の話題ででDDDに関する盛り上がりは収まったかにみえたのですが、翌日、導師かとじゅんさん(@j5ik2o)がみんなの疑問に一つ一つ応えて、我々を更にDDDの世界に導いてくださいました。

実践ドメイン駆動設計 (Object Oriented Selection)

実践ドメイン駆動設計 (Object Oriented Selection)

2月24日


j5ik2o 2015年2月24日

エヴァンスのDDD本だと具体的なrepositoryの置き場所に言及されてないように見える

ドメインモデルのライフサイクルを扱うので、ドメイン層に含まれると思いますけどね。DDDSampleでもそのようになっていたはず。


j5ik2o 2015年2月24日

インフラ層はドメインAPIに依存するのでは

(DDD本に記載されている)トラディショナルなレイヤー化アーキテクチャの場合は、UI層→アプリケーション層→ドメイン層→インフラ層。UI層→インフラ層、アプリケーション層→インフラ層を推奨していますね。実践DDD本には、UI層→アプリケーション層→ドメイン層という依存方向であるが、ドメイン層にはインターフェイス(型としての)を定義し、それをアプリケーション層で実装するというパターンと、DIP(Dependency Inversion Principle)を使った場合の逆転の依存関係で実現したパターンが示されていますね。

http://www.infoq.com/jp/news/2014/11/ddd-onion-architecture

コアがアプリケーションか、ユースケースかな。ちょっとこの図だけでレイヤー表現を解釈することができないな

オニオンアーキテクチャもなんか色々反論でてて何が良いのやら……というわけで実戦DDD本が待ち遠しい今日この頃

オニオンアーキテクチャはあんまり追跡してないんですが、Hexagonal Architectureについては、実践DDD本で言及があった気がします。

Coreってどこ由来の用語なんだろう。エヴァンスのDDD本には出てこなかったような

ドメイン層: "ビジネスの状況を反映する状態はここで制御され使用されるが、それを格納するという技術的な詳細は、インフラストラクチャに移譲される" (エヴァンスのDDD本) オニオンアーキテクチャやヘキサゴナルアーキテクチャとか、DDD本にはでてこないので、一旦DDDの標準的なレイヤー構造を理解した方がいいと思いますよ


j5ik2o 2015年2月24日

実際にインフラ層とドメイン層の橋渡しをするのがリポジトリってやつですね(リポジトリ自体はこれはインフラ層に所属してるって認識でいいんだろうか)

はい。橋渡しはあってますね。リポジトリドメイン層ですね。リポジトリの責務はドメインモデルから永続化責務を分離することなので、ドメインモデルをI/Oするためのオブジェクトということになります。DDD本に記載されている、標準的なレイヤー化アーキテクチャの場合は、下のレイヤーが上のレイヤーを直接依存できないので、仮にリポジトリをインフラ層に配置した場合はこれに反することになります。


j5ik2o 2015年2月24日

かとうさんのペットストアみてたんですが、domain 層と思しき package に JDBC という word が出てきてよくわからなくなったんですよね... https://github.com/j5ik2o/spetstore/blob/master/app/com/github/j5ik2o/spetstore/domain/infrastructure/support/RepositoryOnJDBC.scala あ、これインフラ層なのか

このあたりも試行錯誤ではあるのですが、インフラ層なんですが、すべてのレイヤー(UI, アプリケーション, ドメインなど)から汎用的に利用される技術基盤としてのインフラ層と、各レイヤーだけで必要になる技術基盤とがあるようです。

たとえば、ドメイン層なのになぜJDBCとかJSONというキーワードでてくるのか?話があるのですが、どうしてもドメイン層にしか配置できないものはドメイン層内のインフラ層(言葉が悪いと思っているので、今はs/infrastructure/support/などとしています)に配置しています。


j5ik2o 2015年2月24日

「repositoryを経由することになるので分離は容易」が個人的にとても懐疑的で、ヘタすると謎に層が増えるだけで、全く使いやすくならない、というのが発生しがちな気がしている

自分も最初はこの考え方でしたが、ユビキタス言語パターンを理解するまでは。実装都合でいうと邪魔な層が増えるだけですw が、つまりトレードオフの観点なので、吉田さんの言ってることは全く正しいですが、これはチーム全体の言語を統一してドメインで会話できるようになるために払うコストなんですよね(層を挟むことでドメインモデルがどの永続化技術からも分離できて議論しやすくなるわけなので)。そのコストが払えないチームやプロダクトではそもそもDDDするべきでないと思いますねー。


xuwei-k 2015年2月24日
なるほどー、そういうことならかなり納得できます


j5ik2o 2015年2月24日
はいー


tkawachi 2015年2月24日
@j5ik2o フォローありがとうございます。 実践DDD日本語でたら読まないとなあ


j5ik2o 2015年2月24日

かとうさんも、そのあたり(層をきちんと分けるか否か?)は、パフォーマンスのチューニングのしやすさとか考えると、分けすぎてもあれだし、バランスが必要というかプロジェクト毎に考えるべき的なこと言ってた気がする(かなりうろ覚え)

そうですね。コミュケーションコストを下げるためとはいえ、層は増えますのでなんでもかんでもドメインモデル化しない( つまり重要なものだけに絞るという意)などの工夫が必要なんですよね。 一般的にはドメインモデルは、どの永続化技術にも依存しないので、SkinnyORMなどのORMで表現されるモデルとは分離します。これまでモデル、モデルと呼んでいたものは基本的にインフラ層のモデルになります。なので、Userドメイン(エンティティであり集約) <-> UserRepository(JDBC用) <-> UserTableにmapされることになります。1集約が1テーブルに対応づく場合はよいですが、1集約が複数のテーブルにマップされることもあり(ex 売り上げエンティティ<->売り上げテーブル、売り上げ明細テーブル)、実装はめっちゃ大変です(コード生成でこのあたり作れると楽なんですがねー)


j5ik2o 2015年2月24日

Dao と Repository の使い分けが気になる……。モチベーション的には同じものですよね Dao と Repository。

ここでいうDaoの定義をPofEAAのデータマッパーとすると(一般的にそうだと思うのですが)、Daoはテーブルを扱うためのオブジェクトですね。でも、RepositoryはAggregate(集約)をI/Oするためのものです(集約はドメインモデルのカテゴリとしてはエンティティになります)。そもそもドメインモデルとは、テーブルから分離している存在なので、RepositorとDaoではレイヤーが違ういますね。たとえば、売り上げエンティティは、売り上げテーブルや売り上げ詳細テーブルにマップされる場合があると考えると簡単に理解できます。当然、売り上げエンティティと売り上げテーブルが1:1ならDaoとRepository同じでは?という疑問あると思います。しかし、ドメインモデルはどの永続化技術にも依存せず様々な実装のリポジトリを使って、テーブル以外にファイルやJSON形式で保存されたりします。ネットワークの先のサーバに保存されるかもしれません。テーブルからドメインを見るのではなく、ドメインモデルからみた場合は、テーブルはエンコードの一表現にすぎませんという感じです。

みんなDDD本みてて、最初にレイヤードアーキテクチャが来るからその話が人気なのかな(想像

そうですね。和智さん曰く、2部は一番最後に読むといいらしい


j5ik2o 2015年2月24日

DaoとRepositoryの違い、Daoはデータストレージの抽象化しか志向していないのに対して、Repositoryはドメインモデルとの接続を強く意識しているというのがあるかな(DDDにおいてDaoパターン使ったら自然にRepositoryになりそう)

あと、RepositoryのI/FはRDBMSとかJDBCのコネクションとかトランザクションに依存できないのですー。そとからみたらコレクションのように動作するのがリポジトリなのでDaoとは全然違いますよー

ドメイン層で class MyEntity {...} があって、レポジトリ(インフラ層)で def findMyEntity(id: Id): MyEntity = ??? って書くとしたら、戻り値にドメイン層のクラス出てきてインフラ層がドメイン層に依存してね?って話なんですが

はい。それよくないと思います。ドメインモデルとリポジトリはI/Fも実装もドメイン層に配置することになります。


tototoshi 2015年2月24日
なるほどー

RepositoryのI/FはRDBMSとかJDBCのコネクションとかトランザクションに依存できない ということは理想的にはトランザクションの境界は Repository より下の層にすべきっていう認識で良いですか?


gakuzzzz 2015年2月24日

ここでいうDaoの定義をPofEAAのデータマッパーとすると(一般的にそうだと思うのですが)、Daoはテーブルを扱うためのオブジェクトですね。

あーなるほど。 ここの認識が異なっていた感じですね。 PofEAAのデータマッパーという意味なら理解できます。 Dao というと Data Access Object パターンの認識だったので。 一般的にはどういう認識なんだろう? Seasar界隈ではひがさんがDaoをData Access Object パターン的に説明してたような記憶がうっすらと……


gakuzzzz 2015年2月24日
トランザクションの境界をリポジトリの内側にしちゃうと現実のアプリが回らなくなるか、eventual consistency でやらざるをえなくなるので、 リポジトリドメインモデルが全てSTMモナド的なものを返してアプリケーション層でトランザクションするのかなーと思ってました。


todesking 2015年2月24日
エヴァンスのDDDでは、リポジトリトランザクション管理をしないでクライアント(アプリケーション層?)に任せることを推奨している http://tlync.hateblo.jp/entry/2013/12/12/023135


j5ik2o 2015年2月24日

エヴァンスのDDDでは、リポジトリトランザクション管理をしないでクライアント(アプリケーション層?)に任せることを推奨している http://tlync.hateblo.jp/entry/2013/12/12/023135

ですね。トランザクションの開始と終了については、アプリケーション層の責務となってましたね

Implementing DDDでは、PofEAAパターンで言うData MapperがRepositoryに近くて(どちらもドメインモデルを扱う)、それ以外(Table Module/Table Data Gateway/Active Record)がDao-likeだという解説になってました

ファウラーがいうドメインモデルって集約を意識しているのか、怪しいなと思っています。Data Mapperでは、本来集約内部でにあるオブジェクト群が外に露出していているように見受けられるので。

実践DDD本で手元に届いたらじっくり読んでみます

RepositoryのI/FはRDBMSとかJDBCのコネクションとかトランザクションに依存できない ということは理想的にはトランザクションの境界は Repository より下の層にすべきっていう認識で良いですか?

アプリケーション層ですねー


j5ik2o 2015年2月24日
https://gist.github.com/j5ik2o/973fe2fde3ba8f141bb1

Ctxなんとかできないもんかと。つらい リポジトリのI/Fは永続化技術固有の知識に依存できないのですが、どうにかしてアプリケーション層からドメイン層をまたいでコネクションやらトランザクションをインフラ層にわたさないといけないので


tsukaby 2015年2月24日
すごいレスだ・・・勉強になります。 自分が作ってるDDDっぽいようなMVCっぽいようなScala+PlayアプリもApplication層からdbのsessionを渡して行く感じで「うーん」と思っていたんですが、これはみんな思ってることなのかな。


tkawachi 2015年2月24日

AbstractRepositoryOnJDBC, EmployeeRepositoryOnJDBC は永続化の技術詳細を含むのでインフラ層という認識であってますか? それともドメイン層のなかのインフラ層、と話していたところなのかな..


j5ik2o 2015年2月24日

AbstractRepositoryOnJDBC, EmployeeRepositoryOnJDBC は永続化の技術詳細を含むのでインフラ層という認識であってますか? それともドメイン層のなかのインフラ層、と話していたところなのかな.. 大枠のレイヤーでいうと、AbstractRepositoryOnJDBC, EmployeeRepositoryOnJDBC はドメイン層ですね。インフラ層に移動しちゃうと下位層が上位層に依存することになるので。”ドメイン層の中のインフラ層”的な位置づけになるとは思います。


tkawachi 2015年2月24日
うーん、 ドメイン層 ← インフラ層 方向の依存だったら、インタフェースだけドメイン層におけば、技術詳細をインフラ層に閉じ込めることはできそうなので、そちらのほうが自然に感じるのですが、、、、


j5ik2o 2015年2月24日
"本質的な原則は、レイヤ内のどの要素も、同じレイヤの他の要素か、その「下にある」レイヤの要素にしか依存しない、ということである"なので、上下の定義によるかなと思いますね


以上が、一連のDDD関連の話題になります。

そうですね。和智さん曰く、(DDD本)2部は一番最後に読むといいらしい

そうなので、DDD本も読み返したいです。

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)