Scalaでモデル駆動を実現するにはどのような観点が必要か

加藤潤一氏(以下、加藤):Chatworkの加藤(@j5ik2o)がお送りします。「モデル駆動設計をScalaで解説する」のセッションです。よろしくお願いします。

自己紹介です。Chatworkでテックリードをしています。最近の仕事は、Akka Clusterを使ったイベントソーシングシステムの検証や構築です。「zenn.dev」でScalaの薄い本を出したので、入門したい人は手に取ってほしいなと思います。

それと「Lightbend Academy」が無料受講できるのでやってまして。最近無料と有料に分かれたんですが、リアクティブシステム関係の6つのコースは今も無料で受けられるので。つい先日僕も受講して認定をもらったんですが、興味がある方は、Lightbend Academyを参照してほしいなと思います。

今日は具体的なリアクティブシステムの話には触れませんが、こちらの『ビジネスパターンによるモデル駆動設計』という、2007年に発刊された、すごく古い本なんですけれど。ドメイン駆動設計に関連する書籍でして、Scala界隈ではドメイン駆動設計を実践している方も多いので、今日はこれをテーマに、「Scalaでこういったモデル駆動を実現するには、どのような観点が必要か」の話をしていきたいと思います。

モデル駆動設計のこの書籍。「REA」という構造パターンと、振る舞いのパターンが紹介されていますが、そちらをまず話したいと思います。

「Resource」「Event」「Agent」で「REA」

REAが何かというと、構造のパターンの解説で、「Resource」「Event」「Agent」の頭文字を取って「REA」と呼ばれています。

Eventは、過去に起こった出来事です。Resourceは、Event以外のオブジェクトを意味します。Eventは過去のできごとなので、Event以外の、一般的なヒト・モノ・カネで言うと、モノに当たるもの。Agentがヒトですね。なので、「できごと」「リソース」「ヒト」を中心にモデリングを考えていく話です。

構造的なREAのパターンですが、その中に含まれるポリシー。Operationalは業務レベル、業務遂行レベルという意味合いになりますが、その構造の中には「方針を決める」部分と、業務を遂行する「実行する部分」の2階層に分かれています。今から話すResource、Agent、Eventは、業務遂行レベルに対応する部分です。

Economicとプレフィックスがついていますが、端的に言うと、ResourceとAgentとEventですと。

これらは、下の図に書いているとおり関係があって。Eventは必ず過去の出来事なので、何かが起こったときに、関連する情報があって、ResourceやAgentがそのEventの説明になるという話です。

「商品を出荷した」というEventなら、出荷した商品に必ず説明につかないといけないので、Resourceにはプロダクトやアイテムなど、そういった商品が関連づくと。誰に出荷した、売ったなど、そういう対象のヒトですね。そういった関連があります。

「Inflow」「Outflow」は「流出」や「流入」の話です。商品を出荷したなら、その対象の相手に商品が移動するので「流出」ですし、仕入れ先から商品を仕入れたなら「流入」という関係性があります。

さらにREAの関係性のモデルを追加すると、契約に対して「Commitment」という約束事があります。「将来こういったEventが起こるよ」というのを約束するために、「Commitment」というモデルを導入する場合があります。

よく使われるのは予約です。商品の予約や、ホテルの部屋の予約もそうで、「この日に、このプランの部屋を借りる」という約束をした時にCommitmentが発生しますが、そのCommitmentに基づいて、Eventが発生すると。約束に基づいて発生する「できごと」と考えられています。

約束事自体もいきなりできるわけではなく、契約があって、いくつかの約束事が発生すると捉えられるので、契約と約束事(Commitment)はポリシーレベルと考えられています。なので、その2つの階層があるという話ですね。

REAモデルの基本的な考え方

REAモデルの基本的な考え方は、企業や経済活動をする人たちです。主に企業ですけれど。その制御下にあるリソース全体の価値を増やしたい場合は、通常「いくつかのリソースの価値を下げなければいけない」という考え方があります。

難しい説明ですが、例えば商品を売るなら、商品が流出して代わりに現金が流入すると。そういったことを説明をしています。交換をするときは、こういった価値の移動が起きるという話です。

