Chapter 03

iHerb Affiliates Link Maker DDD分析

DDD分析

iHerbのECサイトのドメイン分析ではなく「iHerb Affiliates Link Makerのドメイン分析」ということを忘れたらいけない。後者にはオーダーとかが定義されたコンテキストは存在せず、あるのはiHerb商品とアフィリエイトIDとアフィリエイトURLだけです。そこにはiHerbドメインしか存在しないのです。

  • iHerbドメイン
    • 商品
    • 商品URL
    • アフィリエイトID
    • アフィリエイトURL

chrome extensionとして作るのだからchromeドメインもあるのでは?と思いがちですが、それはiHerb Affiliates Link Makerを実現するためのアプリケーションサービスの一部なのでドメインとして定義しません。

ドメイン(オブジェクト、サービス)の範疇は「特別な意味のある値とそれが出現する文脈の中で特別な意味のある変換や結合などの操作」で、OOPの解説シーンによく出てくる説明例の「そのモノ自体が取り得る動きや振る舞い」よりもビジネス(=解決しようとしている課題とその解法)色が強いです。

DDD戦術によってレイヤー化するとしたら下記のようになります。

domain object

  • iHerbドメイン
    • 商品
      • URL
    • アフィリエイトID

商品と商品URLは現実社会では別モノですが、このコンテキストでは商品URLは商品の特徴になります。ですがアフィリエイトIDやアフィリエイトURLはやはり商品とは別モノです。

domain service

  • アフィリエイトURLを作成
    • 商品URLとアフィリエイトIDで変換

商品とアフィリエイトIDは別モノなので、ドメインの振る舞いにアフィリエイトURLの作成を含めるのは違和感があります。逆にアフィリエイトオブジェクトを作ってアフィリエイトIDと商品を使ってアフィリエイトURLを作成するのも同様に違和感があります。

この違和感の正体は「商品は必ずしもアフィリエイトの対象にならない」というルールから来ています。よって、このドメインでは「ルールに沿わないので分離している」としています。こういった場合、ドメイン同士では扱えないので、ドメインサービスとして切り出します。

この「ルール」ですが、そのドメインが扱うコンテキストによって変わってきます。リアルワールドが常に正しい、なんてことはありません。

domain repository

  • アフィリエイトIDを保管
  • アフィリエイトIDを復元

リポジトリパターンはドメインではありませんと解説するところもありますが、計算しっぱなしよりも明示的に保存、復元を行う前提の方が自然です。ただし、どんな方法で保存するか・復元するかを考えますが、手段は考えません。例えば「ドメインAとドメインBを入れ子にして保存する」はOKですが「ドメインAとドメインBをchrome.storageを使って保存する」はNGです。前者は保存時のデータ構造についての中枢アイデアであり、後者はサブシステムの選定です。

application service

  • クリップボードにテキストをコピー
    • await navigator.clipboard.writeText()
  • リポジトリからアフィリエイトIDを復元
  • リポジトリへアフィリエイトIDを保管

問題解決方法や能力(ドメイン)をアプリ(アプリケーション)として表現する際の利便性を考慮します。

このアプリの例で言うと、アフィリエイトURLを表示したり手動コピーできるフィールドを出力するより、カーソルだけでコピー出来たり、ショートカットキーだけでコピー出来る、などです。

infrastructure

domain repositoryで定義したアイデアを「どのような手段で実現するか」を定義します。今回はchrome extension MV3 で使えるchrome.storageを利用します。

interfaces

  • アフィリエイトURLをクリップボードにコピーするボタン
    • popup.html (MV3)
  • アフィリエイトIDのinput欄と保存ボタン
    • options.html (MV3)

今回は下記のような複雑な話ではなく、クリップボード操作はWebAPIが提供してくれてるので、具体的なOSのAPIを意識する必要がありません。ただAPIを呼ぶだけなので、htmlページとして表現します。

interfaces自体は、アプリケーションの入出力境界に相当します。場合によっては、infrastructureと重なってしまう場合もありますが、データの保管という意味の操作であればinfrastructureに定義し、データの入出力という意味の操作であればinterfacesに定義する、という使い分けでしょう。

易しい考えならば、前者はDB操作・後者はUI操作になると思いますが、それにこだわる必要は無いと思います。どんな規模のアプリにもドメインは存在するので、小さなセンサーアプリなどでは前者はインメモリ操作で後者はリモートAPI操作という例もあるでしょう。