AI時代の「Embedded Documentation」のススメ

こんにちは! ニーリーアドベントカレンダー2025 始まりました!

トップバッターを務めます、PDBiz開発Gの古庄(@k_furusho_)です。

入社して1ヶ月が経過しました。(入社エントリもきっと書く..!!)

架電業務や駐車場探しの実業務にも参加し、ニーリーの「染み出すカルチャー」を肌で感じる中で、オペレーションやシステムの解像度を一気に上げている最中です。

さて、システムの解像度を高める過程で、開発現場における永遠の課題である「ドキュメント管理」について、改めて思考を巡らせる機会がありました。

「Code is the executable design document(コードこそが動く設計書である)」

私は長らくこの原則を前提に開発プロセスを設計すべきだと思っています。コードが「How(どう動くか)」を最も正確に語っている以上、それと重複する内容を自然言語で書き下すことは、メンテナンスコストを増大させるだけでなく、情報の不整合を生む温床となるからです。

とはいえ、コードだけではカバーしきれない「合意形成」や「全体の見取り図」が必要なのも事実です。

今回は、重複を排除しつつ、AIとツールを用いて必要なコンテキストを補完する「Embedded Documentation」というアプローチをご紹介します。

また、合わせてこのアプローチを実現するために自作したVS Code拡張機能も共有します。

WhyとHowの分離:情報はどこにあるべきか

「コードは動く設計書」である以上、情報の質によって管理場所を明確に分離すべきだと考えています。

Why & What:PRD (Product Requirements Document)

「なぜ作るのか」「ビジネスルールは何か」。 これらはPMやデザイナーといったステークホルダーとの「合意形成」の領域です。認識齟齬を防ぎ、チーム全員が共通認識を持つための「共通言語」として、これらはNotion/Confluenceなどのコラボレーションツールで管理され続けるべきです。

How:Code (Embedded)

「クラス構造」「具体的な処理フロー」。 これらはコードそのものが正解を持っています。したがって、別途ExcelやMarkdownで「処理フロー図」を作成するのは避けるべきだと私は考えます。それはコードとの重複であり、将来的な負債になりがちだからです。

代わりに、コードの中にMermaid記法を用いて「地図」を埋め込む。 ソースコードという SSOT(Single Source of Truth) の中に情報を集約することが、最も健全な状態と言えます。

では、具体的にどう書くのか。私は以下のようなスタイルを使い始めました。

from typing import Optional
from dataclasses import dataclass

@dataclass
class PaymentResult:
    status: str
    message: Optional[str] = None

def process_payment(req: dict) -> PaymentResult:
    """
    決済処理のメインフローを実行する。
    
    バリデーション済みリクエストを受け取り、
    外部決済プロバイダー経由で課金を実行する。

    Mermaid:
    graph TD
    Start[開始] --> Validate{有効性確認}
    Validate -- OK --> Charge[課金実行]
    Validate -- NG --> Error[エラー返却]
    Charge --> |成功| Save[DB保存]
    Charge --> |失敗| Retry{リトライ判定}
    Retry -- Yes --> Charge
    Retry -- No --> Error
    """
    if not _is_valid(req):
        return PaymentResult(status='error', message='Invalid request')
    
    # ... 実装の詳細 ...
    return PaymentResult(status='success')

このように、関数の直上にMermaidを書くことで、コード(詳細)と図(全体像)が物理的に最も近い場所に同居します。 かつて、ドナルド・クヌースが提唱した「文芸的プログラミング(Literate Programming)」は、ツールチェーンの制約などから広く普及するには至りませんでした。しかし、AI時代において、この手法は最も合理的で生産的なスタイルとして再評価できるのではないかと考えています。

"隣"でもまだ遠い。Colocationの課題と解決策

「関連するリソースを近くに置く」という Colocation の原則に従い、src/features/Payment/README.md のようにMarkdownファイルを配置する構成も一般的です。

しかし、以下の理由から「隣のファイルであっても、まだ『遠い』」と感じています。

  • Markdownファイルを別タブで開き、プレビューを開く動作によるコンテキストスイッチ

  • 機能の追加・修正をした際に、Markdownの変更が漏れやすい

そのため、ファイルすら分けず、「実装ファイルやバレルファイルの中に全て記述する」方法を使い始めました。

自作VS Code拡張機能「mermaid-comment-viewer」のアプローチ

しかし、このスタイルを実践する上で一つの技術的課題がありました。 「VS Code上で、コード内のMermaidを快適に閲覧する手段が少ない」という点です。

インライン展開する拡張機能もありますが、コードの可読性を損なうことが多く、既存のプレビュー機能は操作性やオフライン対応に難がありました。

「必要なツールがなければ作る」。 そう考え開発したのが mermaid-comment-viewer です。

Webview Panelと正規表現による解析

1. 分離されたWebview Panel

コードエディタを汚さないよう、VS Codeの vscode.window.createWebviewPanelを使用し、サイドパネルとして独立させました。 「左でコードを読み進め、右で全体像を確認する」。この体験を実現するために、エディタの onDidChangeTextDocument イベントを監視し、カーソル位置やアクティブなファイルに基づいて、該当するMermaidブロックをリアルタイムに抽出しています。

2. オフライン対応

飛行機や新幹線の中での開発を想定し、CDNには依存していません。 拡張機能内に mermaid.min.js をバンドルし、Webviewの localResourceRoots 設定を通じてローカルリソースとして読み込ませています。これにより、ネット環境がない年末年始の帰省中でも開発を進めることが可能です。

3. 柔軟なパースロジック

TypeScriptの /** ... */ だけでなく、Pythonの """ ... """ や一般的な行コメントなど、言語ごとのコメント構文の違いを吸収し、Mermaid記法を特定するパースロジックを実装しています。

AIとMCPによる自律的なメンテナンスサイクル

最後に、このアプローチの未来について少し触れます。

重要になるのが、AIとMCP (Model Context Protocol) の活用と考えています。 「ConfluenceにあるWhy」と「コードにあるHow」を論理的に接続するのは、AIの役割になります。

私が想定しているワークフローは以下の通りです。

Nano Banana Proで作成したフロー図

  1. Context
    AIがMCP経由でConfluenceのPRDを読み込み、「改修の背景(Why)」を理解する。
  2. Generate
    その背景を踏まえてAIがコードを修正し、同時にDocstring内のMermaid図(How)も更新する。
  3. Review
    人間は、AIが生成したコードと図を見て、整合性を検証することに集中する。

Howを可視化するための作業そのものはAIに委譲し、エンジニアは「設計の正しさを検証する」ことに注力する。これがこれからのエンジニアリングのあるべき姿ではないでしょうか。

まとめ

  • Why はコラボレーションツール(Notion, Confluence etc...)へ
    • AIのコンテキスト/チーム全員が共通認識を持つための「共通言語」として
  • How はコード内へ
    • AIにメンテナンスさせる
  • HowのVisualization は mermaid-comment-viewer で快適に
    • 自分で作りましたが、正直便利です

この年末年始、ドキュメント管理に思いを馳せる際に、ぜひこの「Embedded Documentation」を試してみてください。

明日のニーリーアドベントカレンダーもお楽しみに!