人狼ゲームからECサイトへ — L3フルパイプラインとQDHEの構造的盲点
シリーズの到達点
1本目でQDHEを設計しテスト凍結+FMEAを導入
2本目で375件GREEN→遊べない問題に直面
3本目で同条件再実行
4本目でv2.1導入→さぼり問題
5本目でフレームワークなしとの対照実験(28/35 vs 14/35)。
7回の人狼ゲーム開発で得た教訓をフレームワークに焼き込み続けてきた。ただし全てTypeScript、全てL1(Lite)、全てゲームという同一条件下での検証だった。
QDHEが本当に汎用的なフレームワークであるためには、別の言語、別のドメイン、別の品質レベルで検証する必要がある。
そこでアパレルECサイトをPython(FastAPI)+React+PostgreSQL+AWS EC2で構築し、L3(Full)のフルパイプラインを初めて実戦投入した。
ECサイトの規模感
| 項目 | 値 |
|---|---|
| バックエンド | Python 3.12 / FastAPI / SQLAlchemy (async) / asyncpg |
| フロントエンド | React 18 / TypeScript / Vite |
| DB | PostgreSQL 16 |
| 認証 | JWT (HS256) + HttpOnly Cookie + bcrypt |
| デプロイ | AWS EC2 + Docker Compose |
| Phase 1 スライス数 | 11(L3×5、L2×4、L1×1) |
| Phase 2 スライス数 | 3(改修モード、L2) |
| バックエンドテスト | 477件 + 79件 |
| フロントエンドテスト | 79件 |
| テスト合計 | 556件 |
| バックエンドコード | 6,702行(68ファイル) |
| テストコード | 14,628行(バックエンド)+ 2,876行(フロント) |
| ドキュメント | 16,786行(74ファイル) |
| 開発期間 | Phase 1: 約6日 / Phase 2: 約1.5日 |
人狼ゲーム7回目(121テスト、2,152行、5スライス)と比べると約4.6倍のテスト数、約3倍のコード量。9テーブル45カラムのRDB、Clean Architecture/DDD設計、JWT認証、在庫排他制御まで含むフルスタックアプリケーション。
なぜECサイトか
人狼ゲームでは試せなかった3つの変数を同時に変えるため。
言語の変更。 人狼ゲーム7回は全てTypeScriptだった。QDHEのREADMEには「言語非依存」と書いてあるが、Python実績がなかった。
レベルの変更。 人狼ゲームは全てL1(Lite)で、Step 3(FMEA/FTA/STPA)をスキップしていた。ECサイトならユーザー認証(個人情報)と決済(金銭)を扱うため、L2/L3が自然に要求される。
ドメインの変更。 ゲームとECサイトは構造が全く異なる。ゲームはフェーズ遷移が中心、ECサイトはCRUD+状態遷移+トランザクション管理が中心。
L3フルパイプラインの初実戦
L1/L2/L3混在のスライス構成
11スライスにそれぞれ適切なレベルを割り当てた。
| スライス | タイプ | レベル | テスト数 | 分析内容 |
|---|---|---|---|---|
| D-core | ドメイン | L3 | 89 | FTA+FMEA+STPA+STPA-Sec |
| D-inventory | ドメイン | L3 | 47 | FTA+FMEA+STPA+STPA-Sec |
| A-auth | アダプター | L3 | 51 | FTA+FMEA+STPA+STPA-Sec |
| S-cart | 状態管理 | L3 | 65 | FTA+FMEA+STPA+STPA-Sec |
| S-order | 状態管理 | L3 | 82 | FTA+FMEA+STPA+STPA-Sec |
| A-payment-mock | アダプター | L2 | 14 | FMEA |
| A-persistence | アダプター | L2 | 45 | FMEA |
| U-auth | UI | L2 | 32 | FMEA |
| U-cart-checkout | UI | L2 | 25 | FMEA |
| U-product | UI | L1 | 23 | スキップ |
| I-checkout-e2e | 統合 | L3 | 9 | — |
全プロジェクトをL3にする必要はない。商品閲覧UI(L1)にFTAやSTPAを適用しても得るものは少ない。一方で決済フロー(S-order)やカート状態管理(S-cart)はL3で徹底的に分析する価値がある。スライスごとにコストを最適配分できるのがQDHEの3段階レベル設計の狙いだ。
FMEAが設計の穴を見つけた
D-coreスライスのStep 3で、FTA+FMEA+STPA+STPA-Secの4本の分析を実施した。FMEAのRPN上位はこうなった。
| 故障モード | RPN | 内容 |
|---|---|---|
| F-ST-01 | 60 | OrderStatus=completed × ReservationStatus=active → 在庫二重ロック |
| F-ST-02 | 60 | OrderStatus=failed × ReservationStatus=active → 永続在庫凍結 |
| F-11 | 60 | OrderStatusとReservationStatusの整合チェック欠落 |
3件とも**状態遷移のクロス分析([ST]カテゴリ)**から検出された。注文ステータスと在庫予約ステータスの直積で、未定義の組み合わせが存在していた。
Plannerは分析結果を受けて設計書への差し戻しを提案した。
- Order.transition(to, actor) インターフェース追加(監査証跡・否認防止)
- OrderStatus × ReservationStatus のクロスバリデーション責務所在の明記
- 全VOを @dataclass(frozen=True) と設計書に明記
Step 4(テストリスト作成)に進む前に設計書を修正した。分析が設計を改善し、改善された設計からテストが生まれる。 V字モデルの左辺(設計→分析→テスト設計)が実際に機能した瞬間だ。
改修モードの初実戦
テスト全GREENだけどインメモリだった
Phase 1(11スライス、556テスト)が完了した。テストは全GREEN、ミューテーションスコアもドメイン層85%超。パイプラインとしては「完了」だ。
ところがデプロイしたら、全リポジトリがインメモリ実装だった。
A-persistenceスライスはSQLAlchemy ORMモデルとリポジトリ実装を作成していたが、それをmain.pyに配線してインメモリ実装を置き換えるステップがパイプラインに存在しなかった。テストは全てモックやドメインエンティティ単体のテストで、インメモリ実装の挙動を検証しているテストは実質ゼロ。
テストが全部通った ≠ システムが動作する。 2本目の記事で学んだはずの教訓が、形を変えてまた現れた。
Phase 2: 改修モードでDB移行
v2.4で導入した改修モード(retrofit_sliced)を使い、インメモリ→PostgreSQLの移行を実施した。3スライス、約2.5時間で完了。
| スライス | テスト数 | 主な作業 |
|---|---|---|
| A-auth-db | 27 | User/TokenリポジトリのDB実装 |
| A-db-adapters | 37 | Inventory/CartのDB実装 |
| I-db-wiring | 20 | DBSessionMiddleware、main.pyのDI切替 |
Phase 1の凍結テスト477件が回帰テストの安全ネットとして機能し、DB移行中にロジックの破壊がないことを継続的に検証できた。テスト凍結の価値がここで発揮された。
デプロイ後に見つかった3件のバグ
全556テストGREEN、DB移行完了、AWS EC2にDockerでデプロイ。ブラウザで動作確認すると、3件のバグが発覚した。
Bug 1: 複数SKUカートで決済が500エラー
複数のサイズ/色のバリアントをカートに入れて決済すると、MultipleResultsFound例外が発生。SKUごとにInventoryReservationが作られるが、get_reservation_by_order_idが1件のみ想定だった。テストはMagicMockで単一Reservationしかテストしておらず、複数SKUの統合パスが検証されていなかった。
Bug 2: エラー時にトランザクションがコミットされる
FastAPIのHTTPExceptionはミドルウェアから見ると正常完了として扱われ、常にcommitが実行されていた。エラー応答時にもPENDINGオーダーやACTIVE予約がDBに残存する。FMEAで「ミドルウェアcommit/rollback条件」を分析していたにもかかわらず、テストが不十分だった。
Bug 3: SKUの表示順序が毎回変わる
ORM relationshipにorder_byがなく、PostgreSQLがヒープ順で返すため。インメモリ実装ではdict挿入順で安定していたので気づかなかった。
3件とも**「モック境界の外側」で発生した問題**だ。テスト3層体系のHIL層(実環境テスト)と本番環境の乖離が根本原因であり、特にI-checkout-e2eのDB依存テスト5件がskipのまま完了していたことが直接的な原因。
コードレビュー結果
Claude Opus 4.7にECサイトのコードを5観点でレビューさせた。
| 観点 | スコア | 一言 |
|---|---|---|
| セキュリティ | 4.0/10 | デモ用途のため運用面は意図的にスコープ外 |
| バックエンド品質 | 7.5/10 | DDD設計は優秀、型安全性と例外処理に改善余地 |
| フロントエンド品質 | 6.5/10 | 動作はするがUX・型安全性・バリデーションが甘い |
| インフラ・DevOps | 3.5/10 | デモ用途のため運用面は意図的にスコープ外 |
| テスト品質 | 8.5/10 | ドメインテストとミューテーションテストは文句なし |
セキュリティとインフラのスコアが低いのは、本プロジェクトがQDHEフレームワークの実力検証を目的としたデモであり、運用面(CI/CD、監視、セキュリティヘッダー等)を意図的にスコープ外としたため。
注目すべきはテスト品質8.5/10とバックエンド品質7.5/10。レビューは以下を評価した。
- ドメイン層のテストが秀逸。境界値(Quantity: 0拒否、1-99許可、100拒否)、精度検証(0.1+0.2==0.3)、不変性検証が網羅的
- Value Object(Money, Quantity)がfrozen dataclassで不変性を保証
- Order.statusが__setattr__オーバーライドで直接変更を防止
- ミューテーションテスト33ファイル、どのミュータントを殺すかがコメントで明記
QDHEが直接影響する領域(テスト品質、ドメイン設計)では高スコアが出ており、QDHEの影響範囲外(インフラ、運用セキュリティ)は低い。フレームワークの守備範囲が明確に可視化された結果だ。
人狼ゲームとの比較
| 指標 | 人狼ゲーム(7回目) | ECサイト |
|---|---|---|
| 言語 | TypeScript | Python + TypeScript |
| 最高レベル | L1 | L3 |
| テスト総数 | 121 | 556 |
| スライス数 | 5 | 11 + 3(改修) |
| ミューテーション最高 | — | 100%(S-cart, A-payment) |
| デプロイ先 | localhost | AWS EC2 |
| FMEA実施 | なし(L1スキップ) | 50ファイルの分析文書 |
| 設計差し戻し | なし | あり(OrderStatus×ReservationStatus) |
| 改修モード | なし | 初実戦(インメモリ→DB) |
変わらなかったもの: テストファーストの基本構造(Step 4→5→6→7)、テスト凍結によるチート防止、品質ゲートによるStep間の遷移制御。これらはPythonでもTypeScriptでも同じように機能した。
変わったもの: L3の分析コスト。D-coreスライスだけでFTA+FMEA+STPA+STPA-Secの分析に約5分、テスト72件の作成に約35分。L1の人狼ゲームでは全5スライスで約40分だったのに対し、L3のD-core単体で同等以上の時間がかかった。品質と速度のトレードオフが数字で見える。
QDHEの構造的盲点
ECサイトの開発を通じて、QDHEの最も大きな構造的盲点が明らかになった。
テストがGREENであることと、システムが動作することは別の話。
Phase 1完了時点で556テスト全GREENだったが、システムの実体は230行のインメモリスタブだった。A-persistenceスライスがDB実装を作っても、それをmain.pyに配線するステップがパイプラインに存在しなかった。
これは2本目の記事で直面した「375件テスト全GREEN、でも遊べない」と本質的に同じ問題だ。テストのスコープが「ドメインロジックの正しさ」に閉じていて、「システムが実際にDBを使って動作するか」まで届いていない。
教訓
- スライス分割時に「配線スライス」(アダプター実装をmain.pyに統合するIタイプスライス)を必須化すべき
- 各Phaseの完了条件に「テストがGREEN」だけでなく「実際のインフラに接続して動作する」を含めるべき
- skipテストにはインフラ依存の解決期限を設定し、未解決skipが残った状態でのStep 10完了を禁止すべき
QDHEの現在地
6本の記事を通じて、QDHEは以下の実績を積み上げた。
実証済み:
- TypeScriptとPythonの2言語で動作
- L1/L2/L3の3レベル全てを実戦投入
- ゲームとECサイトの2ドメインで検証
- スライスモードと改修モードの両方を実戦投入
- 556テスト規模のプロジェクトを完走
- フレームワークなしとの対照実験で品質差を定量化(28/35 vs 14/35)
- FMEAが設計差し戻しを提案し、設計段階で在庫二重ロックを防止
まだ課題:
- テストGREEN ≠ 動作する、の問題がまだ構造的に解決されていない
- L3のコストが重い(D-coreだけで約1日)
- Unfreeze率42.9%(14スライス中6回)は改善の余地あり
- インフラ層の「実装完了」判定基準がない
QDHEは「AIに壊れにくいコードを書かせるフレームワーク」として機能している。ただし「壊れにくいコード」と「動くシステム」の間にはまだギャップがある。テスト3層体系(SIL/HIL/受入)のHIL層を本番環境に近づけること、skipテストの管理を厳格化すること——次の改善ポイントは明確だ。
参考文献
Discussion