例えば寿司屋では、「交換」と「変換」という2つのパターンがあります。その中にResourceが増減するシチュエーションがあるんです。

ある企業がほかのAgentからResourceを受け取って、その見返りとしてそのAgentにResourceを与えるプロセス。取引ではよくこうなりますが、取引は「交換」プロセスに該当する。何かのResourceを受け取って、逆にまた別のResourceを得るという、交換ですよね。

「Conversion(変換)」は、ある企業が新しいResourceの生産や既存のResourceの変更のために、加工というか変更をする。Resourceを使用、あるいは消費するプロセス。商品の生産は、変換プロセスになるということです。

寿司屋を例にしたREAモデル

これをちょっと具体的に説明しようと思います。寿司屋で説明すると、左側の図を見ると周りには利害関係者が複数いて。原材料を仕入れる、ベンダーというか市場ですよね。あと従業員や顧客がいます。寿司屋自体も存在するので、これらはAgentです。ここの登場人物全員がAgentです。生産される寿司、取引に使われる現金、寿司の生産に関わる労働力、寿司の原材料の魚。これらはResourceです。

取引プロセスには、販売、購入、労働力の取得。3つあると言われます。右側の図を見ると、Conversionの左上の「寿司を生産する」。めちゃくちゃ仰々しく書いてますが「寿司を生産する」は労働力。とともに、原材料の魚を変換するプロセスになります。右側の「寿司の販売」は、現金との交換になると。

「寿司を現金と交換します」という関係性です。寿司と現金は経済リソース。Resourceです。

ここで発生するEventがあります。ただ交換するだけじゃなく、Eventが発生する。寿司屋から顧客へ、寿司の所有権の移転が起こるわけです。商品販売は、減少イベントと言われています。Resourceが寿司屋から出ていくので、減少するわけです。Resourceが減少するEventです。

顧客から寿司へ、現金の所有権の移転です。現金を渡すわけなので、寿司を手に入れる代わりに現金を渡して、相手に現金の所有権を移す。反対の方向です。寿司屋から見ると現金を受領するわけです。受領するので「Resourceが増加する」というEventが発生します。と、REAでは捉えます。

Eventには双対性がある

端的に表したのがこういう図です。先ほど、EventとAgentとResourceは関係する話をしました。これを取引で見た場合、色が変わっている中央に注目してほしいんですが、契約やCommitmentはいったん忘れてもらって、販売のプロセスはこういった双対性、2つが対になっている、Eventが対になっていることを考えなくてはいけません。右でも左でもどっちでもいいんですが、左側が現金の受領Event、右側が寿司を販売したEventの対応づけになります。これが対になってないといけない。もうお気づきの方はいると思いますが、会計システムでは必ずこうなっています。

Eventをimplementationする話で、モデル化するとき、まずEventに注目しているので、先ほど色を変えて説明していたところのモデルを実装していくことになります。

実際にEventをどこまで使うかは、イベントソーシングのシステムでは有益ですが、Eventを最終的に使わない場合だと、このモデルは使わないかもしれませんが、分析の途中までは使えるかもしれないです。

このEventを見てもらうと、ドメイン上、関係する登場人物が含まれていないといけません。寿司を販売したなら、誰に販売したのか。SushiTypeと書いてありますが、これは寿司の商品コードのようなものが含まれていないといけないし、何個売ったのかという履歴のようなものもわからないといけません。現金の受領に関しても、どの顧客からどれだけの金額を受け取ったのかがわからないといけません。

ここで注意なのは、Eventには双方向の関連があります。“双対性”といって、お互いにリンクしていないといけません。

このモデルを見た時に、時系列的に、必ず寿司の販売が起こってからお金を受領するようになっているわけで。その現金受領Eventの中に、寿司を販売したというID……そのIDの型名が間違ってますが、「寿司を販売した」というEventのIDを格納する設計にした場合、必ず寿司の販売のあとに現金の受領をするオブジェクトの生成順序になるので、例えば予約注文などの場合は、これだと対応できません。そのため、モデルを見直す必要があります。

(次回につづく)