2026年8月31日月曜日

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

本稿では、ユースケース間の関係の一つである ensures(保証関係)を取り上げます。

ensuresは、

  • あるユースケースの完了時に成立していなければならない状態を明示する
  • その状態を成立させるユースケースを関連付ける
  • ユースケースの結果を契約として表現する

ための関係です。

前回取り上げたrequiresが、あるユースケースを開始する前に必要な状態を表すのに対し、ensuresは、ユースケースが正常に完了した時に何が成立していることを保証するかを表します。

ensures

  • マージモード : Append
  • マージ点 : After end
  • 機能 : 事後条件統合
  • 由来 :
    • Requirements Engineeringにおけるpostcondition
    • Design by Contract
    • Goal satisfaction
    • Workflow outcome

ensuresの基本方針

ensuresは、

ユースケースの完了契約を、その結果を成立させる別のユースケースへ接続する関係

です。

UseCase A が UseCase B を ensures する場合、Aの正常終了後に、Bが成立させる状態または保証が、Aの完了契約の一部として成立している必要があることを表します。

例えば、注文を確定した後に、

  • 注文番号が発行されている
  • 注文確定の記録が保存されている
  • 顧客が注文内容を確認できる

必要があるとします。

このとき「注文確定結果を記録する」を独立したユースケースとして定義し、「注文を確定する」がそれをensuresする関係として記述できます。

重要なのは、ensuresが単に

Aの直後にBを呼び出す

という手続き的な関係ではないことです。

ensuresが表すのは、

Aが正常に完了したとみなす時点で、Bが保証する結果も成立している必要がある

という契約上の保証です。

結果をA自身が成立させるのか、Bへ委譲するのか、保存済みの状態を確認するのかは、実行設計で決めます。

マージモードのAppendは、AとBから合成シナリオを構成する場合に、BをAの後へ配置する基本戦略を表します。ただし、ensuresの契約上の意味と、単純にBを逐次実行するという実現方式は同一ではありません。

シナリオ技術としてのensures

includeやextendはユースケース内部のフロー構造を扱います。

precedesはユースケース間の時間順序を扱い、triggersは出来事に対する反応を扱います。

ensuresは、これらとは異なり、

あるユースケースが完了したと判断できる結果

を扱います。

このためensuresは、ユースケースを単に後ろへ連結するのではなく、

  • どの状態を保証するか
  • その状態を誰が成立させるか
  • 保証できない場合に完了をどう扱うか

を明確にするために使用します。

意味定義

UseCase A が UseCase B を ensures するとは、

Aの完了に必要な結果の一部または全部を、Bの結果が成立させる

ことを意味します。

基本的な流れは次のようになります。

  • Aの本体処理を実行する
  • Aが要求する保証に対応するBを必要に応じて実行する
  • BのPostを確認する
  • Bの結果がAの必要な事後条件を満たしたことを確認する
  • すべての必要な保証が成立した時点でAを正常終了とする

契約としては、次の関係を期待します。

Post(B) => EnsuredPost(A)

ここでEnsuredPost(A)は、Aのすべての事後条件ではなく、Bとのensures関係によって満たされる部分を表します。

直観的整理

  • ensuresは「これが終わったなら、この結果まで成立している」という関係
  • 対象は実行順序そのものではなく、正常終了時の保証
  • 結果を要求する側と、その結果を提供する側を接続する
  • 必要な結果が成立しなければ、対象ユースケースを正常終了にしない

契約との関係

ensuresでは、後続処理の順序よりも、

  • 保証を利用する側のPost
  • 結果を提供する側のPost

の対応が重要です。

UseCase A ensures UseCase B の場合、望ましい関係は次の通りです。

  • Aのどの事後条件をBが満たすのかが分かる
  • BのPostが明確に定義されている
  • Bが失敗した場合、Aの完了を成功として扱わない
  • Bの結果をどの時点で確認できるかが分かる

例えば、注文確定と確認メール送信では、注文の確定自体は成功していても、メール送信が一時的に失敗することがあります。

このとき、

  • メール送信までを注文確定の必須保証に含める
  • 通知依頼の登録だけを必須保証にする
  • メール送信はtriggersによる独立した後続処理にする

のどれを選ぶかで、完了契約が変わります。

ensuresを設計する際は、利用者に約束する結果と、内部的に後から実行できる処理を区別する必要があります。

ensuresとrequires

requiresは、前提を利用する側から見た関係です。

ensuresは、結果を保証する側から見た関係です。

両者は次のように対応します。

UseCase A ensures  Condition C
UseCase B requires Condition C

ユースケース間の関係として表現する場合は、

UseCase B requires UseCase A
Post(A) satisfies RequiredPre(B)

と整理できます。

ただし、ensuresを記述しただけで、必ず別のユースケースがその結果を利用するとは限りません。

ensuresは提供側の完了契約、requiresは利用側の開始契約です。両方が対応すると、ユースケース間の契約を提供側と利用側の双方から確認できます。

記述例

Pieris Booksで、注文を確定し、その結果を記録する業務を考えます。

usecase RecordConfirmedOrder
  pre:
    - 注文が確定可能である
  post:
    - 注文番号が発行されている
    - 注文確定の記録が保存されている
usecase ConfirmOrder
  pre:
    - 注文内容が検証されている
    - 支払い方法が承認されている
  post:
    - 注文が確定している
    - 注文番号が発行されている
    - 注文確定の記録が保存されている
usecase ConfirmOrder ensures RecordConfirmedOrder

この例では、

  • ConfirmOrderの正常終了には注文確定結果の保存が必要
  • RecordConfirmedOrderの事後条件がConfirmOrderの完了契約の一部を満たす
  • RecordConfirmedOrderが失敗した場合、ConfirmOrderを正常終了として扱わない

という関係になります。

ConfirmOrderの本体とRecordConfirmedOrderを同じトランザクションで実行するかどうかは、ensuresだけでは決まりません。

同じトランザクションで確実に保存する方式も、永続化された実行要求を介して結果成立を追跡する方式も考えられます。いずれの場合も、どの時点をConfirmOrderの正常終了とするかを契約として明確にします。

