チームで本格的に Docs as Code を運用しているので紹介します - エムスリーテックブログ

エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

チームで本格的に Docs as Code を運用しているので紹介します

エムスリーのソフトウェアエンジニアの伊藤です。デジスマチームのブログリレー2日目の記事です。 チームではチームリーディングとプロダクトマネジメントを主に担当しています。

はじめに

最近のプロダクト開発では、AI Agent を活用する機会がどんどん増えてきましたよね。 ただ、いざ導入してみると、従来の開発プロセスやコードベースのままだと AI Agent に思うようにコードを書いてもらえなかったり、コードレビューが滞ったり……。 世の中で言われているほど開発生産性が上がらないなと感じることもあるのではないでしょうか。 自分たちのチームでも、AI Agent をどうチーム開発に取り入れるか、まだまだ試行錯誤しているところです。

今回は、そんな中でチームが取り組んでいる Docs as Code(ドキュメントをコードと同じリポジトリで管理する手法)運用についてまとめたので紹介します。

コンテキスト・エンジニアリング

AI にいい感じに動いてもらうには、プロンプトを工夫するだけでは足りないことが多いです。 AI が精度高く推論するためには、必要なデータやツール、背景情報にアクセスできて、文脈を深く理解したうえで作業できる仕組みが必要になります。 いわゆるコンテキスト・エンジニアリングと呼ばれるアプローチですね。

チームで Docs as Code を採用しているのも、もちろん他の理由もありますが、このコンテキスト・エンジニアリングの観点が大きいです。

AI Ready なコードベースにするためのドキュメント管理

AI Agent が効果的にコードを生成できるよう、次のような情報をコードベース内に整備しています。

  • What(何を作るか): プロダクトの仕様やビジネス要件
  • Why(なぜそうするか): 過去の意思決定や設計判断の背景
  • How(どう作るか): 技術的な詳細な設計、テーブル定義やプロジェクトの規約等
  • Contract(インタフェース定義): API 設計、仕様とコードベースを繋ぐドキュメント

具体的には次のドキュメントを実際に GitHub のリポジトリに入れて管理しています。

  1. プロダクト画面仕様書 — What
  2. ADR(Architectural Decision Record) — Why or How
  3. Design Doc — How
  4. API 定義(Protocol Buffers) — Contract

これらをコードと同じリポジトリで管理することで、AI がリポジトリ内のファイルとしてドキュメントに直接アクセスでき、コンテキストとして活用できるようになります。 こうしておくと、開発メンバーそれぞれが使う AI のアウトプットの差もなるべく小さくできます。

実際の開発フローとしては、何かを作るときに

  1. PdM とエンジニアリーダーが画面仕様書を作成する
  2. デザイナー、PdM、エンジニアで画面仕様書をレビューする
  3. 技術的な意思決定が必要な場合は ADR を書く
  4. 具体的に設計をする(Design Doc, Protocol Buffers を書く)
  5. エンジニア内で設計レビュー
  6. 必要に応じて、コードだけでなく、画面仕様書や ADR, Design Doc を追加・修正する

というサイクルで回しています。 ポイントは6の段階で、どうやって追加の意思決定や設計をコードベースに反映して、次のサイクルや他メンバーの開発で活用できるようにするか、というところを意識しています。 実際に、チームの議論で「この決定を ADR に残しておこう」という発言が出るようになりました。

プロダクト画面仕様書

画面単位やコンポーネント単位で、仕様書を Markdown で管理しています。

当初はデザイン要素も仕様書に書いていたのですが、プロジェクトの性質上デザイン変更が頻繁に発生し、仕様書の更新が追いつかなくなりました。 そこで、デザイン要素は Figma に集約して、仕様書にはデザイン URL だけを載せる運用に変更しました。 ちょっとした工夫として、デザイン URL には Figma の Dev モードの URL を使っています。こうすることで、AI Agent が Figma MCP サーバーを通じてデザイン情報を取得できるようになります。

