コードから作る Claude Code の機能仕様 — シンプルなワークフロー
ルートやコンポーネントから実際のアプリ挙動を抽出して、コードに一致するリビングスペックとギャップリストを作る方法を学びます。

コードと一致する仕様が必要な理由
人はアプリの挙動について意見が分かれます。記憶しているバージョンが違うからです。サポートは最後の荒れたチケットを覚えています。セールスはデモの流れを覚えています。エンジニアはその機能が意図していたことを覚えています。3 人に聞くと 3 つの自信に満ちた答えが返ってきて、現在のビルドとは一致しないことがよくあります。
時間がたつと、コードだけが最新のまま残ります。ドキュメントはずれ、チケットはクローズされ、気軽な修正が積み重なります。ルートに新しいバリデーションが入る。UI のトグルがデフォルトを変える。ハンドラが異なるエラーを返し始める。仕様を更新する人はいません(任意に思えるし、どの変更も小さすぎて記録する価値がないように感じるからです)。
それが予測可能な問題を生みます。チームは存在さえ知らなかったエッジケースを壊す変更を出荷します。QA はハッピーパスだけをテストして、ハンドラに埋もれたルールを見逃します。新しいメンバーは UI から挙動を真似るけれど、実際の制約を理解しません。利害関係者は合意された挙動を指し示す代わりに意見で議論します。
良い結果とは完璧なドキュメントではありません。共有された明確さです。誰もが「もし X をしたら何が起きるか?」「システムは何を保証するか?」を推測せずに答えられるべきです。驚きが減り、レビューサイクルが短くなり、「あ、既にそれできるよ」的な瞬間が減ります。チームが同じ真実を見ているからです。
仕様がコードと一致すれば、変更の計画が安全になります。出荷前に何が安定で何が偶発的で何が欠けているかが見えます。
リビングスペックとギャップリストとは
リビングスペックは、アプリが今日実際にどう振る舞うかを短く編集可能にまとめたものです。1 回きりのドキュメントではありません。振る舞いが変わるたびに更新され、チームが信頼できるものになります。
「コードから書く機能仕様」(例:Claude Code を使う場合)とは簡単に言うと、ルートやハンドラ、画面から実際の挙動を読み取り、それを平易な言葉で書き下すことです。
有用なリビングスペックは、ユーザーが見られることとシステムが約束することに焦点を当てます。カバーすべきは:
- ユーザーに見える挙動(クリック、送信、サインインで何が起きるか)
- ルールと制約(必須フィールド、上限、計算ルール)
- エッジケース(空の状態、エラー、リトライ、タイムアウト)
- 権限(誰が表示/作成/編集/削除できるか)
- 重要な出力(送信されるメール、作成されるレコード、ステータスの変更)
カバーすべきでないのはコードの構成方法です。ファイル名やリファクタ計画を名前で出し始めると実装の詳細に逸れてしまいます。避けるべきは:
- 関数名やクラス名、コンポーネントツリー
- アーキテクチャ論争や書き直し計画
ギャップリストは別物です。仕様を書いている中で見つかった食い違いや不明点を小さなリストにします。
- バグ:コードが現在の振る舞いや合意されたルールに反している
- 機能リクエスト:新しい振る舞いを望むもの
- ギャップ:正しい振る舞いがわからない、または画面/ロール間で不整合があるもの
例:あるルートは 10MB を超えるファイルを拒否するが、UI は 25MB と表示する。チームがどちらが正しいか決めるまではギャップです。
範囲とシンプルな仕様フォーマットを選ぶ
小さく始めてください。アプリ全体をドキュメント化しようとすると、信頼されないメモの山になります。ユーザーが一文で説明できるスライスを選びます(「チームを招待する」「チェックアウト」「パスワードをリセットする」など)。良い範囲は単一の機能領域、1 モジュール、またはエントリから結果までの単一のユーザージャーニーです。
真実がどこにあるかでエントリポイントを選びます:
- 本当のルールが必要なら、ルートとハンドラから始める
- 実際の体験が必要なら、UI のエントリポイントから始める
- 機能が絡み合っているなら、最上位のページ/コントローラから外側へ向かって進める
コードを読む前にいくつかの入力を集めておくと、不一致がすぐに目立ちます:既存の API ドキュメント、古いプロダクトノート、サポートチケット、人々が言う「既知の痛み」など。これらがコードに優先するわけではありませんが、エラーやエッジケース、権限などの欠落状態に気づく助けになります。
仕様フォーマットは地味で一貫したものにします。すべての仕様が同じ読みやすさだとチームは速く合意します。
仕様テンプレート(各ユーザー向けフローごとに繰り返す)
- Purpose: ユーザーが達成しようとしていること
- Entry points: フローが始まる場所(URL、メニュー、ボタン)
- Preconditions: 認証、ロール、必要なデータ
- Main flow: 平易な言葉で 5–10 ステップ
- Data and side effects: 作成/更新されるレコード、送信されるメール、ログ
- Errors and edge cases: 問題が起きたとき何が起きるか
- Open questions: 確認が必要な不明点
この構造を繰り返し使えば、機能仕様は読みやすく、比較しやすく、更新しやすくなります。
ルートとハンドラから挙動を抽出する
まずはサーバのエントリポイントから始めます。ルートとハンドラは「アプリが何をするか」を具体的に示します:誰が呼べるか、何を送る必要があるか、何が返るか、システムで何が変わるか。
対象のルートを一覧にし、それぞれをユーザーの意図にマッピングします。POST /api/orders のように書くのではなく、「注文を確定する」や「下書きを保存する」と書きます。意図を平易に名付けられないなら、それは既に仕様のギャップです。
各ハンドラを読む際には、入力とバリデーションルールをユーザー向け要件として取り込みます。必須フィールド、許容される形式、実際にエラーを発生させるルールを含めます。例:「メールは有効でなければならない」「数量は最低 1」「開始日は過去にできない」など。
認可とロールチェックも同様に書きます。middleware: requireAdmin と書く代わりに、「管理者のみが任意の注文をキャンセルできる。通常ユーザーは 10 分以内に自分の注文のみキャンセルできる」と記述します。コードが所有権、機能フラグ、テナント境界をチェックしているなら、それも含めます。
次に出力と結果を記録します。成功は何を返すか(作成された ID、更新されたオブジェクトなど)?一般的な失敗はどんな形か(401 未認証、403 権限なし、404 見つからない、409 競合、422 バリデーションエラー)?
最後に副作用を記録します。副作用も挙動の一部です:作成/更新されるレコード、送信されるメールや通知、発行されるイベント、キューに入るバックグラウンドジョブ、他のフローをトリガーするものなど。これらは後で仕様に依存するチームを驚かせないために重要です。
コンポーネントと UI フローから挙動を抽出する
ルートはアプリが何をできるかを教えてくれます。コンポーネントはユーザーが実際にどう体験するかを示します。UI を契約の一部として扱ってください:何が表示され、何がブロックされ、問題が起きたらどうなるか。
まず機能のエントリ画面を見つけます。ページコンポーネント、レイアウトラッパー、フェッチや権限、ナビゲーションを制御する「決定」コンポーネントを探します。実際の振る舞いはだいたいそこにあります。
コンポーネントを読むときは、ユーザーが感じるルールを取り込みます:アクションが無効になる条件、必須ステップ、条件付きフィールド、ローディング状態、エラーの表示方法(インラインかトーストか、オートリトライや「もう一度試す」ボタン)など。また、古いデータを一度表示するか、楽観的更新、最後の保存時刻の表示といった状態やキャッシングの挙動も記録します。
ユーザーに見えないフローも注意深く探します。機能フラグ、実験バケット、管理者専用ゲートの記述を検索してください。ログアウトしたユーザーをサインインにリダイレクトする、アクセス権のないユーザーをアップグレード画面に飛ばすといったサイレントなリダイレクトも記録します。
具体例:Change Email 画面では、保存はメールが有効になるまで無効、リクエスト中はスピナーが出る、成功で確認バナーが出る、バックエンドのバリデーションエラーは入力の下に表示される、のように記述します。コード内に newEmailFlow のようなフラグがあれば、両方のバリアントと違いも記録します。
各 UI フローを短いステップ(ユーザーが何をし、UI がどう応答するか)で書き、条件とエラーは影響を受けるステップの横に置きます。こうすると仕様が読みやすくなり、ギャップが見つけやすくなります。
観察結果を読みやすい機能仕様にする
ルートやコンポーネントからの生のメモは有用ですが、議論しにくいことが多いです。観察したことを PM、デザイナー、QA、エンジニアが読んで合意できる仕様に書き直します。
実務的なパターンはルートや画面ごとに 1 つのユーザーストーリーを作ることです。小さく具体的に保ちます。例:「サインイン済みユーザーとして、パスワードをリセットできるのでアクセスを回復できる」など。コードがロールごとに異なる振る舞いを示していれば(管理者と通常ユーザー)、フッタに隠すのではなく別々のストーリーに分けます。
次に受け入れ条件を書きますが、理想のプロダクトではなく実際のコードパスを反映させます。ハンドラがトークン欠如で 401 を返すなら、それが受け入れ条件です。UI がフィールドが有効になるまで送信を無効にするなら、それも条件です。
データルールは平易に書きます。驚きを生むルール(上限、並び順、ユニーク性、必須フィールド)は特に明確にします。「ユーザー名は一意である(保存時にチェックされる)」は「ユニークインデックス」よりわかりやすいです。
エッジケースは良いドキュメントと実用的なドキュメントの差になります。空の状態、null 値、リトライ、タイムアウト、API コール失敗時にユーザーに何が見えるかを明記します。
不明点に当たったら推測せずマークします:
- Unknown: メールが見つからないときにどのメッセージを出すべきか?
- Unknown: 0 個を許容するか、最低 1 個を強制するか?
- Unknown: このエラーはユーザー向けに見せるべきか、それともログだけか?
これらのマーカーがあれば、チームへの簡単な質問に変わり、黙って想定で進むことを防げます。
ギャップリストを作る(ただしバックログにしない)
ギャップリストは第2の Jira にしてはいけません。コードと意図された振る舞いが一致しない箇所、または誰も正しい振る舞いを説明できない箇所を、証拠に基づいて短く記録するものです。うまく運用すれば、合意を得るためのツールになります。
ギャップに含めるべきものを厳格にします:
- 不明瞭な振る舞い:アプリが何かをするがルールがどこにも書かれていない
- 不整合:同じケースに対して場所ごとに振る舞いが違う
- 欠落ルール:エッジケースはあるがコードやドキュメントに決定が見当たらない
ギャップを記録するときは次の 3 つを含めます:
- Type: bug(コードがおかしい)か missing decision(意図が不明)
- Impact: ユーザーの混乱、セキュリティリスク、データ損失、あるいは小さい影響か
- Evidence: どこで何を見たか(route/handler/component)と観察した内容
証拠があればリストは感情論になりません。例:「POST /checkout/apply-coupon は期限切れクーポンを受け付けるが、CouponBanner.tsx は UI でブロックする。影響:収益とユーザー混乱。Type:bug か missing decision(意図を確認する)」
短く保ってください。最初のパスでは上限を 10 件にするなどハードキャップを設定します。もし 40 件見つかれば、パターン(バリデーション不整合、権限チェック、空の状態)にまとめて代表例だけ残します。
ギャップリスト内で日付やスケジュールを入れないでください。所有権が必要なら軽めに:誰が決定すべきか(プロダクト)や誰が振る舞いを検証できるか(エンジニア)をメモして、実際の計画はバックログ側で行います。
実際の機能をコードから文書化する例
小さくトラフィックの多い範囲を選びます:クーポンと配送オプションのあるチェックアウトなど。目的は製品全体を書き直すことではなく、今日アプリが何をするかを捕まえることです。
まずバックエンドのルートから始めます。ルートにルールが現れることが多いです。POST /checkout/apply-promo、GET /checkout/shipping-options、POST /checkout/confirm のようなルートが見つかるかもしれません。
それらのハンドラから、平易な言葉で挙動を書きます:
- プロモコードはサーバ側で検証される(期限切れ、使用上限、顧客の適格性)
- プロモ適用後に合計が再計算されるが、在庫が再確認された後に行われる
- 配送オプションは配送先、重量、アイテムの「restricted」フラグによって決まる
- カート読み込み後に在庫が変わっていると、confirm は失敗する
- 税金は配送が選ばれた後に計算される(プロモ適用時ではない)
次に UI コンポーネントを確認します。PromoCodeInput は成功レスポンスの後にのみ合計が更新され、エラーは入力の下にインラインで表示されるかもしれません。ShippingOptions コンポーネントは最初の読み込みで最安を自動選択し、ユーザーが変更すると価格の内訳が再計算されるかもしれません。
これで読みやすい仕様と小さなギャップリストができます。例:プロモのルートと UI でエラーメッセージが違う("Invalid code" と "Not eligible")、税の丸めルールが明確でない(ラインごとか注文合計か)など。
計画時はまず現状に合意し、それから何を変えるか決めます。意見で議論する代わりに、文書化された振る舞いを見て、一貫性を直すものを一つ選び、残りは「現状の既知の振る舞い」として保留します。
チームで仕様を検証し、最新に保つ
仕様が役に立つのはチームがそれが現状と一致すると合意したときだけです。エンジニア 1 人とプロダクト 1 人で短い読み合わせをします。20〜30 分で、ユーザーが何をできるかとシステムが何を返すかに集中します。
読み合わせでは記述をイエス/ノーの質問に変えます。「このルートに当たるとセッションなしでは常に 403 を返すか?」「この空の状態は意図したものか?」と問い、意図された振る舞いと偶発的に入った挙動を分けます。
編集する前に語彙を合わせます。UI に表示される言葉(ボタンラベル、ページタイトル、エラーメッセージ)を使い、内部名はエンジニアがコードを見つける手助けになる場合にのみ使います。これでプロダクトの言う「Workspace」と仕様の言う「Org」のような食い違いを避けられます。
最新に保つために所有と頻度を明確にします:
- Spec owner: 仕様変更をマージする一人(多くは機能オーナーかテックリード)
- Update trigger: 振る舞い変更の PR マージ時、またはリリースごと
- Quick check: PR テンプレに「Spec updated?」チェックを追加
- Storage: コードに近い場所に置き、コードと一緒に変わるようにする
Koder.ai のようなツールを使う場合、スナップショットやロールバックで更新前後を比較でき、特に大きなリファクタ後に便利です。
よくあるミスと落とし穴
仕様への信頼を失う最速の方法は、あるべき製品を記述して現状を書かないことです。厳密なルール:すべての記述はコードや実際の画面で指し示せる根拠が必要です。
もう一つの落とし穴は、コードの構造をそのままドキュメントに写すことです。「Controller -> Service -> Repository」と読む仕様は仕様ではなくフォルダマップです。ユーザー向けの用語で書いてください:何がトリガーか、ユーザーは何を見るか、何が保存されるか、エラーはどう見えるか。
権限とロールは往々にして最後にまとめられ、そこで破綻します。早い段階でアクセスルールを追加してください。どのロールが閲覧、作成、編集、削除、エクスポート、承認できるか、およびルールがどこで強制されるか(UI のみ、API のみ、両方)を明記します。
ハッピーパス以外を省略しないでください。本当の振る舞いはリトライ、部分的失敗、期限やクールダウンの時間ルールに隠れています。これらを第一級の振る舞いとして扱ってください。
ギャップを表面化する簡単な方法:
- バリデーション失敗とユーザーに見える正確なエラーメッセージを確認する
- 重複送信の扱い(冪等性)
- バックグラウンド処理(キュー、cron)と失敗時の挙動
- 競合(同じレコードを二人が変更した場合)
- 時間ベースの挙動(タイムアウト、有効期限、レート制限)
最後に、ギャップリストを動くものにしてください。各ギャップは「unknown」「needs decision」「bug」「missing feature, plan」のいずれかにラベル付けします。ラベル付けされないとリストは停滞し、仕様は再び死んでしまいます。
共有前の簡単チェックリスト
明確さ、カバレッジ、実行可能性の短いパスを行います。書いた人以外が読んでも今日の機能が何をするか、何が不明か理解できることが目標です。
明確さと共有理解
新しいメンバーが初日に仕様を読んだつもりでチェックします。1 分で機能を要約できれば良い状態です。「どこから始まるか」「ハッピーパスは何か」と聞かれて答えられなければ冒頭を締め直してください。
確認項目:
- ワンページテスト:冒頭にユーザー目標、フローの開始と終了があるか
- ロールとアクセス:主要なロールとそれぞれの出来ること/出来ないこと
- 結果:成功時と失敗時にユーザーが見るもの(メッセージ、リダイレクト、リトライ)
- エッジと制限:サイズ上限、レート制限、タイムアウト、バリデーションルール、データ欠損時の挙動
- 言語:まずユーザー向けの用語を使い、不可避な専門用語は一度だけ定義する
ノイズでなく役立つギャップ
各ギャップは具体的でテスト可能であるべきです。「エラーハンドリングが不明確」ではなく、「支払いプロバイダが 402 を返したとき、UI は汎用トーストを表示する;希望のメッセージとリトライ挙動を確認する」と書き、次のアクション(プロダクトに確認、テストを追加、ログを調査)と回答者を一人書きます。
今週始めるための次のステップ
1 つの機能領域を選び、時間を 60 分に制限してください。ログイン、チェックアウト、検索、管理画面など小さくて実際的なものにします。一文でスコープを書きます:何が含まれ、何が除外されるか。
ワークフローを一度端から端まで実行します:主要なルート/ハンドラをざっと見て、主要な UI フローを追い、観察可能な振る舞い(入力、出力、バリデーション、エラー状態)を書き出します。詰まったら質問をギャップとして残し、先に進んでください。
終わったらチームがコメントできる場所に仕様を共有し、出荷される振る舞いの変更は同じ納品ウィンドウで仕様も更新するというルールを設けます(たとえ 5 行でも)。
ギャップはバックログと分けておき、「unknown behavior」「inconsistent behavior」「missing tests」にまとめ、週次で簡単に見直して今やるべきかを決めます。
ドラフトや反復が遅く感じるなら、Koder.ai のようなチャットベースのビルダーで最初のバージョンを素早く作ると良いでしょう。機能を説明し、主要なスニペットやルート名を貼り付け、会話で表現を磨いてソースをエクスポートできます。目的は速度と共有された明快さであり、プロセスを大きくすることではありません。
よくある質問
既存のコードから機能仕様を書きたいとき、どこから始めればいいですか?
まずは小さく、ユーザーに見える一片(例:「パスワードリセット」や「チーム招待」)から始めます。routes/handlers を読んでルールと結果を取りまとめ、次に UI フロー を読み取ってユーザーが実際に見るもの(無効化状態、エラー、リダイレクト)を拾います。あとは一貫したテンプレートで書き、わからない点は別のギャップリストに記録します。
仕様は製品があるべき姿を書くべきですか、それとも現状のコードの振る舞いを書くべきですか?
原則として、現在のコードの挙動を真実と見なしてドキュメント化します。
挙動が偶発的だったり一貫性がない場合は、仕様で直接“直さない”でください。代わりに、証拠(どこでそれを見たか、どう振る舞うか)を添えてギャップとしてマークし、コードか仕様のどちらを更新するか決めてもらいましょう。
アプリが成長しても読みやすくなる、シンプルな仕様フォーマットは何ですか?
地味で繰り返せるものにしてください。実用的なテンプレートの例:
- Purpose
- Entry points
- Preconditions(認証/ロール/データ)
- Main flow(5〜10ステップ)
- Data and side effects
- Errors and edge cases
- Open questions
この形式は読みやすく、ミスマッチを見つけやすくします。
ハンドラのバリデーションや認可チェックを、平易な言葉の要件にどう落とし込めばいいですか?
コードの注釈ではなく、ユーザー向けの要件として書きます。
例:
- 「メールは有効な形式であること」
- 「数量は最低 1 であること」
- 「管理者のみが任意の注文をキャンセルできる。通常ユーザーは自分の注文のみ、かつ 10 分以内にキャンセルできる」
エラーが発生するトリガーと、ユーザーがそれをどう見るかも記録してください。
仕様にはどのような出力や副作用を含めるべきですか?
観察可能なものに注目してください:
- 成功時の結果(何が変わるか、ユーザーが見るもの)
- よくある失敗の型(未認証、権限なし、見つからない、バリデーションエラーなど)
- 副作用(レコード更新、メール/通知、キュー投入)
副作用は他の機能やサポート/運用に影響するので重要です。
UI とバックエンドでルール(例:ファイルサイズ上限)が異なる場合はどうすればいいですか?
UI と API が食い違う場合は、それを確定するまで ギャップ として記録します。
記録する内容:
- UI が表示/実行すること
- バックエンドが強制していること
- 影響(混乱、セキュリティ、データの問題)
その後、チームでどちらを採用するか決め、コードと仕様の両方を更新します。
ギャップリストをバックログに変えずにどう管理すればいいですか?
ギャップリストは小さく、証拠に基づくことが重要です。各項目には:
- Type: bug または missing decision
- Impact: minor から重大(混乱、セキュリティ、データ損失)
- Evidence: どの route/handler/component で何を観察したか
スケジュール化せず、意思決定のための材料として扱います。
リビングスペックで捉えるべき重要なエッジケースは何ですか?
明確にドキュメント化してください。特に:
- 空の状態(結果なし、権限なし)
- リトライやタイムアウト/その後にユーザーができること
- 重複送信の扱い(ダブルクリック、リロード)
- 同時編集(二人が同じレコードを編集した場合)
- 時間ベースのルール(有効期限、クールダウン)
これらはバグや驚きの主要原因です。
チームに仕様を検証してもらい、信頼を得るにはどうすればいいですか?
短時間で済ませましょう:エンジニア 1 人とプロダクト 1 人で 20〜30 分の読み合わせをします。
文をイエス/ノーで検証する形式にします(例:「このルートにアクセスすると常に 403 を返すか?」)。UI 表示の語彙で揃えると、認識のズレが減ります。
仕様を「生きたもの」に保つにはどうすればいいですか?
コードの近くに置き、出荷の流れに更新を組み込みます。
実務的なルールの例:
- 仕様のオーナーを一人決める(機能オーナーやテックリード)
- 更新トリガー:振る舞い変更のマージ時、またはリリースごと
- PR テンプレに「仕様を更新したか?」チェックボックスを追加
- ギャップは分けて定期的に見直す
小さな頻繁な編集を目標にしてください。