requiresとの違い

ensuresは、requiresと対になる関係です。

どちらも契約を扱いますが、契約を評価する時点と向きが異なります。

観点requiresensures
本質開始条件完了保証
マージモードPrependAppend
マージ点Before startAfter end
関係AにはBの保証が必要Aの完了はBの結果を保証する
主な契約Post(B)とRequiredPre(A)Post(B)とEnsuredPost(A)
失敗時Aを開始しないAを正常終了にしない
A requires B

は、Aの開始にBの結果が必要であることを表します。

A ensures B

は、Aが正常に完了した時にBの結果まで成立していることを表します。

したがって、

  • 処理を始められる条件を表すなら requires
  • 処理が終わったといえる条件を表すなら ensures

と考えると分かりやすくなります。

precedesとの違い

precedesは、Aの完了後にBへ進む時間的な順序を表します。

ensuresは、Aの完了時にBの結果が成立しているという保証を表します。

観点precedesensures
本質実行順序完了契約
マージモードSequenceAppend
マージ点After endAfter end
Bの失敗ワークフロー上の後続失敗Aの保証不成立
Aとの結合時間的な連結結果を介した契約
A precedes B

では、Aが成功した後にBが開始されます。Bが失敗しても、Aの結果自体は成立済みとして扱える場合があります。

A ensures B

では、Bが提供する結果はAの完了契約に含まれます。Bの結果が成立しない限り、A全体を成功として扱えません。

同じ「Aの後にBを行う」という実装でも、順序を表しているのか、Aの保証を成立させているのかで意味が異なります。

triggersとの違い

triggersは、イベントの発生によって別のユースケースが起動候補になる関係です。

ensuresは、イベントを発行したことではなく、必要な結果が成立したことを要求します。

ConfirmOrder triggers SendOrderConfirmation

と書くと、注文確定イベントをきっかけに確認通知の処理が起動する意味になります。

ConfirmOrder ensures RegisterNotificationRequest

と書くと、ConfirmOrderが正常に完了した時点で、通知要求が確実に登録されていることを意味します。

前者は起動の契機、後者は完了時の保証を表します。

非同期処理を使用する場合は、外部処理そのものの完了ではなく、

  • イベントが永続化されている
  • 実行要求が確実に登録されている
  • 再試行可能な状態になっている

ことをensuresの対象とする設計も有効です。

includeとの違い

includeは、別のユースケースのフローを対象ユースケースの内部へ組み込みます。

ensuresは、対象ユースケースの完了時に必要な結果を表します。

観点includeensures
対象内部フロー完了時の契約
関係動作を組み込む結果を保証する
実行原則として含まれる結果の成立方法は実行設計による
結合フロー構造として強い契約を介した依存

例えば、注文番号発行の手順を注文確定フローの一部として常に組み込みたい場合はincludeとして設計できます。

一方、手順の実装場所にかかわらず「注文番号が発行されていること」を完了条件とする場合はensuresが適しています。

実行時の扱い

ensuresはモデル上の保証関係であり、結果をどのように成立させるかは実行設計で決めます。

代表的な方式は次の三つです。

同一処理型

Aの本体処理と、保証を成立させるBを同じ処理境界で実行します。

  • 同じトランザクションで結果を確定したい
  • Bの失敗時にAの変更も取り消せる
  • 完了時点を一つに定めたい

場合に適しています。

確認型

Aの本体処理後に必要な状態を確認し、成立していなければエラーにします。

  • 結果は別の仕組みによって成立する
  • AからBを直接起動しない
  • 完了境界で契約違反を検出する

場合に適しています。

確実な委譲型

Aの完了前に、Bを後から確実に実行できる要求やイベントを永続化します。

  • 外部サービスとの連携を非同期にしたい
  • 一時的な失敗を再試行したい
  • Aのトランザクションを長時間保持したくない

場合に適しています。

この方式では、

Bの外部効果が完了している

ことではなく、

Bを確実に実行する責務が引き受けられている

ことをAの直接の保証とする場合があります。

どの方式でも、Aを正常終了として外部へ通知する時点で、定義したEnsuredPost(A)が成立している必要があります。

複数のensures

一つのユースケースが複数の結果を保証する場合があります。

usecase ConfirmOrder ensures RecordConfirmedOrder
usecase ConfirmOrder ensures RegisterNotificationRequest

この記述は、

  • 注文確定結果の保存
  • 通知要求の登録

の両方がConfirmOrderの完了に必要であることを表します。

ただし、ensuresだけでは、

  • どちらを先に実行するか
  • 並行して実行できるか
  • 一方の失敗時にどこまで取り消すか

までは決まりません。

保証同士に順序が必要な場合はprecedesなどの関係で明示し、並行実行や補償は実行設計で扱います。

失敗と部分的な成功

ensuresを使用する場合、保証を成立させる処理が失敗した時の扱いを決めておく必要があります。

特に、Aの本体処理が取り消せないのに、Bの保証だけが失敗する場合があります。

例えば、注文は保存されたが、外部の配送サービスへの登録が失敗した場合です。

このような場合は、

  • Aを失敗として返し、再実行可能にする
  • 補償ユースケースでAの結果を取り消す
  • Bを再試行待ちにし、その状態をAの結果として明示する
  • Aの保証を「配送登録」ではなく「配送登録要求の永続化」に狭める

といった設計が考えられます。

重要なのは、実際には成立していない結果を、ensuresとして成立したことにしないことです。

部分的な成功を許す場合は、その状態自体を明示的な結果としてモデル化します。

同期実行と非同期実行

ensuresの結果は、対象ユースケースの正常終了時点で成立している必要があります。

しかし、関連する外部処理のすべてが同期的に完了している必要はありません。

例えば、注文確定後のメール送信を非同期で行う場合、ConfirmOrderが保証する内容を、

- メールが送信されている

ではなく、

- メール送信要求が永続化されている
- 送信処理を再試行できる

と定義できます。

その後のメール送信完了は、別のユースケースのPostとして扱います。

ensuresが表す保証の粒度は、同期・非同期の境界と整合させる必要があります。

