2016-10-26 12 views
1

私は自分のプロジェクトでUserエンティティのすべてのストレージ操作を担当するリポジトリを作成しています。私はdbとしてmongoを使用し、クライアントとしてmongoreactiveを使用します。私が今問題にしているのは型についてです。インフラストラクチャコード上のDDD抽象化

trait UserRepository { 
    save(user: User) : ? 
} 

trait MongoUserRepository extends UserRepository { 
    save(user: User) : Future[WriteResult] = { 
     collection.insert(user) 
    } 
} 

MongoReactiveから来たWriteResultを私のドメインでモデル化すべきですか?私はそれが私のドメインに漏れて欲しくない。既存のパターンや良い方法がありますか?

答えて

1

私は同じリポジトリを実装した、私は私が最も興味があったWriteResult値を抽出することになった私の場合は、次のシグネチャになってしまった:。

いずれかのいくつかのエラーメッセージまたはを返す
trait UserRepository { 
    save(user: User) : Future[Option[String]] 
} 

何もなし。結果は次のようになります。

例外の場合は例外メッセージが失われないため、この実装になりました。

代替選択肢がBooleanに挿入結果をマッピングすることができます

trait UserRepository { 
    save(user: User) : Future[Boolean] 
} 

trait MongoUserRepository extends UserRepository { 
    save(user: User) : Future[Boolean] = { 
     collection.insert(user).map(_.ok) 
    } 
} 

しかし、この場合には、あなたは例外メッセージを失うことになります。時にはそれはあなたの正確な場合に依存してうまくいくかもしれません。

更新日:上記の回答は0.11バージョンで有効です。 0.12の方法でerrmsgWriteResultに取り除いた。代わりにwriteErrorsを使用できます。Seqが空でない場合は、errmsgをすべてWriteErrorから抽出します。

希望です、お手数です!

4

MongoReactiveから来たWriteResultを私のドメインでどのようにモデリングすべきですか?私はそれが私のドメインに漏れて欲しくない。既存のパターンや良い方法がありますか?

ドメインでは、永続インフラストラクチャがサポートする必要があるサービスプロバイダーインターフェイス(spi)としてUserRepositoryの特性が定義されています。基本的には、モデルが永続性に課す使用要件を表現する方法です。 Command Query Separationの言語を使用して

saveコマンドである:それはリポジトリの状態を変更する操作です。したがって、特性の実装は、コマンドを実装するためのローカルコーディング標準に準拠する必要があります。 (generic) repositories

グレッグ・ヤング:まさに最初の場所でリポジトリパターンの意図は何

でしたか? [DDD、Evans]を振り返ってみると、一連のオブジェクトをあたかもメモリ内のコレクションであるかのように表現して、永続性の懸念からドメインを解放できることがわかります。言い換えれば、永続性のあるオブジェクトにコレクションのセマンティクスを入れることです。

だから、インスピレーションのためのあなたのコレクションライブラリにもできました。

しかし、一般的に言えば、最も一般的な選択は、だから、あなたの特定の実装を満たすことが期待される契約です

trait UserRepository { 
    save(user: User) : Unit 
} 

ようになります。 MongoUserRepository

、あなたは契約を満たすためにあなたの永続化ソリューションの実装を適応させます。この場合、それは、Futureを開梱エラーWriteResultを検査し、書き込みが失敗した場合に例外をスロー意味します。保存して

(ユーザー:ユーザー):あなたが暗黙的に(例えば:デシベルに障害が発生した場合に)リポジトリの障害を監視するためにあなたのクライアント上の要件を置く単位

他の方法で回避 - リポジトリサービスプロバイダインターフェイスです。この設計はクライアントを制約するのではなく、プロバイダーを制約します。六角形アーキテクチャの用語では、secondary portを定義し、セカンダリアダプタをポートの契約に従わせるように制約しています。

動機は、まさにあなたが記述する1つである:リポジトリ消費者が選択した永続化ソリューションと対話するために必要なプロトコルから単離することになっています。ドメインモデルはビジネスユニバースの真ん中にあり、アダプターはビジネスユニバースを現実から隔離します。

Evans Chapter 6は、(ドメインオブジェクトのライフサイクルを管理することの複雑さによってモデルが萎縮するのを防ぐ)という管理上の課題を提起します。リポジトリは「は巨大なインフラ関与をカプセル化しながら、永続的なオブジェクトを見つけると取得する手段を提供

リポジトリがファイアウォールです

私たちはここに取り組んでいることは懸念の分離である;。。ドメインモデルは、あなたのビジネスを記述するロジックは。我々は明確なビジネスケースを見ることができるようにしたい、そしてそれは我々が明示的に変更可能な、メモリ内に、コレクションが変更に破滅的に失敗した場合に何が起こるかを管理する必要がある場合に可能であることを行っていない。実用的な答えがにありますいやアウトし、アプリケーションがそれを処理させる。言っ

を..私は "あなたの地域のコーディング標準に準拠している"と書いたところで、意図的に上にヘッジしました。現地ガイドラインでrailway oriented programmingまたはmessage drivenを使用している場合は、必ずそれを並べてください。ドメインモデルがストレージが同期型であるのか非同期型であるのかローカルであるのかリモートであるのかは気にする必要はありません。

ドメインモデルが実装上の懸案事項を示す一致式でいっぱいになると、どこかでプロットを失った。

+1

'save(user:User):Unit'では、リポジトリの失敗を監視するためにクライアントに暗黙のうちに*要求を出します(例えば、dbの失敗の場合)。リポジトリによって): 'try {} catch {case MyFailureException(...)=> ...; _ => ...} ' 「試着」や「未来」が良いと思いませんか? – tkachuko

+0

別の考え方をすれば、この正確なメソッドシグネチャは、同期(このメソッドのシグネチャによって適用される)から、ライブラリにある非同期APIの持つ簡単な切り替え方法を提供しません。 – tkachuko