そこに仁義はあるのか(仮)

略してそこ仁!

アーキ部:強いて言えば「集約どう実装するのかな、を考える」会に参加してきた!

kawasimaさん主催のアーキ部に参加しました!

architect-club.connpass.com

テーマの発端になったツイート

これまでドメイン駆動設計やクリーンアーキテクチャとかを勉強してきましたが、このツイートを見て「実際に『性能』を意識してコードを書いていくってどうしたら良いんだろう?」と謎になりました。
この勉強会では、『性能』は重視しつつ、どうやってドメインをコードに表現していくのか、というお話をkawasimaさんからしていただきました!

🗒 ざっくりまとめ


🤔 課題

次の2つを重視しすぎると、ドメインモデルのクラスは美しくなるけれど、性能に問題が出てくるケースがある。

  • ドメインロジックをドメインモデルの中に閉じ込める:完全性
  • ドメイン層は他のレイヤーに依存させないようにする:純粋性


例えば、Cartクラスに新たにItemを追加するというユースケースの場合

  • Cartに入れられる数量の上限に達していないか?
  • Itemは存在している商品か?
  • Cartの中に同じIDのItemは存在しないか?

などをチェックするためには、CartクラスにItemのリストを持たせて、リスト内のアイテムに対して上記のチェックをしなければならない。(DBに対してSQLを叩けばサクッと解決できるはずなのに。)
そうなるとメモリ上にデータを多くもつ、性能に影響を与えてしまう。
(ただし、扱うデータ量が少なければこの限りではない)

💡 基本になる考え方

DDDのトリレンマ
次の3つ全てを得ることは出来ない。「どの選択をしているのか」を認識することが重要。

  • ドメインロジックをドメインモデルの中に閉じ込める:完全性
    • コードの変更容易性に影響する
  • ドメイン層は他のレイヤーに依存させないようにする:純粋性
    • テスト容易性と移植性が向上する
  • 性能
    • 外すことが出来ない

性能は外せない選択肢となる。完全性・純粋性はビジネス影響としては与えないので、ここを悩みすぎるのは微妙。
完全性・純粋性を犠牲にしつつも、それぞれのメリットを少しずつでも享受する方法を考える。

参考
scrapbox.io

✨ 解決方法

高凝集を目指すために、複雑さを紐解いていく

解決に向けての2つのステップ

1. どこに定義するかより、同じでないものを区別する

「カートのアイテム」とまとめて考えるのではなく、「カートに追加したいアイテム」「カートに入れられるアイテム(チェックが済んだアイテム)」「既にカートに保存されたアイテム」は特性が別々なのでは、という考え方。

例えば
「カートに追加したいアイテム」は「カートID」「商品ID」「数量」を情報に持ち、
「カートに入れられるアイテム(チェックが済んだアイテム)」は「カートID」「発売中の商品ID」「数量」「既にカートに追加されている商品IDかどうか」の情報を持つ
という感じ。
本来表現したい特性が別々なので、持つ情報も違ってくる。

また、型として上記を分けることで、チェックしてないアイテムがカートに入るというミスも避けられる

参考(③Design by Typesドメインモデル )
scrapbox.io

このあたりで感じたこと



2. Domain Modeling Made Functional

ステップ1で実施した型を使いつつ、ユースケースのステップをそれぞれ関数にしてドメイン層に実装していく

例えば、
Input「カートに追加したいアイテム」 → 関数:アイテムのチェック → Output「カートに入れられるアイテム(チェックが済んだアイテム)」
という感じ

type ParseAddableCartItem = (cartItem: CartItem) => AddableCartItem

引用:revisiting-domain-model/made_functional.ts at main · kawasima/revisiting-domain-model · GitHub

また、実装の関数としてRepositoryを差し込めるようにすることで、テストもしやすい状態を作れる

function parseAddableCartItem(
    cartRepository: CartRepository,
    productRepository: ProductRepository,
): ParseAddableCartItem {
    return (cartItem: CartItem) => {
...

引用:revisiting-domain-model/made_functional.ts at main · kawasima/revisiting-domain-model · GitHub

このあたりで感じたこと



💬 全体の感想

変更容易性やテストのしやすさも大事だけど、「性能」を犠牲にしちゃいけないし、そういうコードになってないかについて考えなきゃ!と気付けるすごく良い機会でした!
ドメイン駆動設計やクリーンアーキテクチャを勉強してると、どうしても完全性や純粋性を意識したくなるし、「そうすべきだ!」って気持ちに陥りがちなので、気をつけねば。

今、勉強でゆっくり書いてるコードも、この話を聞くと色々修正してみたくなるし、コードの改善って一生終わらない感じする。(でもそれが楽しい)

kawasimaさん、お話ありがとうございました!楽しかったです!🙌

オライリーのサブスク折角あるので、この本も読書チャレンジしたい