他の関係との違い

観点includeextendprecedestriggersrequiresensures
対象フロー構造フロー変形実行順序起動条件開始前提完了保証
本質構造合成条件付き拡張シナリオ連結イベント駆動契約依存結果保証
マージ点任意StepAfter指定After endAfter conditionBefore startAfter end
失敗時の意味内部フロー失敗条件付き拡張失敗後続フロー失敗反応処理失敗対象を開始しない対象を正常終了にしない

つまりensuresは、

別のユースケースを単に後続実行する関係ではなく、その結果を自分の完了契約として引き受ける関係

です。

設計上の注意点

ensuresを使用する際は、次の点に注意します。

  • 正常終了時に外部へ約束する結果を明確にすること
  • BのPostとAのEnsuredPostの対応を確認すること
  • 保証が成立しない場合の失敗、再試行、補償を決めること
  • 同期境界と非同期境界を明示すること
  • 実際に保証できない外部効果を事後条件にしないこと
  • 単純な内部処理をすべて独立ユースケースにしないこと

特に、外部サービスへの通知や連携は、相手側の処理完了までを自分のトランザクションで保証できない場合があります。

その場合は、

  • 自分が確実に保証できる状態
  • 外部処理へ委譲した状態
  • 外部処理が完了した状態

を分けてモデル化します。

また、ensuresの対象を増やしすぎると、一つのユースケースの成功が多数の外部処理に依存し、失敗しやすくなります。

ensuresの対象は、

  • 利用者にとって完了の意味を構成する結果
  • 業務上不可欠な事後条件
  • 独立して契約を定義する価値がある保証

を基本とします。

まとめ

ensuresは、

  • ユースケースの正常終了時に必要な結果を表す関係
  • 対象ユースケースのPostと、結果を提供する側のPostを接続する関係
  • 後続処理の呼び出しではなく、契約を介して保証を表現する仕組み

です。

requiresがユースケースを開始できる条件を扱うのに対し、ensuresは、

ユースケースが完了したといえる条件

を扱います。

ensuresを使用することで、

  • 注文確定時の注文番号発行
  • 予約完了時の予約記録
  • 申請受付時の受付番号発行
  • 更新完了時の監査記録

のような結果を、単なる後続処理ではなく完了契約として表現できます。

次回は、複数のユースケースが並行して協力するcollaboratesを取り上げます。

2026年7月31日金曜日

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

本稿では、ユースケース間の関係の一つである requires(前提関係)を取り上げます。

requiresは、

  • あるユースケースを開始するために必要な状態を明示する
  • その状態を成立させるユースケースを関連付ける
  • ユースケース間の依存を契約として表現する

ための関係です。

前回取り上げたtriggersが、出来事に反応して別のユースケースを起動する関係であるのに対し、requiresは、あるユースケースを開始する前に何が成立していなければならないかを表します。

requires

  • マージモード : Prepend
  • マージ点 : Before start
  • 機能 : 事前条件統合
  • 由来 :
    • Requirements Engineeringにおけるprecondition
    • Design by Contract
    • Goal dependency
    • Workflow prerequisite

requiresの基本方針

requiresは、

ユースケースの開始に必要な契約を、別のユースケースの結果へ接続する関係

です。

UseCase A が UseCase B を requires する場合、Aを開始するために、Bが成立させる状態または保証が必要であることを表します。

例えば、注文を確定する前に、

  • 注文内容が検証されている
  • 購入可能な商品だけが含まれている
  • 金額が確定している

必要があるとします。

このとき「注文を検証する」を独立したユースケースとして定義し、「注文を確定する」がそれをrequiresする関係として記述できます。

重要なのは、requiresが単に

Aの直前にBを必ず呼び出す

という手続き的な関係ではないことです。

requiresが表すのは、

Aの開始時点で、Bが保証する前提が成立している必要がある

という契約上の依存です。

前提がすでに成立している場合にBを再実行するかどうかは、実行設計で決めます。

マージモードのPrependは、AとBから合成シナリオを構成する場合に、BをAの前へ配置する基本戦略を表します。ただし、requiresの契約上の意味と、毎回Bを実行するという実現方式は同一ではありません。

シナリオ技術としてのrequires

includeやextendはユースケース内部のフロー構造を扱います。

precedesはユースケース間の時間順序を扱い、triggersは出来事に対する反応を扱います。

requiresは、これらとは異なり、

あるユースケースを実行可能にするための前提

を扱います。

このためrequiresは、ユースケースを単に時間順に並べるのではなく、

  • どの状態が必要か
  • その状態を誰が保証するか
  • 前提が成立しない場合にどう扱うか

を明確にするために使用します。

意味定義

UseCase A が UseCase B を requires するとは、

Aの開始に必要な条件の一部または全部を、Bの結果が成立させる

ことを意味します。

基本的な流れは次のようになります。

  • Aの開始前にPre(A)を評価する
  • Bが保証する状態に対応する前提を確認する
  • 必要に応じてBを実行し、Post(B)を成立させる
  • Post(B)がAの必要な前提を満たしたことを確認する
  • Aを開始する

契約としては、次の関係を期待します。

Post(B) => RequiredPre(A)

ここでRequiredPre(A)は、Aのすべての事前条件ではなく、Bとのrequires関係によって満たされる部分を表します。

直観的整理

  • requiresは「これを始めるには、先にこの条件が必要」という関係
  • 対象は実行順序そのものではなく、開始時の前提
  • 前提を保証する側と利用する側を接続する
  • 前提が成立しなければ、対象ユースケースは開始しない

契約との関係

requiresでは、起動先の順序よりも、

  • 要求する側のPre
  • 前提を提供する側のPost

の対応が重要です。

UseCase A requires UseCase B の場合、望ましい関係は次の通りです。

  • BのPostが明確に定義されている
  • AのPreのどの部分をBが満たすのかが分かる
  • Bが失敗した場合、Aを開始しない
  • Bの結果がいつまで有効かを判断できる

例えば、認証結果や在庫確認結果には有効範囲や有効時間があります。

一度成立した結果を無期限に利用できるとは限りません。

