疑問だったこと
クリーンアーキテクチャでEnterprise Business Rules層の値オブジェクトを、Interface Adapter層にアウトプットとして直接渡していいか?
それとも、Application Business Rules層で値オブジェクトの中身をデータストラクチャオブジェクト(図2のOutput Data)に移し替えてInterface Adapter層に渡したほうがいいか?
図1
図2
疑問の背景
今回悩んでたのはEnterprise Business Rules層に値オブジェクトが20個くらいあり、それをApplication Business Rules層でデータストラクチャに変換してアウトプットに返すかどうかという点です。実装コードを想像すると、同じコードのクラスがいくつもできてしまう気がして、どちらにするか悩んでました。
値オブジェクトをデータストラクチャに移し替えないと、Interface Adapter層から見たら隠れ層であるEnterprise Business Rules層の変更が間接的に影響をきたすので、アーキテクチャ的には筋が悪いとは感じたのですが、コピペとトレードオフしてもいいのかもやもやしてました。
疑問への答え
- 求心方向の依存は絶対守る
- 値オブジェクトをそのままInterface Adapter層とかに渡るようにするか、データストラクチャにに移し替えてInterface Adapter層に渡るようにするかは、明確なルールはなく決めの問題。(ただし、図から察するに典型的なシナリオでは移し替えることを想定している可能性が大いにある)
ご回答を下さった @nrslib さんと、 @pospome さん、 @hirodragon さんに感謝。
以下 Slack より
— nrs (@nrslib) 2018年12月27日
端的にまとめると
・ボブおじさんが示した典型的なシナリオ(図)では依存していないようにみえる
・ただ、依存方向を内向きにするということがコンセプトなので、そもそもレイヤーについてが厳密ではなく、レイヤーを飛び越えて依存したとしても問題ない
みたいな感じでした pic.twitter.com/jg3ufJzPBd
で、"strict layered or relaxed layered" ってこの点を疑問に思うから調べるんだけど、明記されている or いないに関わらず、そのまま使うことによってどういったメリデメがあるかを考えるといい。もしメリデメが明確ではなければ個人の好みであったり、決めの問題なので好きな方を使ってみるといい。 https://t.co/oZg2APfO8w
— pospome (@pospome) 2018年12月27日
自分も過去に調べたけど、これは「内側に依存する」というだけで明示されてない気がするな。 https://t.co/cwZ9JUAYOX
— pospome (@pospome) 2018年12月27日
実際どうするかについてのアイディア
戦略としてはコードの再利用性重視 OR 層の独立性重視かの二択なのだが、それぞれ細かい実践の部分で工夫はできる。
- エンティティに所属する値オブジェクトを公開する (relaxed layered architecture)
- 値オブジェクト周辺のライフサイクルとデータストラクチャクラス周辺のライフサイクルがほぼ同じ場合など
- 汎用的な値オブジェクト(DateTimeなどと近い存在)をパッケージに切り出して共有する (shared kernel的な)
- 値オブジェクトをデータストラクチャオブジェクトに移し替える (strict layerd architecture)
- そんなに値オブジェクトの数が無い場合は、手作業で詰替コードを書いてもそんなに辛くない
- アーキテクチャにもデメテルの法則があると主張できる
- その際のコードの重複は妥協する
- データストラクチャクラスをコード生成することで、退屈なコーディングを避ける (code generation)
- 値の詰替えは退屈な作業になってしまうから
- 値オブジェクトがたくさんある場合は自動化したほうが楽
- コード生成後は別々のライフサイクルをたどる
- 方針を確定する前にお試しで実装してみて、どちらがそのプロジェクトに合っているか見極める
- テストコードまで書いてみる