以下は、実際の画面仕様書の例です。URL や内容は架空のものですが、フォーマットとしてはこんな感じで管理しています。

# 仕様: ユーザー新規登録画面

## URL Path

/register

## Figma / デザイン

- https://www.figma.com/design/xxxxx (Dev モード URL)

## 表示情報 (データ取得)

### 登録フォーム

| 項目       | 型   | 説明                    | 例                |
|----------|-----|-----------------------|------------------|
| ユーザー名    | 文字列 | ユーザーの表示名              | サンプル タロウ            |
| メールアドレス  | 文字列 | ログインおよび認証リンクの送信先      | taro@example.com |
| パスワード    | 文字列 | ログイン用パスワード(マスク表示)     | ********         |
| パスワード確認  | 文字列 | パスワードの再入力(マスク表示)      | ********         |

## アクション・インタラクション

### バリデーション

| 項目       | 入力種別 | 必須 | バリデーション                | エラーメッセージ                       |
|----------|------|----|------------------------|----------------------------------|
| ユーザー名    | Text | ○  | 50文字以内                 | 50文字以内で入力してください。               |
| メールアドレス  | Text | ○  | メールアドレス形式              | 有効なメールアドレスを入力してください。           |
| パスワード    | Text | ○  | 8文字以上                  | 8文字以上で入力してください。               |
| パスワード確認  | Text | ○  | パスワードと一致すること           | パスワードが一致しません。                 |

### 登録

[登録] ボタンをクリックした時に、次の処理を行う。

* バリデーションを実施する。
* バリデーションエラーがない場合、サーバーへデータを送信する。
* サーバーから正常応答があった場合、認証メール送信完了画面に遷移する。

### アクション時のエラー

| エラー名          | ステータスコード | 事象                   | 振舞                                            |
|---------------|----------|----------------------|-----------------------------------------------|
| メールアドレス重複     | 409      | メールアドレスが既に登録済み       | 「このメールアドレスは既に使用されています」をフォーム上部に表示する |

## 計測・その他

### Google Analytics

* 閲覧ログ
  * event_name: page_view
  * page_title: ユーザー新規登録
  * page_location: /register
* 登録ボタン押下
  * event_name: click_register

ADR

ADR(Architectural Decision Record)は、プロジェクトの重要な設計決定を記録するドキュメントです。 本来はアーキテクチャに関する決定を記録するものですが、チームに影響を与える重要な決定であれば、アーキテクチャに限らず ADR として残すようにしています。 たとえば、

  • モノレポ構成を採用する
  • IDL に Protocol Buffers を採用する
  • 宣言的マイグレーションを使う
  • フロントエンドのパッケージマネージャーに pnpm を採用する

といったものが ADR として残っています。 ADR があると、なぜその決定をしたのか、どんな選択肢を検討したのかが追えるので、将来見直すべきかどうかの判断もしやすくなります。

実際に使っているフォーマットはこんな感じで、場面に応じてセクションを追加・削除しています。

# ユーザー認証方式の選定

Date: 2025-01-15

## 状況 - Status

承認済み - Accepted

## 背景 - Context

ユーザー新規登録機能の実装にあたり、認証方式を決定する必要がある。
セキュリティ要件として、メールアドレスの所有確認が必須。

## 検討した選択肢 - Considered Options

1. メール認証リンク方式: 登録後に認証リンクを送信し、クリックで有効化
2. 認証コード方式: 6桁のコードをメール送信し、画面上で入力
3. OAuth のみ: Google / Apple などの外部プロバイダに委譲

## 決定 - Decision

メール認証リンク方式を採用する。
認証リンクの有効期限は24時間とする。

## 影響 - Consequences

- メール送信基盤の構築が必要
- 認証リンクの有効期限管理のためのトークンテーブルが必要
- 未認証ユーザーの扱い(一定期間後に削除)を別途検討する

## 参考 - References

- OWASP Authentication Cheat Sheet

Design Doc

Design Doc は、API 設計やデータベース設計、ロジックの設計など、技術的な詳細を書くドキュメントです。 ありふれたものではありますが、実際に使っているフォーマットを載せておきます。