requiresを設計する際は、

  • 対象となる利用者や注文
  • 状態を確認した時点
  • 結果を利用できる範囲

も前提条件の一部として扱う必要があります。

requiresとensures

requiresは、前提を利用する側から見た関係です。

一方、ensuresは、ユースケースが結果として何を保証するかを表します。

両者は次のように対応します。

UseCase A requires Condition C
UseCase B ensures  Condition C

ユースケース間の関係として表現する場合は、

UseCase A requires UseCase B
Post(B) satisfies RequiredPre(A)

と整理できます。

requiresだけを記述しても、前提を提供する側の保証が曖昧であれば契約は成立しません。

このため、requiresとensuresは、利用側と提供側から同じ契約を確認するための関係として扱えます。

記述例

Pieris Booksで、注文を検証してから注文を確定する業務を考えます。

usecase ValidateOrder
  pre:
    - 注文に商品が含まれている
  post:
    - 注文内容が検証されている
    - 購入できない商品が含まれていない
    - 注文金額が確定している
usecase ConfirmOrder
  pre:
    - 注文内容が検証されている
    - 購入できない商品が含まれていない
    - 注文金額が確定している
  post:
    - 注文が確定している
usecase ConfirmOrder requires ValidateOrder

この例では、

  • ConfirmOrderの開始には検証済みの注文が必要
  • ValidateOrderの事後条件がConfirmOrderの事前条件を満たす
  • ValidateOrderが失敗した場合、ConfirmOrderは開始されない

という関係になります。

ConfirmOrderがValidateOrderのフローを内部に埋め込む、と決めているわけではありません。

すでに同じ注文に対する有効な検証結果が存在する場合は、その結果を確認してConfirmOrderを開始する実行方式も考えられます。

precedesとの違い

requiresは、precedesと混同されやすい関係です。

どちらもユースケースの前後に関係しますが、モデル化している内容が異なります。

観点precedesrequires
本質実行順序開始条件
マージモードSequencePrepend
マージ点After endBefore start
関係Aの後にBを行うAにはBの保証が必要
主な契約Post(A)とPre(B)Post(B)とRequiredPre(A)
前提が成立済みの場合順序に従って実行Bを再実行しない場合がある
A precedes B

は、Aの完了後にBへ進む時間的な順序を表します。

A requires B

は、Aの開始にBの結果が必要であることを表します。

したがって、

  • 一連の業務手順として必ず順番に進むなら precedes
  • 対象ユースケースの開始条件を別のユースケースが保証するなら requires

と考えると分かりやすくなります。

実際の業務では、同じ二つのユースケースに順序と前提の両方が存在する場合もあります。

その場合も、時間的な関係と契約上の依存を分けて考えることが重要です。

includeとの違い

includeは、別のユースケースのフローを対象ユースケースの内部へ組み込みます。

requiresは、対象ユースケースの外側にある前提を表します。

観点includerequires
対象内部フロー開始前の契約
関係動作を組み込む必要な状態を要求する
実行原則として含まれる前提成立済みなら省略可能
結合フロー構造として強い契約を介した依存

例えば、注文確定の処理そのものに注文検証の手順を常に含めたい場合はincludeとして設計できます。

一方、どこで検証されたかにかかわらず「検証済みであること」を開始条件とする場合はrequiresが適しています。

triggersとの違い

triggersは、イベントの発生によって別のユースケースが起動候補になる関係です。

requiresは、イベントの有無ではなく、開始条件が成立していることを要求します。

ValidateOrder triggers ConfirmOrder

と書くと、注文検証の結果として発生したイベントにConfirmOrderが反応する意味になります。

ConfirmOrder requires ValidateOrder

と書くと、ConfirmOrderを開始するにはValidateOrderの保証が必要であるという意味になります。

前者は起動の契機、後者は開始の可否を表します。

実行時の扱い

requiresはモデル上の契約関係であり、前提をどのように成立させるかは実行設計で決めます。

代表的な方式は次の三つです。

確認型

開始時に前提の成立を確認し、成立していなければエラーにします。

  • 前提は別の業務や利用者操作で成立する
  • 対象ユースケースから前提ユースケースを起動しない
  • APIやコマンドの境界で契約違反を検出する

場合に適しています。

必要時実行型

前提が成立していなければ、前提ユースケースを実行します。

  • 前提を対象処理の直前に確立できる
  • 実行しても業務上不自然な副作用がない
  • 前提ユースケースの失敗を対象ユースケースへ伝播できる

場合に適しています。

事前準備型

前提ユースケースを別の時点で実行し、その結果を保存しておきます。

対象ユースケースは、保存された結果の有効性を確認して開始します。

  • 審査
  • 在庫確認
  • 承認
  • 本人確認

のように、準備と本処理の間に時間差がある場合に適しています。

どの方式でも、Aの開始時点でRequiredPre(A)が成立している、というrequiresの意味は同じです。

複数のrequires

一つのユースケースが複数の前提を必要とする場合があります。

usecase ConfirmOrder requires ValidateOrder
usecase ConfirmOrder requires AuthorizePayment

この記述は、

  • ValidateOrderの保証
  • AuthorizePaymentの保証

の両方がConfirmOrderの開始に必要であることを表します。

ただし、requiresだけでは、

  • どちらを先に実行するか
  • 並行して確認できるか
  • 一方の失敗時に他方を取り消すか

までは決まりません。

前提同士に順序が必要な場合はprecedesなどの関係で明示し、並行実行や補償は実行設計で扱います。

同期実行と非同期実行

requiresの前提確認は、対象ユースケースを開始する前に完了している必要があります。

しかし、前提を成立させる処理そのものが、対象ユースケースと同じ同期処理の中で実行される必要はありません。

例えば、審査ユースケースを非同期で実行し、その結果を後から利用することもできます。

この場合、

  • 審査を開始する処理
  • 審査完了イベント
  • 審査済み状態
  • 審査済み状態をrequiresするユースケース

を分けてモデル化します。

requiresが表すのは、あくまで対象ユースケースの開始時点における前提の成立です。

他の関係との違い

