はじめに
「ドキュメントを書いても、実装が進むにつれて実態と乖離し、誰も読まなくなる」
これはソフトウェア開発における不治の病のようなものです。
しかし、だからといって「ドキュメント不要論(コードが全てだ)」に振り切ると、今度は 「なぜその設計にしたのか(意図)」 がコードからは読み取れず、数年後に誰も触れないレガシーコードが誕生します。
私たちはこのジレンマを解消するために、2つの異なるアプローチを組み合わせた運用に辿り着きました。
- Forward (人間): 実装前に「意図と決定」を書く (ドキュメント駆動)
- Backward (機械): 実装後に「構造と実態」を生成する (リバースエンジニアリング)
本記事では、この2つをCIパイプライン上で衝突させ、**「常に生きているドキュメント」**を維持するハイブリッドな管理術を紹介します。
TL;DR(3行まとめ)
- 人間がメンテするのは「Why(意図)」だけ。 構造(What)は手書きするな
- ER図やAPI仕様書は、コードからCIで「リバースエンジニアリング(自動生成)」し続ける。
- 「最初に書いた設計(理想)」と「生成された図(現実)」を見比べることこそが、正しいレビューである。
1. なぜドキュメントは「嘘つき」になるのか
ドキュメントが腐る最大の原因は、「コードから読み取れる情報(クラス図、テーブル定義、API定義)」を人間が手動で二重管理しているからです。
コードを変更した瞬間にドキュメントは「嘘」になります。人間の意志力で同期し続けるのは不可能です。
そこで、情報を明確に分離します。
| 分類 | 書く内容 | 担当 | ツール例 |
|---|---|---|---|
| Why (意図) | 背景、採用理由、却下した案 | 人間 (先書き) | Markdown, ADR |
| What (実態) | テーブル構造、依存関係、I/F | 機械 (後書き) | tbls, Swagger, Mermaid |
2. Forward: 人間は「Design Doc」を先に書く
実装を始める前に、人間は「コードからは逆算できない情報」だけをドキュメント駆動で書きます。
Google等で採用されている Design Doc や ADR (Architecture Decision Records) がこれに当たります。
書くべきこと(=意図)
- Context: なぜこの機能を作るのか?
- Decision: なぜMySQLではなくDynamoDBを選んだのか?
- Alternatives: 「検討したが却下した案」は何か?(※これが最も重要)
テンプレート例
# [Design Doc] 注文履歴のアーカイブ機能
## 採用したアーキテクチャ
- 1年以上前のデータをS3へCold Storageとして移動する。
## 却下した代替案 (Alternatives Considered)
### 案A: 同一DB内の別テーブルへ移動
- 理由: DB容量の削減につながらないため却下。
- コスト: 実装は楽だが、インフラコスト増が見込まれる。
これらは、どれだけリバースエンジニアリングしてもコードからは出てきません。だからこそ、人間が最初に書く価値があります。
3. Backward: 機械に「実態」を描かせる
コーディング中、あるいはCI(GitHub Actions)が回るたびに、コードから「現在の姿」を強制的にドキュメント化します。 「詳細設計書」を手動更新する時代は終わりです。
データベース定義書 → tbls
Go製のツール tbls が非常に優秀です。 DBスキーマに接続し、テーブル定義やER図(SVG)を含むMarkdownを自動生成してくれます。
# GitHub Actionsでの実行イメージ
- name: Generate DB Docs
run: tbls doc postgres://user:pass@db:5432/myapp
クラス依存関係・構造 → Mermaid + 各種ツール
TypeScriptなら dependency-cruiser、JavaやPHPなら各種ツールを使って、モジュール間の依存関係図を生成します。
API仕様書 → OpenAPI (Code-first)
Spring BootやNestJSなら、コードのアノテーションからSwagger UI (OpenAPI YAML) を生成します。
4. 「答え合わせ」のサイクルを回す
ここからが本題です。 「Design Doc(理想)」と「自動生成ドキュメント(現実)」が揃いました。開発プロセスの中で、この2つを突き合わせます。
レビュー時のチェックポイント
プルリクエストのレビューでは、コードだけでなく「Design Doc」と「生成された図」の差分を見ます。
-
意図せぬ依存:
Design Docでは「A→Bの一方通行」としたのに、生成された図で「相互依存」になっていないか? -
複雑度の増大:
自動生成されたER図が、スパゲッティになっていないか? -
同期:
実装を進める中で「やっぱこうしました」という変更があった場合、Design Doc(意図)側も更新されているか?
この「答え合わせ」を行うことで、ドキュメントは常に「現在のコードを説明するもの」であり続け、かつ「過去の意思決定」も保存されます。
5. まとめ
・「ドキュメント駆動」だけでは、現実に追いつけず陳腐化します。
・「リバースエンジニアリング」だけでは、文脈(Why)が失われます。
この2つを組み合わせることで、初めて「メンテナンス可能なドキュメント運用」が可能になります。
まずは、プロジェクトに tbls などの自動生成ツールを1つ入れ、CIでコミット毎にER図を上書き保存することから始めてみませんか? それだけで、「ドキュメントが古い!」というストレスから解放される第一歩になります。