Scala における Repository の実装パターンを考える -模索篇-
この記事は Scala Advent Calendar 2013 12/11 の記事です。
昨日は @chiral さんの Sprayの簡単な紹介 - アドファイブ日記 でした。
ちゃんと見ましたか? 見てね!
で、この記事は Scala で DDD の Repository の実装を書く場合どう書けばいいのか、その一例を考えてみたというお話しです。
(主軸が Scala より DDD な気がするがキニシナイ)
ただし、書いてる人の関数型成分含有率は 1% 位な為、関数型ガチ勢から見た時いろいろ思うところがある可能性は高いです。 マサカリお待ちしております。
DDD 関連の概念については特に説明しないので適当にググってください。
実現したい要件
Repository の実装パターンを考えるにあたり、達成したい要件としては以下の2点。
1. ドメイン層を特定の永続化技術から独立させる
Repository というのは I/O が絡む為、特に何も気にせず設計すると、どうしても I/O 関連の技術詳細への依存が生まれます。
DDD 本で Eric 神は理想の Repository 実装として以下の様に言及しています。
理想は、クライアントから(クライアントの開発者からではないが)内部の働きをすべて隠蔽し、それによってクライアントコードが、データの格納箇所に関わらず同じになることだ。 … 略 … 格納と取り出し、および問い合わせの仕組みをカプセル化することが、リポジトリの実装における基本的な機能である。
この辺りをどう実現するかは Implementing Domain Driven Design や ddd-sample 等でも言及、紹介されているのでさらっと流しますが、依存性逆転の原則を適用して、ドメイン層はインタフェースのみ依存する様にするのが良く見るパターンです。
ScalikeJdbc を利用した Repository を例にするとこんな感じ。
一見すると上手く分割できた様に見えますが、これにはまだ明らかな問題があります。
セッション管理が Repository 内で閉じている為、複数のリポジトリをまたがるトランザクションを管理する事ができません。
1 を実現したが故に、純粋無垢な Repository のインターフェースを介して、どの様にトランザクション管理をすればよいか、という新たな課題が生まれた訳です。
2. トランザクション管理をアプリケーション層から行う
DDD 本で Eric 神はトランザクション管理についても以下の様に言及しています。
リポジトリはデータベースに対する挿入と削除を行うが通常は何もコミットしない。例えば、保存した後にはコミットしたくなるが、おそらくクライアントには、作業ユニット(unit of work)を正しく開始し、コミットするためのコンテキストがある。トランザクション管理は、リポジトリを手を出さないでいる方が単純になる。
この記事は模索編ですし、Eric 神も Repository の実装はインフラストラクチャ層により多岐に渡ると言及している事もあり、正直なところ Scala と、今 Scala 界隈に存在するライブラリでどの様にするのが実現するのが良いかはまだ見えてません。
ただ、ひとつのやり方として Implicit Parameter を使えば、Boilerplate なコードによる冗長性を可能な限り排除しつつも、ドメイン層のインターフェースは永続化の詳細を抽象化したままアプリケーション層からトランザクション管理をする事ができます。
コードにするとこんな感じです。
なんかこんなんでいいんだろうか感はありますが、一応 1,2 共に要件は達成できました。
ただ、まだこれも問題があってトランザクション管理の仕組みは ScalikeJDBC と密結合になっている為、アプリケーション層のコードは永続化の詳細から切り離せていません。
アプリケーション層からも永続化の詳細から完全に切り離すには、トランザクション管理の抽象レイヤも作ればいいとは思いますが、トランザクションのブロック内だけを見ればインフラ層の永続化詳細から切り離せているので、このレベルで割り切るのもありな気はしてます。
最後に重要なことを言っておくと、この様な Implicit Parameter で環境を引き回すのは id:xuwei さんが定期観測されている関数型ガチ勢的にはアンチパターンな様です。
関数型ガチ勢から見たScalaのアンチパターン - scalaとか・・・
正直どんなデメリットや、代替手段があるかコードレベルで全然思いつかないので、そろそろ Monad っておいしそうな名前だよねとか言っている場合じゃないと実感します。
所感
- DDD は若干ポエムなのでコードレベルに落としこむのが大変。で、Java ベースではなく、今ある技術や考え方を使ってシンプルかつエレガントに実現するプラクティスやパターンを共有する必要性を感じる。
- Implicit の多用は良くないのは分かっているけど、各レイヤーのグルーとして使うのはアリだと思っている。
- Scala はプログラマの考え方を広げてくれる素晴らしい言語
なんか最後の方は無理矢理感がありますが、続編はすごいH本をちゃんと理解した後にまたやるかもしれません。 明日は k4200@github さんです!
終わったー! 酒だー!! (現在時刻 12/11 26:30)