観点includeextendprecedestriggersrequires
対象フロー構造フロー変形実行順序起動条件開始前提
本質構造合成条件付き拡張シナリオ連結イベント駆動契約依存
マージ点任意StepAfter指定After endAfter conditionBefore start
前提成立済みの場合関係なし条件による順序に従うイベントに反応再実行を省略可能

つまりrequiresは、

別のユースケースの動作を組み込む関係ではなく、その結果を開始契約として利用する関係

です。

設計上の注意点

requiresを使用する際は、次の点に注意します。

  • 必要な前提を業務上の状態として明確にすること
  • BのPostとAのPreの対応を確認すること
  • 前提が成立しない場合の振る舞いを決めること
  • 前提の対象、有効範囲、有効時間を明示すること
  • requiresの循環を作らないこと
  • 単純な入力値検証をすべて独立ユースケースにしないこと

特に、

A requires B
B requires A

のような循環は、どちらも開始できないモデルになります。

複数段のrequiresを使用する場合は、依存グラフとして開始可能性を確認する必要があります。

また、単なるライブラリ関数や内部メソッドへの依存をrequiresとして表現すると、ユースケースモデルが実装詳細で埋まります。

requiresの対象は、

  • 業務上意味のある前提
  • 独立して契約を定義する価値がある処理
  • 複数のユースケースから参照される保証

を基本とします。

まとめ

requiresは、

  • ユースケースの開始に必要な前提を表す関係
  • 要求する側のPreと、提供する側のPostを接続する関係
  • フローの埋め込みではなく、契約を介して依存を表現する仕組み

です。

precedesが時間的な連続性を扱い、triggersが出来事に対する反応を扱うのに対し、requiresは、

ユースケースを開始できる条件

を扱います。

requiresを使用することで、

  • 注文確定前の注文検証
  • 出荷前の在庫引当
  • 契約前の審査
  • 操作前の承認

のような依存を、単なる呼び出し順ではなく契約として表現できます。

次回は、ユースケースの完了によって何を保証するかを表すensuresを取り上げます。

2026年6月30日火曜日

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

本稿では、ユースケース間の関係の一つである triggers(トリガ関係)を取り上げます。

triggersは、

  • あるユースケースの実行や状態変化をきっかけにする
  • 条件が成立した後に別のユースケースを起動する
  • 同期的な手順ではなく、イベント駆動の連携として表現する

ための関係です。

triggers

  • マージモード : EventDriven
  • マージ点 : After condition
  • 機能 : イベント駆動
  • 由来 :
    • Event-driven modeling
    • Domain event
    • Reactive system
    • Workflow event handling

triggersの基本方針

triggersは、

ユースケース間のイベント駆動の起動関係を定義する関係

です。

あるユースケースの途中または完了後に、特定の条件が成立したとき、その条件をイベントとして扱い、別のユースケースを起動することを表します。

precedesが「Aの後にBを行う」という順序関係であるのに対し、triggersは「Aによって発生した事実がBを起動する」という関係です。

したがってtriggersでは、

  • AとBを直列手順として密結合しない
  • Bの起動条件をイベントとして明示する
  • Bが同期的に起動されるか非同期に起動されるかは実行設計で決める

という整理になります。

シナリオ技術としてのtriggers

includeやextendがユースケース内部の構造を扱い、precedesがユースケース間の順序を扱うのに対し、triggersはユースケース間の反応関係を扱います。

例えば、Pieris Booksで次のような業務を考えます。

  • 注文が確定する
  • 在庫引当が必要になる
  • 顧客へ確認メールを送る
  • 配送準備を開始する

これらは「注文確定の後に必ず同じ手順で直列実行する処理」としても書けます。しかし、実際には注文確定という出来事を契機に、複数の後続処理がそれぞれ起動されると考えた方が自然な場合があります。

triggersは、このような

ある出来事に反応して別のユースケースが起動する構造

を表現します。

意味定義

UseCase A が UseCase B を triggers するとは、

A の実行中または完了後に条件 C が成立したとき、B の起動イベントが発生する

ことを意味します。

すなわち、

  • A の実行により事実や状態変化が発生する
  • その事実が条件 C を満たす
  • 条件 C の成立をイベントとして扱う
  • イベントによって B が起動候補になる

という流れになります。

ここで重要なのは、triggersが「Bを手続き的に呼び出す」関係ではないことです。

triggersは、

イベント発生とユースケース起動の関係

をモデル上で明示するための関係です。

直観的整理

  • triggersは「この出来事が起きたら、このユースケースが動く」という関係
  • 順序そのものではなく、起動条件を表現する
  • 後続処理をイベント駆動で分離する
  • 複数のユースケースが同じイベントに反応してもよい

契約との関係

triggersでは、起動元ユースケースの事後条件と、起動先ユースケースの事前条件の間に、イベント条件が入ります。

基本的には次のように整理できます。

  • A の実行により Event E が発生する
  • Event E が B の起動条件を満たす
  • B の Pre(B) が評価される
  • Pre(B) が成立すれば B が実行される

precedesでは Post(A) と Pre(B) の直接的な整合性が重要でした。一方triggersでは、

  • Post(A)
  • Event E
  • Pre(B)

の対応を整理することが重要になります。

望ましい条件は次の通りです。

  • Aの結果からイベントEが明確に導けること
  • イベントEがBの起動理由として妥当であること
  • Bの事前条件がイベントEまたは関連状態から満たせること

このためtriggersは、

  • ensures(事後条件)
  • requires(事前条件)
  • domain event

を結びつける関係として扱うことができます。

記述例

usecase ConfirmOrder pre: - 注文内容が入力されている - 支払い方法が選択されている post: - 注文が確定している - OrderConfirmed が発生している

usecase ReserveStock pre: - OrderConfirmed が発生している - 注文に在庫引当対象の商品が含まれている post: - 在庫が引き当てられている

usecase SendOrderConfirmation pre: - OrderConfirmed が発生している - 顧客の連絡先が登録されている post: - 注文確認通知が送信されている

usecase ConfirmOrder triggers ReserveStock when: - OrderConfirmed

usecase ConfirmOrder triggers SendOrderConfirmation when: - OrderConfirmed