# Design Doc: ユーザー新規登録

## 1. Context (背景と目的)

- 関連する ADR: ユーザー認証方式の選定(メール認証リンク方式を採用)
- 関連する仕様書: ユーザー新規登録画面
- ユーザー新規登録の API 設計とデータベース設計を行う

## 2. Goals / Non-Goals (やること・やらないこと)

- Goals:
  - ユーザーの新規登録 API を設計する
  - 認証メール送信のフローを設計する
- Non-Goals:
  - ログイン・ログアウト機能(別 Design Doc で扱う)
  - OAuth 連携(現時点ではスコープ外)

## 3. Proposed Solution (提案する解決策)

### API 設計

- [CreateUser](proto/app/user/v1/service.proto#L10)

### テーブル設計

- [users テーブル](db/schema.sql#L20)

## 4. Alternatives Considered (検討した他の選択肢)

- 認証メールを同期的に送信する案 → レスポンス遅延を避けるため非同期を採用

## 5. Cross-Cutting Concerns (懸念点・影響範囲)

- メール送信の失敗時のリトライ戦略を別途検討する必要がある
- 未認証ユーザーの定期削除バッチが必要

ただ、Design Doc の運用には悩ましさもあります。 技術的な詳細を書いておくと AI Agent でコードを書くときにはとても役立つのですが、ストック情報としてはちょっと細かすぎることが多いんですよね。 実際、Design Doc とコードが乖離したり、ドキュメントが陳腐化したり、コンテキストが膨れすぎたりしがちです。 ドキュメントも DRY にしたいので、Design Doc 上のスニペットコードなど本コードと重複する情報は、コミット前に該当コードへのリンクに置き換えるといった工夫が必要だなと感じています。

もしかすると、ADR のような軽量なドキュメントだけの運用にシフトしていく可能性もあるかもしれません。ドキュメントの数がまだそこまで多くない今の段階でも、そう感じることがあります。

API 定義 (Protocol Buffers)

Protocol Buffers による API 定義も、重要なドキュメントの1つです。 フロントエンドとバックエンドのインタフェースを明確に定義しておくことで、両者を独立して開発できるようにしています。 AI 活用の観点では、仕様書と実装をつなぐドキュメントとしての役割が大きいです。そのため、API 定義にはなるべくコメントを書くようにしています。 初期実装では、AI が仕様書を読んでコードを書いてくれますが、仕様とコードを恒久的にマッピングするドキュメントがあると、AI Agent がコードを変更するときのコンテキストとして活用しやすくなります。

// ユーザーの登録・管理を行うサービス
service UserService {
  // ユーザーを新規登録し、認証メールを送信する
  // 認証メールは非同期で送信される
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
}

message CreateUserRequest {
  // ユーザー名(必須、50文字以内)
  string name = 1;
  // メールアドレス(必須、認証リンクの送信先)
  string email = 2;
  // パスワード(必須、8文字以上)
  string password = 3;
}

// 登録されたユーザーの ID を返す
message CreateUserResponse {
  int64 id = 1;
}

まとめ

今回は、チームで取り組んでいる Docs as Code の運用について紹介しました。 ドキュメントの管理方法はプロジェクトやチームによって最適解が変わるので、唯一の正解があるわけではありません。 ただ、AI Agent を使った開発が当たり前になりつつある今、コードベース内にドキュメントを整備しておくことは、開発生産性を上げるための大事な投資だと感じています。

この記事がドキュメント管理に悩んでいる方のヒントになれば嬉しいです。

We are Hiring!

エムスリーでは、積極的に AI を活用しています。 AI を活用したプロダクト開発は勿論、新しい技術やビジネスに興味のあるエンジニアを募集しています。 興味を持ってもらえたらとても嬉しいです。

エンジニア採用ページはこちら

jobs.m3.com

エンジニア新卒採用サイト! !

fresh.m3recruit.com

カジュアル面談! !

jobs.m3.com