保守・改善・引継ぎ・終了学習記事全11節Integration
小さな変更を実装し、既存テストを再実行して段階的に反映する
この記事で身につくこと小さく変更し、既存機能が壊れていないかを確認して段階的に反映する流れと、自動確認の役割を説明できる。
記事内目次(19項目)
この記事の会社・人物・データはすべて架空の設定です。実在する会社や案件とは関係ありません。本文のコードはこの記事の作成時に実際にローカルで実行して確認したものです(第7節)。ただし、この演習で作る
canWithdrawは「提出済み→下書き」という、05-02の状態遷移表に無い遷移を扱います。演習は判定関数を小さく作って再検証の流れを確かめるもので、遷移表・権限表への正式な追加を決めたものではありません。実際の配置・段階的反映も行っていません。
この記事は何の話か。13-01で「追加を検討」とした「提出済みの依頼を取り下げたい」を、小さな単位(取り下げ可否を判定する関数)で実装し、新規テストと既存のテスト(09-01のテストケース)の両方を実行して、既存機能への影響がないことを確認する話です。
なぜ必要か。13-02では大きな変更(承認取消)の影響を調べ、見送りとしました。一方、小さな変更であっても、既存機能に影響がないかを確認せずに反映すると、意図しない不具合を生む可能性があります。たとえば取り下げは「依頼の状態」を扱うので、同じ状態を見て判定している承認(canApprove)が知らないうちに壊れていても、新しい機能のテストだけでは気づけません。「変更→既存テストの再実行→絞った範囲で反映」の一巡を、小さな題材で身につけておく必要があります。
この記事を読むとできるようになること。
- 小さく変更し、既存機能が壊れていないかを確認して段階的に反映する流れを説明できる
- 変更を小さな単位で実装し、既存の要件・テスト対応表を再実行して結果を記録できる
- 再検証の範囲を、変更の影響と確認費用から判断できる
- 「既存テストが全件PASS」で何が分かり、何が分からないかを言える
読む順路。この記事は3つの深さで読めます。全部を順に読む必要はありません。
- 基本だけ理解する:第1節→第3節(変更→再検証→反映の一巡)→第4節(判断すること)→第9節。ここまでで、新しい機能のテストだけでは足りない理由と、反映する範囲を絞る考え方が分かります。AIへの依頼は出てきません。
- 作って確かめる:上に加えて第5.1節(13-02の6観点で「取り下げ」をたどる)→第5.2節(新規テスト)→第5.3節(既存テストの再実行)→第5.4節(人が確認したこと)→第6節(実行結果と更新記録)→第7節(確かめたこと・確かめていないこと)。
- 設計判断を深める:上に加えて第8節(全件再実行する条件、反映範囲と拡大条件)。
1. 今回の業務課題と完成するもの
この記事でやることは、13-01で「追加を検討」とした「提出済みの依頼を取り下げたい」という要望を、取り下げ可否を判定する最小の関数(canWithdraw)として実装し、新規テストと、既存の承認可否判定関数(canApprove)のテストケースを再実行して、既存機能への影響がないことを確認することです。
13-02では大きな変更の影響調査を行いましたが、実際に小さな変更を反映する流れはまだ扱っていませんでした。この記事では、それを扱います。
この記事を読み終えると、次のものが手元にできます。
- 更新・再検証コード(
examples/13-03-update-retest/) - 更新記録・再検証結果(変更内容、版、再実行したテスト、結果、影響がなかった範囲の根拠、反映範囲、日時)
2. 前提知識と読む順路
この記事で使う言葉を先に説明します。
段階的に反映する
一言でいうと、変更を一度に全部適用するのではなく、小さな単位に分けて、確認しながら反映していくことです。11-03で扱った「対象者・機能・期間を絞る」考え方と同じです。
再検証
一言でいうと、変更した部分だけでなく、既存の機能(この記事では承認可否の判定)が壊れていないかを、既存のテストを再実行して確認することです。
これがないと、新しい機能を追加したときに、既存の機能に意図しない影響が出ていても気づかず、そのまま反映してしまう可能性があります。
読む順路:改善要望は13-01、変更影響調査は13-02、既存のテストは09-01・記事B、段階的な利用開始は11-03が該当します。この記事の更新記録は、06-03の変更履歴、13-04の引継ぎ資料で使います。
3. 理解する:小さく変更し、確認して反映する流れ
3.1 変更→再検証→反映の一巡
| 段階 | 内容 | 抜けると起きること |
|---|---|---|
| 変更 | 小さな単位(この記事では1つの関数)で実装する | 変更が大きいと、不一致が出たときに原因の箇所を絞れない |
| 再検証 | 新規テストに加え、既存のテストを再実行し、既存機能への影響がないことを確認する | 既存機能が壊れたまま反映され、利用者の申告で初めて気づく |
| 反映 | 再検証の結果をもとに、反映する範囲(11-03と同じ考え方で対象者・機能を絞る)を決める | 全員に一度に広がり、問題が出たときに戻す範囲も大きくなる |
3.2 よくある誤解
「新しい機能のテストさえ通ればよい」。新しい機能(canWithdraw)が正しく動いても、既存の機能(canApprove)に意図しない影響が出ていないかは別に確認する必要があります(第5.3節・第6節)。
「小さな変更だから再検証は不要」。小さな変更でも、既存のコードと同じファイルやデータを扱う場合は、影響がないとは限りません。この記事では、既存テストを再実行して確認します(第8.1節)。
「既存テストが全件PASSなら、既存機能は壊れていない」。全件PASSで分かるのは「既存テストが見ている範囲では、変更前と同じ結果になる」ことまでです。テストが見ていない範囲(画面・保存処理・連携)は分かりません(第7節)。09-01で確かめた検出力の範囲で「壊れていない」と言えます。
「判定関数のテストが通ったから、取り下げ機能は完成」。この演習で作ったのは判定関数だけです。取り下げを実際に使えるようにするには、05-02の遷移表・05-03の権限表への追加、保存処理、画面、手順書の更新が要ります(第5.1節)。
4. 判断すること
小さな変更を反映するときに人が判断することは、次の5つです。
| 判断すること | なぜ判断が必要か | 仮置きしてよいか | 間違えた場合の影響 |
|---|---|---|---|
| 変更の単位(どこまでを1回の変更にするか) | 単位が大きいと、不一致が出たときにどの変更が原因か分からない。単位が小さすぎると、反映のたびに再検証の手間だけが増える | 可(この記事は「判定関数1つ」で仮置き) | 原因の切り分けに時間がかかる、または再検証の負担で続かない |
| 再検証の範囲(新規だけか、既存も全件か) | 変更が既存機能と同じデータ・同じファイルを扱うなら、既存のテストを再実行しないと影響が分からない | 不可(第8.1節の条件で決め、理由を更新記録に書く) | 既存の承認機能が壊れたことに気づかない |
| 「影響がなかった」と言える根拠は何か | 「テストが通った」だけでは、何を見て通ったのかが残らない。変更していないファイルと、再実行したテストの一致を根拠にする | 不可(根拠の無い「影響なし」は書かない) | あとで壊れたときに、いつから壊れていたか追えない |
| 反映する範囲と、広げる条件 | 一度に全員へ広げると、問題が出たときの影響と戻す範囲が大きい | 可(この記事の反映範囲は想定。第8.2節) | 問題が全員に及ぶ、または誰にも使われないまま止まる |
| 不一致が出たら、どこで止めるか | 既存テストに不一致が出た時点で反映を止め、変更を見直す。「新規は通ったから」で進めない | 不可 | 壊れた機能を反映し、12-02の初動を自分で招く |
勝手に決めてはいけないこと:05-02の状態遷移表、05-03の権限表に無い条件を、この演習で「確定した設計」として追加しません。canWithdraw が扱う「提出済み→下書き」は遷移表に無い遷移で、正式に足すかどうかは13-02の影響調査を経て業務の責任者が決めます(第5.1節)。既存テストを再実行せずに、「影響はないはず」と決めつけて反映しません。この記事で実際に配置・段階的反映を行ったかのように書きません。
AIに任せる範囲:判定関数の実装案、新規テストケースの下書き、既存テストの再実行と結果の整形はAIに任せられます。任せてはいけないのは、変更の単位と再検証の範囲の決定、「影響がなかった」と言える根拠の判断、反映する範囲と広げる条件の決定、不一致が出たときに止める判断です。AIが「既存テストも通りました」と報告しても、人が実行結果(第6節)を自分で見て一致を確かめます。
5. 作って確かめる:小さな変更を実装し再検証する
5.1 13-02の6観点で「取り下げ」をたどる(変更の単位を決める)
13-02の変更影響調査は「承認取消」を題材にして見送りになったので、この記事では13-01で「追加を検討」とした「取り下げ」を、同じ6観点で短くたどってから変更の単位を決めます。机上の推定で、実装はこの記事の演習の範囲だけです。
| 観点 | 影響(見た表・行) | この記事の演習で扱う範囲 |
|---|---|---|
| 要件 | REQ-002(依頼者は自分の依頼だけ操作できる)、REQ-005(履歴を残す。取り下げの操作は対象に無い)、REQ-007(状態を戻す+記録を残すの組) | 判定条件(提出済み、依頼者本人)だけ |
| データ | 05-02の遷移表に「提出済み→下書き(取り下げ)」は無い。新しい状態は増やさない | 遷移表は変更しない。判定関数の演習として扱う |
| 連携 | 08-03相当の受け口と画面の操作が要る | 扱わない |
| 権限 | 05-03の権限表に「取り下げ」の列は無い。依頼者本人だけに限る前提で判定条件を書く | 権限表は変更しない。判定条件に「依頼者本人」を含める |
| 運用手順 | 10-03の依頼者の手順に操作の追加が要る | 扱わない |
| 教材 | 05-02、05-03、08-02、記事B、10-03 | 扱わない(正式に足すときに更新する) |
この結果から、変更の単位を「取り下げ可否を判定する関数1つ」に絞ります。既存の canApprove と同じ「依頼の状態」を扱うので、再検証の範囲は既存テスト全件です(第8.1節)。
変更内容(withdraw.js、正本の全文):
// examples/13-03-update-retest/withdraw.js
// 教材演習用:13-01で「追加を検討」とした「提出済みの依頼を取り下げたい」を、小さな単位で実装する。
// 依頼者自身が、提出済みの依頼を下書きに戻せるかどうかを判定する最小の関数。
function canWithdraw(state, isRequester) {
if (state !== "提出済み") return false; // 提出済み以外は取り下げの対象にしない
if (!isRequester) return false; // 依頼者本人以外は取り下げられない(他人の依頼を勝手に戻せない)
return true;
}
module.exports = { canWithdraw };
5.2 新規テスト
期待結果は、実装より先に第5.1節の判定条件から決めます。正常1件・異常2件です。
// examples/13-03-update-retest/run.js(抜粋)
const newCases = [
{ id: "TC-W01", kind: "正常", input: { state: "提出済み", isRequester: true }, expected: true, note: "依頼者本人が提出済みの依頼を取り下げられる" },
{ id: "TC-W02", kind: "異常", input: { state: "下書き", isRequester: true }, expected: false, note: "下書きは取り下げの対象にしない" },
{ id: "TC-W03", kind: "異常", input: { state: "提出済み", isRequester: false }, expected: false, note: "依頼者本人以外は取り下げられない" },
];
5.3 既存テストの再実行
09-01の canApprove のテストケース6件(TC-01〜06)を、変更していない approval.js に対して再実行します。入力と期待値は09-01の対応表と同じです。
// examples/13-03-update-retest/run.js(抜粋)
// 09-01のcanApproveテストケースを、変更していないapproval.jsに対して再実行する。
const existingCases = [
{ id: "TC-01", input: { state: "提出済み", isAssignedApprover: true, isSelf: false }, expected: true },
{ id: "TC-02", input: { state: "下書き", isAssignedApprover: true, isSelf: false }, expected: false },
{ id: "TC-03", input: { state: "承認済み", isAssignedApprover: true, isSelf: false }, expected: false },
{ id: "TC-04", input: { state: "提出済み", isAssignedApprover: false, isSelf: false }, expected: false },
{ id: "TC-05", input: { state: "提出済み", isAssignedApprover: true, isSelf: true }, expected: false },
{ id: "TC-06", input: { state: "", isAssignedApprover: true, isSelf: false }, expected: false },
];
5.4 人が確認したこと
実行結果を見る前に、人が次を確かめます。「テストが通った」を根拠にするには、何を再実行したのかが確かでなければならないからです。
| 確認したこと | 方法 | 結果 |
|---|---|---|
approval.js の関数本体が09-01と同じで、変更していない | diff で examples/09-01-unit-tests/approval.js と比較 | 判定の3行は同一。違いは行末のコメントだけ(実行記録の2.) |
| 既存テストの入力・期待値が09-01の対応表と同じ | 09-01第5.1節の表(TC-01〜06)と run.js の existingCases を1行ずつ照合 | 6件すべて一致 |
| 新規テストの期待結果が第5.1節の判定条件から導ける | 条件(提出済み、依頼者本人)の組合せから正常1・異常2を導き、run.js の newCases の期待値と照合した | 3件とも条件どおり |
| 出力のうち、実行のたびに変わる行はどれか | run.js の2行目は実行時刻を出す | 時刻の行だけが変わり、判定の行は同じ(実行記録の注意) |
6. 実行結果(更新記録・再検証結果)
実行環境:macOS 26.6.2、Node.js v24.18.0(node:assertのみ使用)、2026-09-21に実行。stdout・stderr・終了コードをそのまま記録した実行記録は第9節の run_log.md にあります。stderr は空、終了コードは 0 でした。
$ node run.js
版: v0.2.0-sandbox
実行環境: darwin, Node.js v24.18.0, 2026-09-21T01:00:06.161Z
=== 新規テスト(canWithdraw、13-01の要望に対応する小さな変更) ===
TC-W01 [正常] 入力={"state":"提出済み","isRequester":true} 期待値=true 実行結果=true 判定=PASS(依頼者本人が提出済みの依頼を取り下げられる)
TC-W02 [異常] 入力={"state":"下書き","isRequester":true} 期待値=false 実行結果=false 判定=PASS(下書きは取り下げの対象にしない)
TC-W03 [異常] 入力={"state":"提出済み","isRequester":false} 期待値=false 実行結果=false 判定=PASS(依頼者本人以外は取り下げられない)
=== 既存テストの再実行(09-01のcanApproveテストケース。変更していない) ===
TC-01 入力={"state":"提出済み","isAssignedApprover":true,"isSelf":false} 期待値=true 実行結果=true 判定=PASS
TC-02 入力={"state":"下書き","isAssignedApprover":true,"isSelf":false} 期待値=false 実行結果=false 判定=PASS
TC-03 入力={"state":"承認済み","isAssignedApprover":true,"isSelf":false} 期待値=false 実行結果=false 判定=PASS
TC-04 入力={"state":"提出済み","isAssignedApprover":false,"isSelf":false} 期待値=false 実行結果=false 判定=PASS
TC-05 入力={"state":"提出済み","isAssignedApprover":true,"isSelf":true} 期待値=false 実行結果=false 判定=PASS
TC-06 入力={"state":"","isAssignedApprover":true,"isSelf":false} 期待値=false 実行結果=false 判定=PASS
新規テスト: 3件中3件PASS
既存テストの再実行: 6件中6件PASS(変更の影響がなかったことを確認)
| 変更内容 | 版 | 再実行したテスト | 結果 | 影響がなかった範囲の根拠 | 反映範囲(想定) | 日時 |
|---|---|---|---|---|---|---|
canWithdraw関数の追加(判定関数のみ。遷移表・権限表は未変更) | v0.2.0-sandbox | 新規3件、既存6件(09-01のcanApproveテストケース) | 9件中9件PASS | approval.jsを変更しておらず(diffで確認)、既存6件のテストが全件一致した。根拠が及ぶのは判定関数の単体テストの範囲まで | 依頼者役の取り下げ操作のみから段階的に開始する想定(11-03と同じ考え方。実際の配置は未実施) | 2026-09-21 |
7. 確認結果
実行環境:macOS 26.6.2、Node.js v24.18.0(node:assertのみ使用)、2026-09-21に実行。教材演習用のフォルダ(examples/13-03-update-retest/)の中で行い、approval.js は変えていません。
完了条件との照合:
| 完了条件 | 確認結果 |
|---|---|
| 変更した版が特定できる | 第6節に記載(v0.2.0-sandbox) |
| 既存テストの再実行結果がある | 第5.3節・第6節に記載(6件中6件PASS) |
| 反映範囲と拡大条件がある | 第6節・第8.2節に記載(想定と明記) |
| 「影響がなかった」の根拠が、変更していないファイルと再実行の一致で書かれている | 第5.4節・第6節に記載 |
| 実行記録(stdout・stderr・終了コード)が残っている | evidence_public/phase5b2d-2026-09-21/13-03/run_log.md |
この記事で確かめたこと:canWithdraw が第5.1節の判定条件どおりに動くこと(3件)。approval.js を変えていない状態で、09-01と同じ6件の入力に対して同じ結果が出ること。実行記録の時刻の行以外が決定的であること。
この記事で確かめていないこと:
| 範囲 | 理由 | どこで確かめるか |
|---|---|---|
| 画面・保存処理・連携を通した取り下げ | 判定関数だけを作った。08-02の保存処理・08-03の連携に取り下げは無い | 正式に足すときに、記事Bの対応表に取り下げの行を加えて |
| 「提出済み→下書き」を遷移表・権限表に正式に足してよいか | 業務の責任者の判断が要る(13-02の6観点の「どこで止めるか」と同じ) | 13-02の形で調査し、05-02・05-03を更新する |
| 取り下げ後の履歴(REQ-005・007) | 判定だけで、状態を変える処理と記録を残す処理は作っていない | 08-02・08-04の形で「状態+履歴」を組にして実装したときに |
| 実際の配置と段階的反映 | この記事では配置していない。11-02で配置した範囲にも提出機能は無い | 配置後に11-03の形で |
canWithdraw の検出力(テストが壊れ方を見つけられるか) | 09-01の壊した版の確認はこの記事では行っていない | 09-01第5.4節と同じ方法で |
残る制限:この検証は、関数単体のテストの再実行によるものです。実際の画面・保存処理・連携(08-02、08-03)を通した再検証は、この記事の時点では行っていません。この記事の本文はClaude Codeが作成したもので、業務担当者による内容確認は行っていません。
8. 設計を判断する
8.1 全件再実行する条件と、一部で済ませる条件
| 条件 | 内容 |
|---|---|
| 全件再実行する | 変更した箇所と、既存の機能が同じデータ・同じファイルを扱う場合(この記事のように、承認と取り下げが同じ依頼データの状態を扱う場合) |
| 一部で済ませる | 変更が完全に独立した新しい機能であり、既存のコードを一切変更していないことが明確な場合 |
この記事の変更(canWithdraw)は新しい関数の追加ですが、依頼の状態という同じデータを扱うため、既存の承認可否判定(canApprove)のテストも全件再実行しました。この記事の6件は数秒で終わるので迷いませんが、再実行に時間がかかる場合でも、「同じデータを扱う」なら全件を優先し、一部で済ませるときはその理由を更新記録に残します。
8.2 反映範囲と拡大条件
11-03と同じ考え方で、対象者・機能を絞って段階的に反映します。次の表は反映の想定であり、この記事では配置していません(11-02で配置した範囲は承認可否の判定だけで、提出機能も取り下げもありません)。
| 項目 | 内容(想定) |
|---|---|
| 反映範囲 | 依頼者役による取り下げ操作のみ(承認機能は対象外) |
| 拡大条件 | 一定期間、取り下げ操作で異常の兆候(12-01の失敗ログ・申告)がないことを確認できた場合、対象者を広げる |
| 止める条件 | 既存の承認で不一致・申告が出た場合は、取り下げの反映を止めて11-04の切戻し判断へ |
9. 持ち帰る成果物
| 成果物 | 空欄版 | 記入例 |
|---|---|---|
| 更新記録・再検証結果ひな形(変更内容、版、再実行したテスト、結果、影響がなかった範囲の根拠、反映範囲、日時) | templates/13-03-update-retest_template.md | templates/13-03-update-retest_example.md |
| 更新・再検証コード一式 | examples/13-03-update-retest/(withdraw.js、approval.js、run.js) | 同上 |
| 実行記録(stdout・stderr・終了コード、整形なし) | — | evidence_public/phase5b2d-2026-09-21/13-03/run_log.md |
自分の業務に使うときの手順は次のとおりです。
- 13-02の調査結果や13-01の要望から、小さな単位の変更を選ぶ(6観点で短くたどり、扱わない範囲を書く)
- 変更を実装し、期待結果を先に決めて新規テストを作る
- 既存のテストを再実行し、変更していないファイルと再実行の一致を根拠に、既存機能への影響がないことを確認する
- 不一致が出たら反映を止め、変更内容を見直す
- 反映範囲を絞って段階的に反映し、拡大条件と止める条件を決める
10. 次工程への受渡し
次へ渡すもの:更新記録・再検証結果。
次工程での使われ方:06-03(変更履歴を管理する)の変更履歴に記録します。13-04(引継ぎ・移行・廃止を行う)では、この更新記録を引継ぎ資料の一部として使います。取り下げを正式に足す場合は、13-02の形で6観点を確定し、05-02・05-03・記事Bの対応表を更新してから、11-03の形で段階的に反映します。
前工程へ戻る条件:既存テストの再実行で不一致が見つかった場合は、変更内容を見直します。変更が05-02・05-03の設計に及ぶことが分かった場合は、13-02に戻って影響を調べ直します。
11. 根拠と更新情報
- この記事の会社・人物・データはすべて架空の設定です。
- 変更内容の出所は13-01、既存テストは09-01に基づきます。
- 制作の来歴:本文はClaude Codeが作成しました。第5〜6節のコードは
examples/13-03-update-retest/を正本とし、2026-09-21にmacOS 26.6.2・Node.js v24.18.0の環境で実際に実行して、stdout・stderr・終了コードをevidence_public/phase5b2d-2026-09-21/13-03/run_log.mdに記録しています。人(ユーザー)による実読・内容確認は未実施です。 - 未確認事項:実際の画面・保存処理・連携を通した再検証、実際の配置・段階的反映は、この記事の時点では行っていません。
canWithdrawが扱う「提出済み→下書き」を05-02の遷移表・05-03の権限表に正式に足すかどうかは未決定です。 - 2026-09-21(Phase 5B-2D):読む順路(3つの深さ)、第4節の判断項目、第5.1節に13-02の6観点で「取り下げ」をたどった結果と扱わない範囲、第5.4節「人が確認したこと」(approval.js の diff、テストケースの照合)、第7節の確かめていないこと、第8.2節の止める条件と「想定」の明示、POINT・CHECKLIST・記事間の参照を追加した。第6節の実行結果を2026-09-20の出力から2026-09-21の実測に置き換え、実行記録を evidence_public に追加した(初版には実行記録が無かった)。コード・テストケース・判定結果(9件中9件PASS)・完了条件は変えていない。
