2026年9月30日水曜日

Cozyモデル駆動開発/ユースケース/collaborates

本稿では、ユースケース間の関係の一つである collaborates(並行・協調関係)を取り上げます。

前回のensuresでは、一つのユースケースが正常に完了した時に保証する結果を整理しました。今回は、複数のユースケースがそれぞれの役割を果たし、その結果を合わせて業務を進める場合を考えます。

例えば、書籍の注文を受け付けた後には、出荷する書籍の確保と、支払いの承認が必要になります。両者を独立して進められるなら、並行して処理し、双方の結果が揃ったところで出荷へ進めます。

collaboratesは、このようなユースケース間の協調を表すために使用します。

collaborates

  • マージモード : Parallel
  • マージ点 : 同期点
  • 機能 : 並行・協調動作
  • 由来 : Workflow patterns

本連載では、collaboratesを、共通の業務目的に向けて複数のユースケースが協調する関係として扱います。並行するシナリオを合成する際には、参加するユースケースと、その結果を合わせる同期点を定めます。

collaboratesの基本方針

collaboratesでは、次の三つを明確にします。

  • 各ユースケースが担当する役割
  • 各ユースケースが提供する結果
  • 結果を合わせて次へ進める条件

例えば「注文分の書籍を確保する」と「注文の支払いを承認する」は、それぞれ在庫と決済を担当します。この二つが提供する結果を合わせることで、注文を出荷可能な状態にできます。

各ユースケースの契約に加え、協調全体の契約が必要になります。

マージモードのParallelは、合成シナリオの中に並行する経路を設ける基本戦略を表します。実際の開始時刻や実行資源の割り当ては実行設計で決めます。ここで扱う並行性は、複数のユースケースが進行中となり得る業務上の構造です。

意味定義

UseCase A が UseCase B と collaborates するとは、

AとBがそれぞれの結果を提供し、共通の業務目的の達成に協力する

ことを意味します。

本稿では、両方の結果を必要とする協調を基本形とします。

  • 共通の業務対象と開始条件を確認する
  • AとBをそれぞれ開始する
  • AとBの進行状態と結果を記録する
  • 同期点で両方の結果を確認する
  • 協調全体の完了条件を満たした時点で次の処理へ進む

協調全体をCとすると、同期点で確認する条件は次のように整理できます。

Ready(C) = Post(A) and Post(B) and Compatible(A, B)

Post(A)とPost(B)は、各ユースケースが保証する結果です。Compatible(A, B)は、その結果を組み合わせられる条件です。

例えば、在庫を確保した注文と支払いを承認した注文が同じであること、対象となる注文内容の版が同じであること、予約や承認が有効期限内であることを確認します。

個々の処理が成功したという記録に加え、同期点で利用する結果の有効性を確認することで、協調全体の完了を判断できます。

記述例

Pieris Booksで、受け付けた注文の出荷準備を進める業務を考えます。

注文内容と金額が確定した後、倉庫側は書籍を確保し、決済側は支払いを承認します。この例では、決済の承認までを扱い、実際の売上確定は後の処理とします。

以下は関係と契約を説明するための記述例です。実行可能な構文の仕様は別途定めるものとします。

usecase ReserveOrderBooks
  pre:
    - 注文内容が確定している
  post:
    - 対象の注文に必要な書籍が予約されている
    - 在庫予約の識別子と有効期限が記録されている
usecase AuthorizeOrderPayment
  pre:
    - 注文金額が確定している
    - 支払い方法が指定されている
  post:
    - 対象の注文金額について支払いが承認されている
    - 決済承認の識別子と有効期限が記録されている
usecase ReserveOrderBooks collaborates AuthorizeOrderPayment

協調全体を「注文の出荷準備を整える」とすると、その同期点では次の条件を確認します。

  • 書籍の予約が成立している
  • 支払いの承認が成立している
  • 双方が同じ注文と注文内容の版を対象としている
  • 在庫予約と決済承認が有効である

すべての条件を満たしたところで、注文を出荷可能な状態に更新します。

