第13章:ルールの違いで切る⚖️🧠
第13章 ルールの違いで切る⚖️🧠
この章のゴール🎯✨
- 「ルール(業務ルール)」を見つけて、カードみたいに整理できる🃏📝
- ルールが 似てる/違う を見て、境界(BC)の候補を作れる✂️📦
- 最後に「ルールのまとまり」を 3つ 作れる🧩🧩🧩
1. なぜ「ルール」が境界になるの?⚖️🧱

「同じ商品を扱う」にしても、出品のルールと取引のルールは全然違うよね?😊
「こういう条件のとき、こうしなきゃいけない」っていう決まりごと📌
たとえば学内フリマだと…🛍️🏫
- 出品は1人10件まで!🔟
- 禁止物(薬・危険物など)は出品NG!🚫
- 購入後24時間以内に支払いがないと自動キャンセル!⏰
- 返品できる/できない条件がある!📦↩️
- 手数料はカテゴリによって違う!💰
この「決まり方」が 違う場所 は、境界になりやすいんだよ〜⚖️✨
2) ルールの違いが「境界」を教えてくれる理由🧭✨
ルールで切ると何がうれしいの?🎁 ポイントはこの3つ👇
① 変わるタイミングが違う🌀
- 出品ルールだけ頻繁に変わる(例:禁止物の追加)🧾
- 取引ルールだけ変わる(例:支払い期限の変更)⏳
- 運営ルールだけ変わる(例:通報の扱いを厳しく)🚨
変わる理由が違う=別の“都合”で動いてる、ってことになりがち💡
② 責任者(判断する人)が違う👩💼👩🏫🧑🔧
- 学生の体験を良くしたい人🙂
- お金やトラブルを減らしたい人💰🛡️
- 安全・規約・通報を見てる人🚨📜
責任者が違うと、ルールの言葉も判断もズレやすいよね🌀
③ 例外の出方が違う🌪️
例外が増えるほど、コードも会話もゴチャる😵💫 だから 例外の性質が違う場所 は分けたくなる✂️✨
3) 手順:ルールで境界候補を作る “5ステップ” 🪜🧩
Step 1:ルールを集める🧲📝
ユースケース(出品・購入・発送)から、「決まりごと」を抜くよ🔎✨ “must/should/can’t” っぽい文が見つかったら、それはルール候補📌
Step 2:ルールカードにする🃏
ルールを 1枚=1ルール にするのがコツ! ごちゃ混ぜを防げるよ🧼✨
ルールカードのテンプレ👇
- ルール名:
- だれに関係?(出品者/購入者/運営…)
- いつ発動?(出品時/購入時/発送時…)
- 条件:
- 結果:
- 例外:
- 変わりやすさ:高/中/低
Step 3:カードを「似てるもの同士」で束ねる🧩
束ね方は雑でOK🙆♀️ まずは “ざっくり3束” を目標にするよ🎀
Step 4:束に名前をつける🏷️✨
名前は 業務の言葉 で! 例:Listing(出品) / Trading(取引) / Trust&Safety(安全)など📦
Step 5:境界の確認質問をする❓
束ごとに、こう聞けたら強い💪✨
- 「この束のルール、他の束が知らなくても困らない?」🤔
- 「この束だけ変更しても、他が壊れない?」🔧
- 「この束は誰が責任持つ?」👩💼
4) 学内フリマ例:ルールをカードにしてみよう🛍️🃏
まずは素材として、例のルールを並べるね👇(サンプル)✨
ルール候補(12個)📝
出品まわり(Listingっぽい)📦
- 出品は1人10件まで🔟
- 禁止カテゴリ(危険物など)は出品不可🚫
- 出品タイトルにNGワードがあると掲載停止🛑
- 価格は0円不可&上限あり💰
購入・取引まわり(Tradingっぽい)🤝 5. 購入後24時間以内に支払いがないとキャンセル⏰ 6. 手数料はカテゴリで変わる(例:電子機器は高め)🧾 7. 取引キャンセルは「発送前まで」なら可能📦 8. 返品は「説明と違う/破損」など条件つき↩️
運営・安全まわり(Trust & Safetyっぽい)🛡️ 9. 通報が一定数で自動的に出品を非表示🚨 10. 悪質ユーザーは利用停止(期間/永久)🔒 11. 取引トラブルは運営が仲裁して判断👩🏫 12. 個人情報(住所/連絡先)を本文に書いたらNG🙅♀️
5) 成果物:ルールのまとまり “3つ” を作る🧩🧩🧩
ここからが本番!🎉 さっきの12ルールを、3つの束 に分けるよ✂️✨
まとまり例(サンプル回答)✅
A) Listing(出品ルール)📦📝
- 1 出品数の上限🔟
- 2 禁止カテゴリ🚫
- 3 NGワード🛑
- 4 価格の範囲💰
👉 「出品できる状態か?」を決めるルールたち✨
B) Trading(取引ルール)🤝💸
- 5 支払い期限⏰
- 6 手数料🧾
- 7 キャンセル条件📦
- 8 返品条件↩️
👉 「取引が成立して進められるか?」のルールたち✨
C) Trust & Safety(運営・安全ルール)🛡️🚨
- 9 通報で非表示🚨
- 10 利用停止🔒
- 11 仲裁/判断👩🏫
- 12 個人情報NG🙅♀️
👉 「全体を安全に保つ」ためのルールたち✨
6) “境界っぽい匂い” チェックリスト👃✅
束を作ったら、次をチェックすると精度が上がるよ✨
- ルールの変更理由が同じ?違う?🌀
- 例外の種類が同じ?違う?🌪️
- ルールが参照してる情報が同じ?違う?🗂️
- 「運営判断」が入るかどうか(入る束は別になりがち)👩🏫
- その束の言葉(用語)がブレない?🗣️🔒
7) TypeScriptミニ演習:ルールを “束ごと” にコードへ固定📁🔒
ここでは Listing(出品ルール) だけを、まず小さく実装してみるよ🧸💻 (ポイント:ルールを1関数に詰め込まない ✋💦)
フォルダ案📁
src/contexts/listing/domain/ListingDraft.tssrc/contexts/listing/domain/listingRules.tssrc/contexts/listing/application/publishListing.ts
① 出品の下書き(Draft)型📄
// src/contexts/listing/domain/ListingDraft.ts
export type ListingDraft = {
sellerId: string;
title: string;
priceYen: number;
category: "books" | "gadgets" | "other";
};
export type RuleViolation = {
code: string;
message: string;
};
② ルールは「小さな関数」に分ける🧩
// src/contexts/listing/domain/listingRules.ts
import { ListingDraft, RuleViolation } from "./ListingDraft";
type ListingRule = (draft: ListingDraft) => RuleViolation | null;
const rule_priceMustBePositive: ListingRule = (d) => {
if (d.priceYen <= 0) return { code: "price.nonPositive", message: "価格は1円以上にしてね💰" };
return null;
};
const rule_titleMustNotContainNgWord = (ngWords: string[]): ListingRule => (d) => {
const hit = ngWords.find((w) => d.title.includes(w));
if (hit) return { code: "title.ngWord", message: `タイトルに使えない言葉があるよ🙅♀️("${hit}")` };
return null;
};
const rule_categoryMustNotBeForbidden = (forbidden: Set<string>): ListingRule => (d) => {
if (forbidden.has(d.category)) {
return { code: "category.forbidden", message: "このカテゴリは出品できないよ🚫" };
}
return null;
};
export const validateListingDraft = (draft: ListingDraft): RuleViolation[] => {
const rules: ListingRule[] = [
rule_priceMustBePositive,
rule_titleMustNotContainNgWord(["連絡先", "住所", "電話番号"]),
rule_categoryMustNotBeForbidden(new Set(["gadgets"])), // サンプル:ガジェット禁止にしてみた
];
return rules
.map((r) => r(draft))
.filter((x): x is RuleViolation => x !== null);
};
③ アプリ層(ユースケース)でまとめて判定する🚪✨
// src/contexts/listing/application/publishListing.ts
import { ListingDraft } from "../domain/ListingDraft";
import { validateListingDraft } from "../domain/listingRules";
export const publishListing = (draft: ListingDraft) => {
const violations = validateListingDraft(draft);
if (violations.length > 0) {
return { ok: false as const, violations };
}
// ここではDB保存などはまだやらない(後の章でやるよ🧸)
return { ok: true as const, listingId: "listing_123" };
};
できたらチェック✅🧪
- 「出品ルール」だけが
listingの中に閉じてる?📦 - 取引(支払い期限とか)のルールを混ぜてない?🤝🚫
- 例外が増えても “ルール関数” を追加するだけで済みそう?➕✨
8) AI相棒🤖に頼むと爆速になるところ💨✨
ルール抽出プロンプト(ユースケース文から抜く)🧲
学内フリマのユースケース文を貼るので、
「業務ルール」を1行1ルールで抽出して。
各ルールは「いつ / 条件 / 結果 / 例外(あれば)」も短く付けて。
最後に、似ているルール同士を3グループに束ねて、グループ名も提案して。
ルールの“境界チェック”プロンプト👃✅
この3つのルールグループ案は境界(BC)の候補として妥当?
「変更理由」「責任者」「例外の性質」「必要データ」の4観点で、
混ざって困るポイントがあれば指摘して。改善案も出して。
TypeScript実装の“ルール分割”レビュー依頼🧼
このTypeScriptコードは、業務ルールが1か所にベタ書きになってない?
ルール関数の分割、命名、テストしやすさの観点で改善案を出して。
9) まとめ🧸✨
- ルールは「境界の材料」になりやすい📌
- ルールカードにして、似てるものを束ねると見えてくる🃏🧩
- まずは 3つのまとまり を作れたら大成功🎉🎉🎉
次の章へのつながり🔗⌛
次の 第14章 は「データの寿命で切る」🗄️⌛ 今日作った“ルールのまとまり”が、データ(短命/長命/監査)の分け方にも効いてくるよ✨
参考🔎
TypeScriptの安定版ライン(npmのLatest表示)として 5.9.3 が掲載されている。(npm) TypeScript 5.9 の公式リリースノート。(TypeScript) Bounded Context の説明(Martin Fowler)。(martinfowler.com) TypeScript 5.9 の発表(Microsoft)。(Microsoft for Developers) AI拡張の例として、GitHub Copilot や OpenAI Codex のような支援ツールがある(一般的な名称として本文では例示)。