このとき、

  • ConfirmOrder は ReserveStock を手続きとして直接呼び出しているわけではない
  • ConfirmOrder により OrderConfirmed というイベントが発生する
  • ReserveStock と SendOrderConfirmation は、そのイベントに反応して起動される

という関係になります。

precedesとの違い

triggersはprecedesと混同されやすい関係です。どちらもユースケース間の関係を扱いますが、意味は異なります。

観点precedestriggers
本質順序関係イベント駆動
マージモードSequenceEventDriven
マージ点After endAfter condition
起動理由前の処理が終わったから条件を満たすイベントが発生したから
結合度比較的強い比較的弱い
後続処理直列的反応的

precedesは、

Aが終わったらBへ進む

という関係です。

triggersは、

Aによってイベントが発生し、そのイベントにBが反応する

という関係です。

したがって、

  • 業務手順としてBがAの次に必ず必要なら precedes
  • Aの結果に反応してBが起動されるなら triggers
  • 同じイベントに複数の後続ユースケースが反応するなら triggers

と考えると分かりやすくなります。

他の関係との違い

観点includeextendprecedestriggers
対象フロー構造フロー変形実行順序起動条件
本質構造合成条件付き拡張シナリオ連結イベント駆動
時間関係なし部分あり条件成立後
結合内部合成内部拡張直列連結反応連携

includeは、共通フローをユースケース内部に埋め込みます。

extendは、条件付きでユースケース内部のフローを拡張します。

precedesは、ユースケース同士を時間順に接続します。

triggersは、イベントや条件を契機として別のユースケースを起動します。

つまりtriggersは、

フローの一部を共有するための関係ではなく、出来事に対する反応を表現する関係

です。

同期実行と非同期実行

triggersはイベント駆動の関係ですが、実装上の実行形態は一つに固定されません。

典型的には次の2つがあります。

  • 同期型 : イベント発生後、同じ処理の流れの中で起動先ユースケースを実行する
  • 非同期型 : イベントを発行し、別のタスクやワーカーが起動先ユースケースを実行する

モデル上のtriggersは、

何が何を起動するか

を表します。

一方で、同期か非同期かは、

  • 実行基盤
  • トランザクション境界
  • エラー処理
  • 再試行
  • 通知やキューの有無

といった設計で決めます。

この分離により、ユースケースモデルでは業務上の反応関係を表現し、実装設計では実行方式を選択できます。

設計上の注意点

triggersを使用する際は、次の点に注意します。

  • イベント名を業務上の事実として定義すること
  • 単なるメソッド呼び出しをtriggersとして表現しないこと
  • 起動条件を曖昧にしないこと
  • 同じイベントに反応するユースケースが増えすぎないようにすること
  • 同期実行と非同期実行の責務を混同しないこと

特に重要なのは、イベントを「命令」としてではなく「事実」として表現することです。

例えば、

  • ReserveStock

というイベント名にすると「在庫を引き当てよ」という命令に見えます。

一方、

  • OrderConfirmed

というイベント名にすると「注文が確定した」という事実になります。

triggersでは、この事実に対して後続ユースケースが反応する、という形にするとモデルが安定します。

まとめ

triggersは、

  • ユースケース間のイベント駆動の起動関係
  • 条件成立後に別のユースケースを起動する仕組み
  • 後続処理を直列手順から分離するための関係

です。

precedesが

時間的な連続性

を扱う関係であるのに対し、

triggersは

出来事に対する反応

を扱う関係です。

この関係を使うことで、

  • 注文確定後の在庫引当
  • 通知送信
  • 配送準備
  • 外部システム連携

のような処理を、ユースケース間のイベント駆動の連携として表現できます。

2026年5月31日日曜日

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

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

precedesは、

  • ユースケース同士を時間的に連結する
  • シナリオを順序として構成する

ための関係です。

precedes

  • マージモード : Sequence
  • マージ点 : After end
  • 機能 : シナリオ連結
  • 由来 :
    • OML(OPEN Modeling Language の precedes relationship)
    • Use Case Scenario Chaining(ユースケースシナリオ連結)
    • Workflow Modeling(ワークフローモデリング)
    • BPMN(Sequence Flow によるプロセス連結)
    • プロセス代数(逐次合成 / sequential composition)

precedesの基本方針

precedesは、

ユースケース間の実行順序を定義する関係

です。

あるユースケースの実行完了後に、別のユースケースが続いて実行されることを表します。

シナリオ技術としてのprecedes

includeやextendがユースケース内部の構造を扱うのに対し、precedesはユースケース同士を時間順に接続し、より大きなシナリオを構成するための関係です。

例えば、

  • 商品を選択する
  • 購入する
  • 出荷する

という一連の業務シナリオは、複数のユースケースへ分割して記述できます。

precedesは、それらのユースケースを順序で接続し、シナリオ全体を構成します。

この考え方は、OMLにおける ordered use cases や use case scenario chaining の流れに位置づけられます。

したがってprecedesは、

ユースケースをシナリオ構築要素として扱うための関係

と考えることができます.

意味定義

UseCase A が UseCase B を precedes するとは、

A の完了後に B が開始される

ことを意味します。

すなわち、

  • A の事後条件(Post(A))が成立した後
  • B の事前条件(Pre(B))が評価され
  • B が実行される

という流れになります。

直観的整理

  • precedesは「前のユースケースが終わったら次へ進む」という関係
  • フローを分割したユースケース同士をつなぐ
  • ワークフロー的な連結を表現する

契約との関係

precedesはフローの関係ですが、

  • Post(A) と Pre(B) の整合性

が重要になります。

望ましい条件は次の通りです。

  • Post(A) が Pre(B) を満たす(または包含する)

これにより、

A の結果がそのまま B の入力条件として利用できる

という自然な連結になります。

この関係は、

  • requires(事前条件)
  • ensures(事後条件)

とも整合的に扱うことができます。

記述例

usecase SelectProduct pre: - 顧客がログインしている post: - 商品が選択されている

usecase Purchase pre: - 商品が選択されている post: - 注文が確定している