collaboratesの関係に加え、この同期点と完了条件を定義することで、出荷準備の合成シナリオが具体化します。

同期点

同期点は、複数の経路から得られた結果を合わせて、業務を次へ進められるか判断する場所です。

書籍の確保が先に終わった場合は、在庫予約を保持しながら支払いの承認を待ちます。支払いの承認が先に終わった場合は、承認結果を保持しながら書籍の確保を待ちます。

どちらが先に終わるかにかかわらず、出荷へ進む条件は共通です。

書籍の確保支払いの承認協調全体の扱い
完了処理中承認結果を待つ
処理中完了在庫予約の結果を待つ
完了完了結果の対応と有効性を確認し、出荷可能にする
失敗完了出荷を保留し、決済承認の取消しを進める
完了失敗出荷を保留し、在庫予約の解放を進める
完了結果不明決済結果の照会や期限管理を行う

「処理中」「失敗」「結果不明」を分けることで、待機、再試行、補償の判断を具体化できます。

同期の条件

本稿の例では、両方の結果を待つ全件完了型の同期を使っています。

業務によっては、複数の候補のうち一つの結果を採用する場合や、必要な件数の結果が揃えば先へ進める場合も考えられます。その場合は、採用条件と残りの処理の扱いを個別に定義します。

collaboratesを使用する際は、同期点ごとに必要な結果を明示することが重要です。

契約との関係

collaboratesでは、個々のユースケースの契約と、協調全体の契約を分けて記述します。

契約確認する内容
各ユースケースの事前条件個別の処理を開始できるか
各ユースケースの事後条件個別の処理がどの結果を提供するか
協調全体の開始条件同じ業務対象について各処理を開始できるか
同期点の条件結果が揃い、組み合わせて利用できるか
協調全体の事後条件利用者にどの結果を約束するか

注文の例では、在庫予約と支払い承認の結果を確認し、注文を出荷可能にしたことが協調全体の事後条件になります。

一方の処理が他方の前提を変更する場合は、その影響も契約に含めます。例えば、書籍の確保中に注文数量が変わると、先に得られた決済承認の金額との対応が崩れます。

そこで、協調の開始時に注文内容の版を固定する、変更時には協調をやり直す、といった方針を定めます。

他の関係との違い

precedesとの違い

precedesは、ユースケース間の実行順序を表します。

A precedes B

では、Aの完了後にBへ進みます。

collaboratesでは、AとBが担当する処理をそれぞれ進め、同期点で結果を合わせます。相互の結果を開始条件として要求せずに進められる部分が、並行化の対象になります。

例えば、在庫の確保後に初めて注文金額が決まる業務なら、その金額を用いる支払い承認には順序が必要です。業務上の依存関係に応じて、precedesによる順序とcollaboratesによる協調を組み合わせます。

triggersとの違い

triggersは、出来事をきっかけに別のユースケースを起動する関係です。

注文受付イベントから在庫予約と支払い承認を起動するなら、triggersで開始の契機を表せます。その後、両方の結果を合わせて出荷可能にする構造をcollaboratesで表します。

起動の契機と、結果を合わせる条件を分けることで、開始から完了までの責務が明確になります。

ensuresとの違い

ensuresは、あるユースケースの正常終了時に必要な結果を表します。

collaboratesは、その結果を得るために複数のユースケースが協調する構造を表します。

注文の出荷準備が「有効な在庫予約と決済承認が揃っていること」を保証する場合、その完了契約はensuresの観点で整理できます。書籍の確保と支払い承認を並行して進め、結果を合わせる構造はcollaboratesの観点で整理できます。

includeとの違い

includeは、別のユースケースのフローを内部へ組み込む関係です。

collaboratesでは、各ユースケースの役割と結果を定め、協調する経路として扱います。独立した進行状態を持ち、結果の待合せが必要となる場面で、その構造を明示するために使用します。

失敗と補償

並行するユースケースでは、一方が完了した後に、もう一方が失敗する場合があります。

