Scala で IO コンテキストの共有を implicit 以外で解決する方法 (0)
※注: 解のないチラシの裏です。
Scala でレイヤードアーキテクチャを採用し実装する場合、データベース接続等の IO のセッションをどう引き回すか、というのが問題になる。
単純に引数として引き回せば、全レイヤー貫通して DbSession 等の特定の永続化層への依存が生まれるし、かといって永続化層に隠蔽するとアプリケーション層からの柔軟なトランザクション管理が出来なくなる。
以前、実現の方法に多少の違いはあれど、よくありそうな implicit conversion で解決するパターンの記事を書いた。
この話題は少しだけ ScalaMatsuri 2日目の最後の Scaling Scala というアンカファレンスでも話しにでた。
#ScalaMatsuri DDDでリポジトリパターンを記述する際にConnection/Transactionをインフラ層で制御するが、ContextをImplicitで引き回すところは議論がある。
— Kimura Sotaro (@kimutansk) 2014, 9月 7
「議論がある」。 確かに。
implicit で引き回すのは、宣言の冗長性と、レイヤーをまたがる依存性の観点などで美しくないと思いつつ、基本は implicit でやっている。
何故なら今の知識レベルではその他の方法は知らない & 思いつかないから。
id:xuwei_k さん曰く、それ Reader Monad でできるよ、ただし、Monad Transformer なども定義したりしないといけなかったり、そこまでチームでやるかといったらやらない、という様なニュアンスのことをそのセッション内で言っていた気がする。
※ 全然違ったらごめんなさい
で、キーワードに反応してなんとなく記憶に残っていた ScalaDays 2014 でやっていた Reader Monad に関するセッションについて言及してみたものの…
ScalaDay 2014 で ReaderMonad 使った Repository パターンの実装例があった気がする The Reader Monad for Dependency Injection/ https://t.co/xo3AAIeR8u #ScalaMatsuri
— takuyaf (@tlync) 2014, 9月 7
ちゃんと見たら全然関係なく静的な DI を Reader Monad でやる方法を解説していただけで、セッション中のコード例でも Context は Implicit で引き回す、という現実を間のあたりにした。
※ 下記の Jason さんもセッション中に「なんか良い方法知ってる?」という様なことを言っていた
僕が求めているのは Reader Monad ではないのか、と思いかけたが、以下のリンクを見て、やはり Reader Monad の考え方でいける気がすると思い直した。
https://groups.google.com/d/msg/scalaz/W6jiZUu5jaU/UBUGZjgnW7MJ
Strictly speaking, you should be using an IO-like Monad to do your database code. But that's OK because you can use ReaderT[IO, Config]
Typically I would define something like (if I understand you correctly):
case class Config(controllers: Controllers, services: Services, repos: Repositories)
Then run your program thru Reader[Config, _]. If you do use ReaderT with IO, then it's useful to do something like this:
type Program[+A] = ReaderT[IO, Config, A]
You can then define type constructors in a module:
object Program { def pointA = .... }
上記の URL に記載されているが、次の新しい道を差し示してくれるヒントが下記の動画かもしれない。
Teaching an old dog new tricks: wrapping an imperative API in a functional one https://skillsmatter.com/skillscasts/4943-teaching-an-old-dog-new-tricks-wrapping-an-imperative-api-in-a-functional-one#showModal?modal-signup-complete
説明では、この人が勝手にだろうけど Trampolining IO と呼んでいて、結局 Applicative functor のことらしいが、まだ見てないので実際のとこなんなのか良く分かってない。
何か進捗あれば次の記事 (1) を書く。