📑 この章の目次
title: 開発プロセス・品質 icon: 🛡️ card_desc: バグを未然に防ぎ・早く見つける仕組み — テスト・Lint・型チェック・レビューの役割分担と「早く見つけるほど安い」思想 slug: 12-quality
12 開発プロセス・品質 — バグを未然に防ぎ、早く見つける仕組み
前章(第11章)では「起きてしまったバグ」を論理的に直す作法を扱いました。本章ではその前段 —— そもそもバグを出しにくくし、出ても早く見つける仕組みを扱います。「直す力」と同じくらい「防ぐ力」が、開発の現場では問われます。
一言でいうと
バグは後になるほど直すコストが跳ね上がります(本番で発覚すれば手元の何倍・何十倍)。だから現場は「人間の目と記憶に頼らず、機械にチェックさせる」仕組みを何層も重ねます。本章では、コードの品質を保つ3つの自動検査 —— テスト・Lint・型チェック —— と、人間のコードレビューの役割分担、そして「早く見つけるほど安い」という工程の思想を扱います。
1. なぜ品質の作法が必要なのか
「後で直す」の罠
締め切り前。「とりあえず動いたから、テストは後で書こう」と検査を後回しにして進める。すると:
- 後で触った時に別の場所を壊す(気づかないまま進む)
- バグが本番のユーザーの目に触れる(クレーム・信用失墜)
- 原因が遠い昔のコードにあって追跡が困難になる
これが第1章で触れた技術的負債の正体です。「後で直す」は借金で、利息(後からの追加コスト)が雪だるま式に膨らみます。
バグの発見は「早いほど安い」
経験則として、バグの発見タイミングと修復コストには桁違いの差があると言われます:
| どこで見つかるか | おおまかなコスト(比) |
|---|---|
| 書いている最中(エディタ・型チェック) | 1 |
| コミット前(手元のテスト・Lint) | 数倍 |
| CI / PR(push 時の自動検査) | 数十倍 |
| 結合テスト・QA | 数百倍 |
| 本番のユーザー | 数千〜数万倍(信用損失を含む) |
※ 数値は文脈による目安ですが、「手元で直すのと本番で直すのとで桁が違う」はほぼ普遍的な傾向です。
だからこそ「できるだけ手前で」バグを見つける仕組みが必要です。第11章は「起きたバグを直す」、本章は「そもそも起きない・出ても早く見つける」の作法です。
2. 「品質を保つ仕組み」とは
4つの防衛線
現場で品質を保つ主な仕組みは、自動検査3つ + 人間の目1つです:
| 仕組み | 何を見つけるか | 誰が/何が見つけるか |
|---|---|---|
テスト(test) |
「期待通り動くか」を実行で確かめる | 機械(自動) |
| Lint(リント) | コードの書き方の問題・バグの種 | 機械(自動) |
型チェック(type check/型検査) |
データの「種類」の矛盾 | 機械(自動) |
| コードレビュー | 設計・可読性・見逃し | 人間 |
※ CI(→ 第1章)は、これら自動検査を「push するたび機械に回させる」土俵です。中身の検査(テスト/Lint/型チェック)があるからこそ、CI の「緑」に意味が出ます。
共通の思想: 機械に任せる
4つすべてに共通する思想は「人間の目と記憶に頼らない」ことです。人間は忘れ・見落とします。「同じ規約を毎回手で確認する」は破綻します。だから一度ルールを書けば、何度でも機械が同じ基準でチェックする仕組みにのせる —— これが品質の作法の根幹です。
3. 🔑 バグを防ぐ3つの自動検査
テスト —— 正しく動くか「実行」で確かめる
テストは「この入力なら、この結果になるはず」を実際に動かして確かめる仕組みです(→ 第1章で既出、ここでは「なぜ書くか」を掘り下げます)。
- 単体テスト(
unit test/ユニットテスト): 関数など最小単位を単独で確かめる。速い・原因が特定しやすい - 統合テスト(
integration test/インテグレーションテスト): 複数の部品を組み合わせた状態で確かめる。現実に近いが遅い
テストの最大の価値は変更時の安全網です。コードを直した時、前まで動いていたものが壊れていないか(= 回帰/regression/リグレッション)を自動で教えてくれます。テストがないと「直したつもりが別を壊した」に気づけません。
💡 テストしやすさも設計: 「テストが書きにくい」コードは、往々にして1つの関数に責務が混ざりすぎているサインです。テストを書きやすい設計は、結果的に読みやすく変更しやすい設計になります。
Lint —— コードの書き方の問題を「静的に」見つける
Lint(リント)は、コードを実行せずに(= 静的解析/static analysis/スタティックアナリシス)、書き方の問題を見つける検査です。リンター(linter/→ 用語集)が担当します。
見つけてくれるもの:
- バグの種: 「使っていない変数」「到達しないコード」「比較と代入の書き間違え(
==と=等)」等、実行しなくても分かる問題 - 可読性・一貫性: チームの書き方規約(インデント・命名 等)の遵守
Lint の強みは速さと完全性です。実行不要なので一瞬で、かつ「全部の行を見る」ので人間の見落としを補います。「インデントが揃っていない」等は人間が直すには退屈で、機械に任せるべき典型です。
型チェック —— データの「種類」の矛盾を見つける
型チェック(type check/型検査)は、データの**「種類(型)」**の矛盾を(これも静的に)見つける検査です。
例:
- 「数値」を期待する関数に「文字列」を渡していないか
null(空であること)の可能性がある値を、確認せず使っていないか
型の矛盾は実行時エラーやバグの代表格です。型チェックを通しておけば「この値は絶対に数値」と機械が保証してくれるため、その类别のバグが構造的に起きなくなります。静的型付き言語(TypeScript・Rust・Go 等)ではコンパイラが、動的型言語(Python 等)では型ヒント+検査ツール(mypy 等)が担います。
3つの役割分担
| 検査 | 得意 | 見つけられない |
|---|---|---|
| テスト | 実際の動作・回帰防止 | 書いていない経路・仕様の誤り |
| Lint | 書き方の問題・バグの種 | 実行時にしか分かる問題・仕様 |
| 型チェック | データの種類の矛盾 | 正しい型だが中身が違う問題 |
どれ1つで完璧にはなりません。3つを重ねて「それぞれの隙間」を埋めるのが、品質を保つ作法です。
4. レビューと「早く見つける」思想
コードレビュー —— 人間が見る最後の砦
自動検査を全通過しても、まだ人間にしか分からない問題が残ります:
- 設計が適切か(もっとシンプルに書けないか)
- 他の人が読んで分かるか(可読性)
- 要件を満たしているか(仕様の見落とし)
これを Pull Request(→ 第2章)で他のメンバーに見てもらうのがコードレビューです。レビューは単なるミス探しでなく、チームの知見を共有し合う場でもあります(詳細は第13章「レビュー文化・設計」で扱います)。
🔑 レフトシフト —— 手前で見つけるほど安い
前出の「バグは早く見つけるほど安い」を、工程の観点で言い換えたのが left shift(レフトシフト/左へずらす)という思想です。
開発工程を左から右へ進むと見立てます:
設計 → コーディング → テスト → リリース → 本番運用
←早く見つけるほど安い→ ←遅いほど高い→
問題をこの流れの**左(手前)**で見つけるほど、直すコストが安い。だから:
- 型チェックはエディタで書いている最中に指摘(一番左)
- pre-commit(プレコミット): コミットする直前に自動検査を走らせる仕組みで、問題あるコードが履歴に入るのを防ぐ
- CI / PR(→ 第1章・第2章)で push のたび全検査を回す
すべて「問題を右に運ばない」ための仕組みです。
5. 🔑 段階的な検査 —— 手元から本番まで何層も重ねる
同じ検査を「複数のタイミング」で
重要なのは、検査を1回しかしないのでなく何層も重ねることです。例えばテスト・Lint・型チェックは:
- エディタ: 書いている最中(リアルタイムに波線等で指摘)
- コミット前(
pre-commit): 履歴に入る直前にブロック - CI / PR(→ 第1章): push のたび全体を自動検査
- 本番前ゲート(→ CD): 検査不通過なら本番に行かせない
なぜ何層も? —— 各層が別の目的を担うからです。エディタは速さ、CI は完全性、本番前ゲートは最終防衛。1層抜けても次で止まる多重防御が、品質を安定させます。
「検査を通す」でなく「検査に頼る」設計
落とし穴は「検査があるから大丈夫」と検査に丸投げする態度です。検査は書かれたことしか確かめません。テストが無い経路は検査されず、Lint も型チェックも「仕様が正しいか」は分かりません。だからこそ:
- 検査を書く = どうあるべきかを言語化する作業(仕様の明文化)
- 検査が多い = 自信の根拠が増える(「これだけ通ったから大丈夫」)
品質の作法は「検査をパスすること」でなく「検査に支えられた自信を持つこと」が目的です。
6. なぜ「品質の作法」が開発の作法なのか
作法として位置づけられる理由
- 本番事故の防止: 本番のバグは金・信用・時の損失。手前で見つける仕組みは保険であり責務
- チーム開発の前提: テストも Lint もないコードは、他の人が触る時に壊す恐怖と戦うことになる。検査があるからこそ安心して変更できる
- 変更への自信: 「テストが通っているから大胆に直せる」は、現場でコードを改善し続ける原動力です
面接・実務での意味
- 「テスト・Lint・型チェックの違いを説明してください」は面接の定番質問です。3つの役割分担(動作・書き方・型)を即答できるかは、実務経験の指標です
- 「なぜテストを書くのか」への正解は「バグを見つけるため」だけでなく「将来の変更を安全にするため(回帰防止)」まで言えると深い
- 「品質をどう担保していますか?」への回答も、これらの仕組みを層として語れるかが問われます
7. よくある落とし穴と対処
| 落とし穴 | 何が起きるか | 正しい対応 |
|---|---|---|
| テストを書かずに進める | 回帰に気づかない・本番事故 | 最初からテストを書く。後回しは利息が膨らむ(技術的負債) |
| テストだけで安心する | 仕様の誤り・型の問題を見逃す | Lint・型チェックも重ねる。3つの役割分担を意識 |
| Lint を無視/例外だらけ | バグの種が残る・規約が形骸化 | 例外は最小に・意味のある指摘は直す。機械任せを徹底 |
| 検査を「通すため」に書く | 通ったが中身が薄い・自信の根拠にならない | 検査は仕様の明文化。重要な経路を意識して書く |
| 人間の目に頼る | 見落とし・属人化(担当者不在で止まる) | 機械ができることは機械に。人はレビュー(設計・可読性)へ |
| 早い段階の検査をサボる | CI・本番まで運んで大コスト | レフトシフト: エディタ・pre-commit で手前に止める |
💡 カバレッジの罠: 「テストのカバレッジ(→ 用語集・何%のコードを実行したか)が高い = 品質が高い」は短絡です。カバレッジは「実行した割合」であって「正しさを確かめた割合」ではありません。「通っただけで正しい結果を見ていない」テストもカバレッジを稼ぎます。数値は参考値と割り切り、中身(重要な経路を確かめたか)で判断するのが作法です。
まとめ
- バグは後になるほど直すコストが跳ね上がる。だから「早く見つける」仕組みが問われる
- 品質を保つ3つの自動検査: テスト(動作・回帰防止)・Lint(書き方の問題)・型チェック(データの型の矛盾)。役割分担を重ねて隙間を埋める
- 共通思想は「人間の目と記憶に頼らず、機械に任せる」。CI(→ 第1章)はそれらを回す土俵
- コードレビューは人間にしか分からない問題(設計・可読性・要件)を扱う最後の砦(→ 第13章で詳しく)
- レフトシフト: 問題を工程の**左(手前)**で見つけるほど安い。エディタ・pre-commit・CI を層で重ねる
- 検査は「パスすること」でなく「自信の根拠を持つこと」が目的。カバレッジ等の数値は参考値
💡 次のステップ: バグを防ぐ個別の検査と「早く見つける」思想が見えました。最後の第13章「レビュー文化・設計」では、人間の目であるコードレビューの作法と、そもそも変更しやすいコードの設計(アーキテクチャ)の基本を扱って、本書を締めくくります。