usecase SelectProduct precedes Purchase

このとき、

  • SelectProduct の完了後に Purchase が実行される
  • SelectProduct の結果(商品選択済み)が Purchase の前提条件を満たす

という関係になります。

他の関係との違い

観点includeextendgeneralizeprecedes
対象フロー構造フロー変形契約(意味)実行順序
本質構造合成条件付き拡張仕様精緻化シナリオ連結
時間関係なし部分なしあり

precedesは、

  • includeのようにフローを埋め込むのではなく
  • extendのように条件分岐を行うのでもなく
  • generalizeのように型関係を定義するのでもなく

ユースケース同士を時間的に直列接続する

関係です。

include / extend との使い分け

precedesとinclude / extendは混同されやすいですが、役割は明確に異なります。

基本的な整理は次の通りです。

  • include / extend :ユースケース内部の構造を扱う
  • precedes :ユースケース間の時間的関係を扱う

includeとの違い

includeは、

  • フローの一部を共通化し
  • ユースケースの内部に埋め込む

関係です。

したがって、

1つのユースケースの中で自然に記述される処理

に適用します。

一方precedesは、

  • ユースケース同士を順序で接続する

関係であり、

処理の段階(フェーズ)として分離したい場合

に使用します。

extendとの違い

extendは、

  • 条件付きでフローを追加する
  • 例外やオプションを表現する

関係です。

つまり、

同一ユースケースのバリエーション

を表現するためのものです。

一方precedesは、

  • 条件分岐ではなく
  • 時間的な前後関係

を表現します。

使い分けの指針

次の観点で判断すると分かりやすくなります。

  • 同一ユースケース内の処理か? → include / extend
  • 条件による分岐か? → extend
  • 時間的に前後する別の処理か? → precedes

典型パターン

SelectProduct precedes Purchase

Purchase include Payment extend Coupon

Purchase precedes Shipping

このように、

  • precedesで全体の流れ(段階)を構成し
  • include / extendで各ユースケース内部の構造を定義する

という使い分けが自然です。

設計上の注意点

precedesを使用する際は、

  • ユースケースを適切な粒度で分割すること
  • PostとPreの整合性を意識すること
  • 不要な細分化によってフローが分断されすぎないようにすること

が重要です。

特に、

  • 1つのユースケースで表現した方が自然なもの
  • 強く結合した処理

を無理に分割すると、モデルが読みにくくなります。

まとめ

precedesは、

  • ユースケース同士を順序でつなぐ関係
  • ワークフロー的なシナリオ連結を表現する仕組み

です。

契約(Pre/Post)と組み合わせることで、

  • 状態遷移の流れ
  • 処理の段階的構成

を自然に表現することができます。

include / extend / generalize とは異なり、

precedesは

時間的な連続性

を扱う関係であり、

ユースケースを組み合わせて全体シナリオを構築する際の基本的な構成要素となります。

2026年4月30日木曜日

Cozyモデル駆動開発/ユースケース/generalize-syntax

本稿では、ユースケース間のgeneralization関係を前提としたCMLの記述方法について整理します。

設計の前提

generalizationはユースケース間の関係を表すものです。

ここでは、generalizationは「関係の宣言(マーク)」として扱います。

一方で、ユースケースのフローは、include や extend などの構造によって記述します。

したがって本稿では、

  • generalization(関係の宣言)
  • フロー構造(実行の記述)

を明確に分離して扱います。

記述方法

基本形

# UseCase
## PurchaseOnline
### GENERALIZATION
Purchase
### INCLUDE
#### Purchase

この例では、

  • PurchaseOnline が Purchase と関係を持つことを宣言し
  • フローは include によって記述しています

ただし、この2つの関係は現時点では直接結びつけません。

拡張を含む場合

# UseCase
## PurchaseOnline
### GENERALIZATION
Purchase
### INCLUDE
#### Purchase
### EXTEND
#### After payment
- 配送先を登録する

この場合も同様に、

  • GENERALIZATION は関係の宣言
  • INCLUDE / EXTEND はフロー構造

として独立に記述します。

設計の考え方

現段階ではgeneralizationとフロー構造を過度に結び付けていません。

例えば、

  • generalizationしたら必ずincludeする
  • 特定のフロー構造を強制する

といったルールは導入しません。

あくまで、

  • GENERALIZATION は意味の手がかり
  • INCLUDE / EXTEND は実際の構造

として並置します。

今後の展開

generalizationの意味(契約、状態遷移、LSPなど)や、

  • どのようなフロー構造が許されるのか
  • どのような実現方法が妥当なのか

といった点については、今後段階的に整理していきます。

まとめ

本稿では、generalization関係を前提としたCML記述の基本形を示しました。

現時点では、

  • GENERALIZATION は関係の宣言
  • INCLUDE / EXTEND はフロー構造

として扱い、両者を独立に記述するというシンプルな方針を採用します。

この段階的なアプローチにより、

  • 記述のシンプルさを保ちつつ
  • 将来的な意味拡張に対応できる

構造を維持することができます。

2026年3月31日火曜日

Cozyモデル駆動開発/ユースケース/generalize-realization

Pieris Books(ブックカフェ併設のセレクトショップ販売店)のシステム開発プロジェクトを進めています。

前回は、ユースケース間の generalize(汎化)を

  • 契約(Pre/Post)の包含関係
  • 状態遷移断片の精緻化

として定義しました。

本稿では、その generalization をどのように実現するか、すなわち「フロー設計の戦略」について整理します。

本稿の位置づけ

前回:

  • generalize = 契約関係(型)

本稿:

  • generalize を満たすための実現戦略(設計パターン)

つまり、重要な前提として、

  • generalizationはフローを規定しない
  • しかしフローは契約を満たさなければならない

という関係にあります。この実装戦略が本稿のテーマです。

generalizationの実現戦略

generalizationは「意味の包含」であり、フローはその実現手段です。

そのため、複数の実現パターンが存在します。

本稿では代表的な3つを整理します。

  • Template型
  • Extension型
  • Replacement型

Template型(骨格共有)

  • 親ユースケースがフローの骨格を提供し、子ユースケースが一部のステップを差し替える方式

