Decision Quality と設計判断失敗パターン
Decision Quality (DQ) は SDG が体系化した意思決定の質の枠組みで、良い意思決定の条件を6つに分解する。
Frame(解くべき問題の枠組み)
Alternatives(選択肢)
Information(情報)
Values(評価基準)
Sound Reasoning(論理的推論)
Commitment to Action(実行へのコミット)
全体の質は一番弱い要素で決まる、というのがDQの中心的な主張である。意思決定そのものと、その結果は区別する。良い意思決定でも結果が悪いことはあるし、その逆もある。
設計判断の現場で繰り返し観測される失敗の多くは、6要素のうち Frame と Values の2つの取り違えで説明できる。Valuesを 評価軸 として8つに整理し、Frame の取り違えは 支配軸の取り違え として捉える。残りの4要素も副次的に絡む。早合点 は Information の信頼性問題、名ばかりの完了 は Commitment to Action の欠落、車輪の再発明 や 早すぎる抽象化 は Alternatives の貧困、場当たり対応 や 越境実装 は Sound Reasoning の論理飛躍として読み下せる。最も弱い要素が全体を律速する、というDQの主張はそのまま設計判断にも当てはまる。
優れたSEは、ここで扱う判断の多くを実務で身につけてきた。ただしそれは暗黙知として個人に蓄積されたもので、言語化された教材も明示的な育成プランもなかった。設計レビューとOJTで継承されてきたが、判断の根拠は属人的だった。Vibe Coding時代には、判断を持つベテランの背中が見える環境が崩れる。エージェントは判断軸を持たないので、暗黙知に依存していた抑止が効かない。失敗パターンの多くはAI以前から現場にあるが、観測される件数と頻度が桁違いに増えている。AIは代替案もメリデメも出すが、自分が「いまどの失敗パターンに入っているか」を自覚しない。その自覚を人間側で持つための整理を試みる。
評価軸の整理
学術的には Decision Analysis の criteria、ATAM の quality attributes、ISO/IEC 25010 の quality characteristics のように、領域ごとにそれぞれ呼び名がある。DQの Values に対応する設計判断の評価基準として、これらを横断する総称を 評価軸 と呼ぶことにする。
設計判断で使う評価軸は、以下の8つに集約できる。
目的適合性: Value-Focused Thinking (Keeney) に対応
制約適合性: Requirements Engineering における functional/non-functional requirements に対応
実現可能性: INCOSE Systems Engineering Handbook の feasibility analysis(技術・経済・運用・スケジュール・法の5側面)。本ページでは 実現可能性(技術) と 実現可能性(組織) の二層で扱う
品質影響: ISO/IEC 25010 の quality characteristics に対応(保守性・運用性などの-ilityを含む)
時間効果: Technical Debt (Cunningham) と Real Options (Matts/Maassen) に対応。短期/長期の時相で読む
リスク・不確実性: Decision Analysis における uncertainty / risk evaluation に対応
整合性: アーキテクチャ整合性の議論に対応。記録手段としての ADR (Nygard)
合意可能性: Decision Quality (SDG) の Commitment to Action に対応
軸を扱う代表的な手法として、複数軸のトレードオフ評価には ATAM (SEI)、要件と制約の整理には INCOSE Systems Engineering Handbook、計画とスケジュールの実現可能性には PMBOK Guide がある。
本ページで使う用語は次のとおり。
評価軸: 設計判断で使う評価基準(criteria)の総称。本ページ独自の呼び方ではなく、学術用語を横断する運用語として扱う
支配軸: いまの判断で最も重視する評価軸(dominant criterion 相当)。原則として1つに絞る
二次条件: 支配軸ほど重視しないが、満たすべき水準を決めておく軸。例えば支配軸を時間効果(短期)にしても、制約適合性を二次条件として最低水準は確保する、という形で使う
実現可能性(技術) / 実現可能性(組織): 前者は「そもそも動くか、技術的に成立するか」、後者は「当該組織のスキル・体制で運用・保守・進化させられるか」を指す。SIerでは後者を見落とすか、逆に過大評価して下方に判断を寄せる失敗が多い
これらは抽象的な評価語彙であり、実際に観測されるのは軸そのものではなく 支配軸の取り違え の方だ。本来の支配軸 ≠ 採用した支配軸 という構造が、別々の症状として現れる。
例:
障害対応なのに、長期的な理想設計を始める
基幹刷新なのに、短期実装容易性だけで選ぶ
セキュリティ問題なのに、UXだけで判断する
PoCなのに、本番運用品質を要求する
本番機能なのに、PoCの速度感で作る
以降に挙げるパターンは、この 支配軸の取り違え が設計判断時に繰り返し現れる。各パターンの 評価軸の偏り は、そのパターンを採ったときに判断者が各軸をどう偏って評価しているかを示している。記法は次のとおり。
↑: 判断者がその軸を過大評価している
↓: 判断者がその軸を過小評価している
不明 / 評価不能: その軸を評価するための情報が揃っていない
時間効果(短期)↑ / 時間効果(長期)↓ のように、同じ軸でも時相が違えば偏りの方向が逆になることもある。この場合「短期効果を過大評価し、長期効果を過小評価している」と読む。
設計判断の失敗パターン
車輪の再発明
標準解があるのに独自実装に逸脱する。
評価軸の偏り
目的適合性↑
整合性↓
実現可能性(技術)↓
品質影響(保守性)↓
典型例
標準の認証ライブラリを使わず、独自トークン認証を作る
Spring Securityで足りるのに、FilterとThreadLocalで独自認可にする
DB制約で表せるものを、アプリ側のif文に押し込む
HTTPステータスコードを使わず、常に200で独自エラーコードを返す
Spring の @Scheduled や Quartz があるのに、Thread と while(true) + sleep で独自スケジューラを書く
敢えて選ぶとき
標準解が要件の一次制約(性能・セキュリティ・契約上の制約)に合わないことを実測または既知の制限として示せる
独自実装によって得られる差別化メリットが、標準からの逸脱コストを明らかに上回る
AIが書くコードは「動く」が、既存フレームワークの正道から外れていることがある。「普通これは自作しない」という判断は、AIからは出てこない。
牛刀をもって鶏を割く
評価軸の偏り
目的適合性↑
実現可能性(技術)↓
時間効果(短期)↓
品質影響(運用性)↓
合意可能性↓
典型例
社内利用30人規模の管理画面を、最初からマイクロサービス4分割で設計する
状態が 下書き → 申請中 → 承認 → 確定 の4段階しかないのにイベントソーシングを導入する
日次500件のCSV取込にKafka + Consumer Group構成を組む
申請→上長承認の1段階しかない承認機能に、Camundaのような汎用ワークフローエンジンを入れる
月次1回のレポート生成バッチを、SparkクラスタとKubernetes CronJobで動かす
入力チェックが「必須」「桁数」「正規表現」程度なのに、Droolsのようなルールエンジンを採用する
敢えて選ぶとき
学習・検証用途のPoCで、その構成自体を試すことが目的であるとき
1〜2年以内に規模が想定水準に達することがロードマップ上で明確に予定されているとき
既存組織が当該基盤の運用ノウハウを既に持っており、運用コストの増分が小さいとき
AIは「よくあるベストプラクティス」を文脈非依存に持ち込みやすい。文脈上の十分性より、一般的に見栄えのよい構成へ寄る、と思っておくとよい。
身の丈に合わない設計
技術的に望ましい構成を選ぶが、運用組織のスキル・人員・オンコール体制を見ていない型。技術側だけで 実現可能性(技術) を満たし、実現可能性(組織) を見ていない。SIerの提案フェーズで「うちの運用が回せるか」を最後まで詰めずに採用が決まり、納品後に保守チームが破綻する典型。
評価軸の偏り
実現可能性(技術)↑
実現可能性(組織)↓
品質影響(運用性)↓
リスク・不確実性↓
典型例
24時間オンコール体制が無いチームに、夜間障害対応を前提とするマルチリージョン構成を採用する
KubernetesやKafkaの運用経験者がいないのに本番採用し、外部ベンダ任せの運用になる
週次リリースのチームに、毎日マージするtrunk-based developmentとデイリーリリースを強制する
DBAがいないのにマルチマスター構成や複雑なシャーディングを最初から組む
SREがいないのにSLO/エラーバジェットを掲げて、実態を測れない
リリース承認プロセスが手動の組織に、CDパイプラインを引いてしまう
敢えて選ぶとき
スキル獲得計画と移行スケジュールがセットで合意されているとき。教育期間と外部支援の期限を明記する
一定期間ベンダや外部SREに運用を委託することが計画されており、内製化のタイミングまで決まっているとき
エージェントは組織のスキル分布を知らない。望ましい構成 をそのまま提案するので、運用側の現実とぶつかる。エージェントへの指示に 運用チームのスキル前提 を書いておかないと、毎回ベストプラクティス側に寄る。
羹に懲りて膾を吹く
運用組織のスキルを過小評価して、技術的に劣る選択をする型。判断者がチームのスキルを実態より低く見積もり、うちには無理 保守できない という言葉で標準解や適切な抽象化を退ける。SIerの保守容易性を錦の御旗にした下方迎合の判断として頻発する。
評価軸の偏り
実現可能性(組織)↓
リスク・不確実性↑
品質影響(保守性)↑
品質影響(進化性)↓
時間効果(長期)↓
整合性↓
典型例
Java の Lambda / Stream API を「読めない人がいる」と禁止し、すべて拡張for文で書かせる
Optional を「意味が伝わらない」と禁止し、戻り値の null 判定を呼び出し側に書かせ続ける
TypeScriptを導入できる場面でも「型定義の保守ができる人がいない」とJavaScriptで書き続ける
Git の rebase や squash を「履歴を書き換えるのは危険」と禁止し、merge commitだけで運用する
ビルド自動化・CIを 誰も保守できない と退け、手動リリースを残し続ける
敢えて選ぶとき
組織のスキル獲得計画と移行スケジュールが立てられず、現状維持で凌ぐしかない期間限定の判断であるとき。期限と移行条件を明記する
教育コストとリターンが釣り合わない短命なシステムであるとき
羹に懲りて膾を吹く は技術的負債を意図的に選ぶ判断だが、判断者にも本人にも「現実的判断」と見えるため自覚されにくい。SIerでは「保守容易性」「現場が回ること」が下方迎合の言い訳として機能してきた。スキル獲得の機会を奪う判断であることを意識する必要がある。
場当たり対応
短期的にコードが通るので、判断の手前で止まらない。
評価軸の偏り
時間効果(短期)↑
整合性↓
品質影響↓
時間効果(長期)↓
典型例
エラーを握りつぶして画面だけ進める
既存の責務分離を無視して Controller にロジックを追加する
ドメインルールにすべきものを画面側だけでチェックする
その場のNullPointerExceptionだけ避ける if (x != null) を追加する
テストが落ちるのでテスト期待値を実装に合わせる
敢えて選ぶとき
障害の一次対応として、まず影響範囲を止めることが最優先のとき。適用時刻・差し戻し条件・恒久対応チケットの3点を必ず残す
それ以外で敢えて選ぶ理由は無い。整合性を壊した状態のまま判断を保留すると、恒久対応が立たないまま定着する
時間効果(短期)を支配軸にしたときに起きる典型的な失敗である。生成AIは局所的に通るコードを高速に出すので、ここでブレーキをかけられるのは人間しかいない。
早合点
コマンドが通った テストが緑になった 200が返った を、目的が達成されたことと混同する型。Kindeのspec drift記事が "execution hallucination" と呼んだ現象に対応する。
評価軸の偏り
目的適合性 評価不能
整合性↓
リスク・不確実性↓
典型例
HTTPレスポンスが200 OKなので「動いた」と判断する。実際には副作用が発生していない
DBに書き込んだはずが、INSERTが暗黙に弾かれていても「保存できた」と扱う
外部APIへの送信は成功したが、相手側で受理されていない応答を「成功」と扱う
バッチが完走したので成功と扱う。実際には対象0件で何もしていない
console.logを仕込んだだけで「ログ出力対応済み」とする
マイグレーションがエラーなく終わったので成功と扱う。実際には対象テーブルが存在せずスキップされている
敢えて選ぶとき
敢えて選ぶ理由は無い。実行の戻り値ではなく 業務的な成立条件 を検証する経路に置き換える
暫定で疎通確認だけしたい場合は「いま検証していない」ことを明示し、本来の検証条件をチケットに残す
エージェントは戻り値・終了コードを成功条件と等価に扱う癖がある。成功した と返してきた応答は、コマンドが完走した 以上のことを意味しないと前提しておく必要がある。
見切り発車
要求仕様が定まらないまま実装に着手する型と、要求はあるが実装側の作戦が無いまま着手する型の両方を含む。前者は外側の不在、後者は内側の不在で、どちらも 動くものができるまで判断を保留する 形になる。時間的プレッシャーやリソース効率の都合で見切り発車する文脈は、AI以前から現場にあった。
評価軸の偏り
目的適合性 評価不能
制約適合性 評価不能
品質影響 評価不能
時間効果(短期)↑
合意可能性↓
典型例
要求が曖昧なまま画面・API・DBを生成する
受け入れ基準がないまま「動く」ものを作る
業務ルールが未定義なのにバリデーションを実装する
エラー時の業務扱いが未定なのに例外処理を書く
権限制約が未定なのにUIだけ隠す
旧システムとのデータ突合方針が決まる前にデータ移行スクリプトを書き始める
何件・何秒で動くべきかが定まる前に、Redisキャッシュ層を最初から組み込む
敢えて選ぶとき
仕様探索を目的にしたスパイク実装で、最初から使い捨てる前提のとき。削除予定日と削除担当を併記する
動かしてみないと要件が固まらないことが事前に合意されているとき。本実装は別ブランチで仕切り直す
「実装が動く」ことが判断を曇らせる。Vibe Codingは動くものを早く出すので、仕様の空白も方針の空白も実装で埋められたように錯覚する。
早すぎる抽象化
評価軸の偏り
品質影響(変更容易性)↑
目的適合性↓
実現可能性(技術)↓
時間効果(短期)↓
典型例
実装が1種類しかない段階で Strategy パターンを導入する
画面が1つしかない段階で汎用フォームレンダラを作る
設定項目を増やす予定が無いのに、設定値をDBに持たせて管理画面を作る
検索条件が name と status の2つしかないのに独自DSLを設計する
1画面・1ファイル形式しか取り込まないのに、汎用CSVインポート基盤を作る
敢えて選ぶとき
敢えて選ぶ理由は無い。変化点が2回以上観測されてから抽象化する(Rule of Three)
例外は、抽象化そのものが学習・実験の目的のとき。本番コードに混ぜずスパイクとして切り離す
flexibility や extensibility という言葉が出たときほど危ない。これは変更容易性を過大評価した失敗である。
制約の後付け
業務システム特有のパターンであり、制約は本体である という前提を取り損ねている。
権限・履歴・監査・冪等性・状態遷移は、後から横付けする部品ではなく、データモデルとユースケース設計に最初から織り込むべきものだ。にもかかわらず、Vibe Codingではまず機能の見える形が早く出てしまうため、制約が「追加実装」として扱われやすい。設計順序の問題は、AI生成の速度が上がるほど顕在化する頻度が増す。
評価軸の偏り
制約適合性↓
リスク・不確実性↓
品質影響↓
典型例
CRUDを作ってから権限を足す
データ更新を作ってから監査ログを足す
削除機能を作ってから履歴要件に気づく
同期連携を作ってから再送・冪等性を足す
住所更新を作ってから過去請求書再発行に気づく
敢えて選ぶとき
敢えて選ぶ理由は無い。新規設計では制約をデータモデルとユースケースに最初から埋め込む
既稼働コードへの追加対応は別問題。制約を満たす経路を追加して旧経路を非推奨化する段階移行とし、段階の終了条件を明記する
過去への忖度
互換性要件の実利用者と保証範囲を確認しないまま、最大限保守的な前提で複雑な解を選ぶ型。過去の利用者を守りすぎる失敗で、後述の 取らぬ狸の拡張点 とは時相が逆向きの兄弟パターンになる。
評価軸の偏り
制約適合性↑
目的適合性↓
実現可能性(技術)↓
品質影響(保守性)↓
時間効果(短期)↓
典型例
既存APIを壊さないため、新旧両方のエンドポイントを並走させ続ける
DBカラムを廃止せず、状態を表す is_deleted is_archived is_suspended が累積していく
列挙型を変更せず、新値を別フィールドで持つ
旧バージョンが出力したJSONを読めるよう、version フィールドで分岐するパース処理が版を重ねるごとに肥大化する
廃止された設定キーを @Deprecated のまま残し、起動時に旧キーを読んで新キーに変換するブリッジを置き続ける
Spring Boot 2系のままでよい理由を作るため、3系の機能を諦めて独自実装で穴埋めし続ける
マイグレーションで既存データを変換せず、新旧両形式を同時にサポートするコードを書く
敢えて選ぶとき
公開API・契約APIで利用者が組織外にいて、移行コストを利用者側に強制できないとき
法令・監査要件で過去のデータ形式やインターフェースを保持する義務があるとき
いずれの場合も 保つ範囲 保つ期限 廃止計画 の3つを明記する。期限なしの互換性保証は採らない
エージェントは「既存コードを壊さない」を強い制約として受け取りやすい。既存テストを通したまま と指示すると、テストの本来意図を疑わずに全部通す方向の最も複雑な解を選ぶ。人間なら「この互換性、本当に必要か」を一次質問にするが、エージェントは制約を額面どおり受け取って解の複雑さを膨らませる。
名ばかりの完了
受け入れ基準は記述されているが、判定可能な粒度に分解されていない型。「正しく表示されること」「適切にログ出力する」のような表面的な記述だけで、実装側もレビュー側も完了を判定できない。見切り発車 が要求や実装方針の不在を指すのに対し、こちらは形式上の完了条件はあるが、検証可能な形をしていない点が違う。
評価軸の偏り
合意可能性↓
目的適合性 評価不能
品質影響 評価不能
典型例
「正しく表示されること」
「必要に応じてエラーにする」
「通常の範囲で高速に動作する」
「現行と同等」
「適切にログ出力する」
「ユーザーが使いやすいこと」
敢えて選ぶとき
敢えて選ぶ理由は無い。完了条件を具体的な入力・状態・期待結果・例外条件に分解してから着手する
これはAI以前からある問題だが、Vibe Codingでは「それっぽい完了条件」をAIが量産するため、検出が一段難しくなる。
越境実装
評価軸の偏り
整合性↓
品質影響(保守性)↓
リスク・不確実性↓
典型例
注文の上限金額判定をドメインではなくControllerに書く
「管理者には削除ボタンを表示する」をBladeテンプレートやJSXの中で直接判定する
集計画面の表示順を確定するため、SQLに ORDER BY CASE WHEN status = 'urgent' THEN 0 ELSE 1 END のような画面都合の式を埋める
夜間バッチに「○○のときはSlackで通知して止める」を埋め込み、運用者の手動再開を前提にする
同じOrderDtoに、JPAの@Columnアノテーションと、画面表示用の@JsonFormatの両方が並ぶ
敢えて選ぶとき
既存構造側にバグがあり、責務本体を直すコストが当面引き受けられないとき。暫定として越境を許す代わりに差し戻し条件と恒久対応チケットを残す
フレームワーク・ライブラリの制約で、本来の責務位置に書けない実装上の理由があるとき。理由をコメントとして残す
AIは「どこに書くべきか」より「どこに書けば今動くか」に寄ることがある。
郷に従わぬ正論
評価軸の偏り
整合性↓
目的適合性↓
実現可能性(技術)↓
典型例
既存コードはチェック例外を業務例外として使い分けているのに、新規コードだけRuntimeExceptionに統一する
ログレベルの方針が決まっているのに、AIが書いたコードだけ全部 info で出力する
サービス層でトランザクションを開く規約なのに、Controllerで @Transactional を付ける
日付処理に既存の独自ユーティリティを使う規約なのに、java.time を直接呼んで書く
テストがJUnit 4の @Rule 構成なのに、新規分だけ JUnit 5 の @ExtendWith で書く
Spring Bootの一般例を、その会社のEAP/Jakarta EE制約にそのまま持ち込む
敢えて選ぶとき
既存規約自体が陳腐化しており、規約改定のレビューを通せるとき。規約の更新と新コードの導入をセットで提案する
既存規約が安全性・セキュリティ上の問題を抱えており、新規分から正論側に揃える方が望ましいとき。移行計画と既存コードの扱いを併記する
これはAIが「一般的Web開発」の知識で空白を埋めることで生まれる。プロジェクトの既存コードを読みに行く動作をAIに強制しない限り、減らない。
隣を見ない再実装
既に存在する関数・クラス・ユーティリティを読まずに、似た役割のものを新規に作る型。Addy Osmaniが言う Comprehension Debt の典型的な発生経路である。
評価軸の偏り
整合性↓
品質影響(保守性)↓
合意可能性↓
典型例
共通日付ユーティリティが既にあるのに、formatDate dateToString toIsoDate が並列に増えていく
Repository層を経由する規約なのに、新しいService内で直接SQLを書く
バリデーション規則が共通化されているのに、追加画面で同じ規則をローカル関数で書き直す
認可チェックがDecorator/Interceptorに集約されているのに、新規エンドポイントだけControllerの先頭で個別判定する
既存の Money クラスがあるのに、新しい計算ロジックで BigDecimal を直接扱う
同じドメインの定数が Constants.java にあるのに、別ファイルに再定義する
敢えて選ぶとき
既存実装に重大な制約(性能・互換性・既存利用箇所の凍結)があり、当該箇所だけ別実装にする方が安いとき。既存実装の廃止計画を併記する
既存実装の責務が広がりすぎており、新規分は意図的に切り出すとき。重複ではなく分離の意図であることをコメント等で明示する
エージェントは指示された箇所の周辺だけを読んで実装する傾向がある。まず既存に同じ役割のものがないか探してから書く という動作を明示的に指示しないと、似た関数が並列に増える。CLAUDE.mdに「新規ファイルを作る前に既存コードを検索する」を明記しておくと頻度が下がる。
砂上の依存
存在しないライブラリ・関数・引数シグネチャ・メソッドを呼び出すコードを生成する型。エージェントの訓練データに含まれていた古い情報、もしくは類似ライブラリとの混同が原因になる。package hallucination として研究領域でも観測されている現象。
評価軸の偏り
実現可能性(技術)↓
リスク・不確実性↓
制約適合性↓
典型例
存在しないパッケージを import し、pip install も通ってしまう(攻撃者が同名パッケージを先回りで登録するslopsquattingのリスク)
pandasの df.append(other) のように、過去のバージョンには存在したが現行では削除されたメソッドを呼ぶ
requests.get(url, timeout=5, retry=3) のように、もっともらしいが実在しない引数名を渡す
似た名前の別ライブラリのAPIを混ぜる(lodashとunderscore、momentとdayjs)
社内ライブラリの命名規則から類推した、実在しないユーティリティ関数を呼ぶ
TypeScriptの型定義に存在しないプロパティにアクセスし、@ts-ignore で押し通す
敢えて選ぶとき
敢えて選ぶ理由は無い。新規ライブラリ・新規APIの導入時は、一次資料(公式ドキュメント・ソース)での存在確認と実行確認をセットで行う
実現可能性の確認をエージェントに任せきりにすると、動くように見えるが動かない コードが量産される。ドキュメント参照(context7のようなツール)と実行確認の運用が前提になる。
取らぬ狸の拡張点
早すぎる抽象化と隣接するが、見分け方は次のとおり。
早すぎる抽象化: 変化点がまだ1度も観測されていない段階で抽象化する
取らぬ狸の拡張点: 将来変化が口頭で語られているだけで、時期と責任者と便益が紐づいていない段階で拡張点を作る
偏りの中身も違う。早すぎる抽象化 は 変更容易性 の過大評価が主因で、こちらは 時間効果(長期) の過大評価が主因である。打ち手も別なので分けておく。
評価軸の偏り
時間効果(長期)↑
時間効果(短期)↓
実現可能性(技術)↓
リスク・不確実性↓
典型例
「将来複数DBに対応するかも」と抽象DAOを増やす
「将来メールだけでなくSMS・LINEにも送るかも」と汎用通知基盤を作る
「将来ルールが増えるかも」とDroolsを入れる
「将来多言語化するかも」と全ラベルをメッセージリソース経由にする
「将来別の決済代行を使うかも」と決済プロバイダ抽象層を最初に作る
いずれの「将来」も、誰がいつ実現に責任を持つかが紐づいていない。
敢えて選ぶとき
ロードマップに時期と責任者が紐づいた変化が予定されているとき。コミットされた将来変化に対する拡張点だけを許す
変化点を後から差し込むコストが構造上極端に高い箇所(外部公開API、永続データのスキーマなど)で、最初に拡張余地を確保する方が合理的なとき
それ以外は、変化が観測された時点で抽象化する