注文の例では、在庫予約が成立した後に支払いが拒否されることがあります。この場合は出荷へ進まず、在庫予約を解放します。

反対に、支払いが承認された後に書籍を確保できなかった場合は、決済承認を取り消します。

これらを協調全体の失敗時シナリオとして定義します。

  • どの失敗をもって協調を中断するか
  • 実行中の処理に取消しを要求するか
  • すでに成立した結果をどう補償するか
  • 補償が完了するまでの状態をどう表すか
  • 補償自体が失敗した場合に誰が対応するか

補償が必要な業務では、「失敗」「補償中」「補償完了」「要確認」などを区別すると、進行状態と残った責務を追跡できます。

取消しと遅れて届く結果

取消しを要求した時点で、相手側の処理がすでに完了していることがあります。

例えば、在庫不足によって協調を中断した直後に、決済承認の成功通知が届く場合です。この結果は、中断済みの注文に対する承認として記録し、取消しの対象にします。

協調を中断した後も、実行中だった処理の結果を受け取れるようにし、必要な補償へ接続する設計が必要です。

非同期処理での扱い

在庫管理と決済が別のシステムで動作する場合は、結果の通知を受け取りながら協調状態を更新します。

そのために、次の情報を管理します。

  • 協調する一回の実行を識別するID
  • 対象となる注文IDと注文内容の版
  • 各ユースケースの実行状態と結果
  • 結果の有効期限と待機期限
  • 再試行や補償の状態

同じ注文について再試行が行われる場合は、注文IDに加えて協調の実行IDを使うことで、過去の実行結果との混同を防ぎます。

同じ結果通知が複数回届く場合にも、一つの完了結果として扱う必要があります。同期点を通過して出荷可能にする処理についても、重複した通知によって出荷指示が重複しないように設計します。

待機期限を超えた場合は、結果を照会する、取消しへ進む、担当者による確認に回す、といった方針を定めます。応答がない状態は「結果不明」として扱い、相手側で成立している可能性を確認します。

共有状態の扱い

並行するユースケースが同じデータを更新すると、互いの変更に影響する場合があります。

注文の例では、在庫予約の状態は在庫側、決済承認の状態は決済側が管理し、協調全体の状態は両方の結果を受け取る側が管理する形が考えられます。

更新の責務を分けることで、それぞれの処理が提供する結果と、協調全体を進める判断を対応させやすくなります。

同じ状態への更新が必要な場合には、更新順序や競合検出の方式を実行設計で定めます。collaboratesで協調構造を表し、その構造を安全に実行するための制御を具体化します。

設計上の確認点

collaboratesを使用する際は、次の点を確認します。

  • 共通の業務目的と協調全体の完了条件が明確か
  • 各ユースケースの役割と提供する結果が明確か
  • 並行して進められる範囲と、順序が必要な範囲が分かれているか
  • 同期点で待つ結果と、その有効性を確認できるか
  • 結果を同じ業務対象、同じ実行へ対応付けられるか
  • 失敗、期限切れ、取消し、補償の扱いが定義されているか
  • 重複した通知や遅れて届く結果を扱えるか

レビューでは、正常に両方が完了する場合に加えて、一方だけの完了、片方の失敗、通知の遅延、補償の失敗をシナリオとして確認すると、協調の境界を具体的に検討できます。

まとめ

collaboratesは、複数のユースケースが共通の業務目的に向けて協調する関係です。

  • 各ユースケースに役割と結果を割り当てる
  • 独立して進められる処理を並行する経路として構成する
  • 同期点で必要な結果とその整合性を確認する
  • 協調全体の完了条件に従って次の処理へ進む

この構造を定めることで、在庫予約と支払い承認のように、複数の処理結果を合わせて成立する業務をモデル化できます。

正常時の同期とともに、失敗時の補償や結果不明時の確認を記述すると、各ユースケースの契約を協調全体の契約へ接続できます。

次回は、ユースケース間の競合や排他を表すconflictsを取り上げます。