これはいわゆる Template Method に相当します。

特徴

  • フローの構造は親が支配する
  • 子は差分のみを定義する
  • 契約との対応が明確

適用場面

  • 処理手順がほぼ同じ
  • 一部の処理だけ差し替えたい

  • Purchase の中の「支払い処理」を差し替える
  • PurchaseOnline / PurchaseInStore の分岐

評価

  • 一貫性が高い
  • 再利用性が高い
  • ただし柔軟性は低い

Extension型(後付け拡張)

  • 親ユースケースのフローをベースとし、子が追加ステップを挿入する方式

extendに近いが、契約レベルで整合している点が異なります。

特徴

  • 親のフローをベースにする
  • 子は追加責務を持つ
  • 契約は強化される

適用場面

  • 追加機能(ログ、通知、配送など)
  • オプション的な振る舞い

  • Purchase に対して配送登録を追加する PurchaseOnline

評価

  • 柔軟性が高い
  • ただしフローの一貫性は弱くなりやすい

Replacement型(全面再定義)

  • 子ユースケースがフローを完全に再定義する方式

契約だけを共有し、実装は独立します。

特徴

  • フローは完全に独立
  • 契約のみ共通
  • 最も自由度が高い

適用場面

  • 実現方式が大きく異なる
  • UIやチャネルが異なる(オンライン / 店頭など)

  • Purchase と PurchaseOnline が全く異なる手順で実行される

評価

  • 柔軟性が最大
  • 再利用性は低い
  • 設計の一貫性維持が難しい

3つの戦略の整理

観点Template型Extension型Replacement型
フロー共有高い中程度なし
柔軟性低い高い
契約整合明確明確明確
再利用性高い低い

重要なのは、

  • どの方式でも generalizationの契約制約は守られる必要がある

という点です。

まとめ

generalizationは

  • 契約の関係

であり、

その実現は

  • フロー設計の戦略

として分離されます。

この分離により、

  • 型安全な意味定義
  • 柔軟な実行設計

を両立することができます。

  • Template型をDSLとしてどう表現するか
  • 差分記述(override)の記法設計
  • フロー合成の形式化

といった点は、

  • aggregatebehavior や内部DSL

と関連しますが、具体的なアプローチを次回に取り上げる予定です。

2026年2月28日土曜日

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

Pieris Books(ブックカフェ併設のセレクトショップ販売店)のシステム開発プロジェクトを進めています。

要求モデルをCozyモデルとして定義する方法を検討しています。

現在はユースケース間の関係をCML(Cozy Modeling Language)でどのように記述するかという観点で整理を進めています。前回は extend を検討しました。

今回は generalize(汎化) を取り上げます。

generalize

  • マージモード : TypeRefinement
  • マージ点 : N/A(フロー非依存)
  • 機能 : 契約包含(仕様精緻化)
  • 由来 : UML generalization

generalizeの基本方針

Cozyモデルでは、ユースケース間のgeneralizationを

  • ユースケース間の型的関係(契約関係)

として定義します。

具体的なフロー継承方法やsuper展開規則は、generalizationの仕様外とします。

ユースケースの意味定義

Cozyモデルでは、ユースケースを

  • 状態遷移モデルの断片

とみなします。

その意味は、主に次の契約によって定義されます。

  • 事前条件(Pre)
  • 事後条件(Post)

ユースケース U は、

  • ある状態が Pre(U) を満たすとき実行可能であり
  • 実行後の状態は Post(U) を満たす

という仕様を持つものとします。

抽象状態機械は明示的には定義しませんが、

  • 暗黙の抽象状態機械 = ユースケース集合

という位置付けを取ります。

generalizationの定義

UseCase C が UseCase P を generalize するとは、

  • C が P の契約を包含し、意味を精緻化する関係

と定義します。

具体的には、LSP(リスコフの置換原則)的に次を満たすことを要件とします。

事前条件の包含

親の事前条件を満たす状態では、子も実行可能でなければならない。

すなわち、

  • C は P の事前条件を弱めない
  • 子は親より実行可能範囲を狭めてはならない

事後条件の保存

子は、親が保証する結果を壊してはならない。

  • C の事後条件は P の事後条件を包含するか、より強い保証を与える

直観的整理

  • 親が約束することは、子でも必ず成り立つ
  • 子は親より具体的であってよいが、意味を破壊してはならない

このとき、

  • generalization = 状態遷移断片の refinement(仕様精緻化)

とみなすことができます。

フローとの関係

前述した通りCozyモデルでは「generalizationはフローの継承方法を規定しない」というアプローチを取ります。

  • MainFlowは契約を実現するシナリオである
  • 契約が保持される限り、フロー構造は自由である

したがって、

  • super展開の位置
  • テンプレート的骨格継承
  • 差分オーバーライド

といったgeneralization関係にあるユースケース間のフローの関係は仕様としては定めておらず自由な構造を選択することができます。

include / extendとの違い

観点includeextendgeneralize
対象フロー構造フロー変形契約(意味)
本質構造合成条件付き拡張仕様精緻化
型関係なしなしあり
LSP制約なしなしあり

include や extend が

  • シナリオ構造の操作

であるのに対し、generalize は

  • 意味(契約)の包含関係

です。

記述例

usecase Purchase pre: - 顧客が商品を選択している post: - 注文が確定している - 支払いが登録されている

usecase PurchaseOnline generalize Purchase pre: - 顧客が商品を選択している - 顧客がログインしている post: - 注文が確定している - 支払いが登録されている - 配送先が登録されている

このとき、

  • 子は親の事前条件を包含し
  • 親の事後条件を壊していない

ため、generalization関係が成立します。

まとめ

本稿では、generalizeを

  • ユースケース間の型的関係 = 契約包含関係 = 状態遷移断片の精緻化

として定義しました。

generalizationは、

  • フロー構造の継承を規定するものではなく
  • 契約レベルでの意味関係を定義するもの

と位置付けます。

具体的なフロー実現方法(テンプレート的継承、差分オーバーライドなど)は、

  • generalizationを実現するための設計戦略

として、次回検討します。