はじめに
既存のRailsプロジェクトを引き継ぐにあたり、コーディングエージェントで全体の設計書を作成しました。
目次
背景
Kiroに設計を依頼したとき、下記のような困難を感じました。
- あまりにも実装に寄りすぎている。そのため、要件とのギャップが大きくてレビューが難しい。全体的におかしな内容であっても、それに気づくまでに時間がかかる
- そのプロジェクトの設計についての知見を蓄積しにくい
- 人間向けとしては、用途が限られる
これらを個別に掘り下げる前に、全体の設計書を作成することで状況がどのように変わるか、確かめたいと思いました。
設計書の要件(希望)
- 機能単位でなく、アプリケーション全体の設計書である
- コーディングエージェントにとって有用(例えば、Kiroが生成するdesignの代わりに使える)で、かつ人間が効率的にレビューできる
- コードベースと同じリポジトリにコミットする
- 例えば、QAチームが結合テストを設計する際のインプットとしても有効である
- ステークホルダーへの共有・説明にも利用可能である
作成した設計書
対象プロジェクトの規模
Ruby on Railsで構築されたプロジェクト。
- モデル数:36
- Concern:13
- API コントローラ数: 15
- Concern:6
- Web コントローラ:49
- Concern:23
- サービスクラス:20個 (外部連携など)
- 外部連携
- PDF生成
- CSV取込
(コントローラのConcernが多いですが、これはビジネスロジックがコントローラ層に漏洩している様子でした)
ディレクトリ構成
docs/design配下に、app/と同じ構成およびファイル名で作成する運用としました。
⏺ docs/
├── design/
│ ├── controllers/
│ │ └── concerns/
│ ├── models/
│ │ └── concerns/
│ └── views/
└── workflows/workflowsには、これもまたコーディングエージェントに作成を依頼した、Mermaid記法の業務フロー図を配置しています。design というよりは spec 寄りの情報ということもあって、さしあたり、別のディレクトリにしています。
ドメインモデル設計書の要件
- 他の設計書から以下の形式で参照する想定。そのときに、自然に意味が通るようにしておく
その{モデル名}.{メソッド名}によって... (インスタンスメソッド)
{モデル名}.{メソッド名}によって... (クラスメソッド)- 独自に和訳せず翻訳ファイルの定義を参照する
- 基本的に日本語の翻訳で記述するが、コード上の識別子も原文のまま併記する
プロンプト
# モデル設計書作成ガイド
## 翻訳
- 独自に訳さず、翻訳ファイル(config/locales)の定義を使う
- 属性名は翻訳ファイルに従って日本語に翻訳する
- 翻訳がない属性は英語のまま
- メソッド名は英語のまま
- メソッドセクションでは属性名に英語識別子を付記する
## コード値の表記
- `true`, `'some_string'` などリテラル値はバッククォートで囲む
## 特性
- 各項目に()でConcern名を付記
- 自動実行 →「〜する」、メソッド提供 →「〜できる」
- 独自Concernのみ(gemは含めない)
## アソシエーション
- `belongs_to` →「属する」で統一(optionalも含む)
- `has_many` →「複数持つ」
- `has_one` →「1つ持つ」
## 列挙型
- enumはまとめて「列挙型」セクションに
- テーブル形式:`| キー | 値 | 日本語 |`
- キー:enumのシンボル名(例:`active`)
- 値:DBに保存される数値(例:`0`)
- 日本語:翻訳ファイルの日本語訳(翻訳がない場合は空欄)
## 状態遷移図
- コードで明示的に定義されている遷移のみ図示
- 画面から任意に変更可能な場合は注釈を追加
## メソッド
- 「クラスメソッド」「インスタンスメソッド」セクションに分ける
- Railsが自動生成するgetter/setterは書かない(明示的に定義されたメソッドのみ)
- 各メソッドは `### メソッド名` で見出しを付ける
- コードの各行を段落形式で自然言語で説明する(番号付きリストではなく段落)画面設計書の要件
- 画面項目を記載する
- 画面上で実行されるJavaScriptの処理内容を記載する
- Stimulusコントローラの処理内容を記載する
- Railsコントローラの処理は基本的に記載しないが、この設計書単体で意味が理解できるように配慮する
- リダイレクト先は、画面設計書側にも記載する
プロンプト
```markdown
# 画面設計書作成ガイド
## ファイル構成
app/viewsのファイル構成に合わせる。
```
docs/design/views/
├── {controller_name}/
│ ├── {action_name}.md
│ ├── _{partial_name}.md # パーシャルは別ファイル
│ └── ...
└── ...
```
コントローラの処理は `docs/design/controllers/` に分離する(.claude/commands/design_controller.md参照)。
### パーシャルの参照
メインの設計書からパーシャルを参照する場合、本文に「`パス`を参照。」と記載する。
## 画面項目
テーブル形式で記載する。
```
番号 | 名前 | 種類 | 遷移先 | 選択肢 | 必須 | 備考
-- | --- | --- | --- | --- | --- | ----
1 | 項目名 | 種類 | | | |
```
### 種類の例
- 表示
- 表示(リンク)
- テキスト入力
- テキストエリア
- セレクトボックス
- チェックボックス
- 画像アップロード
- ボタン
- リンク
## 処理セクション
ビュー設計書にはJavaScript処理と画面更新のみを記載する。コントローラ処理は `docs/design/controllers/` に分離する。
Stimulusコントローラの処理はViewの一部として記述する(「...controllerにより」などの記載は不要)。
### リクエストの記載
- 同期リクエスト: `メソッド パス`へリクエストを送信する
- 非同期リクエスト: `メソッド パス`へ**非同期**リクエストを送信する
- リクエストの目的を括弧で追記する(例: `(顧客一覧の取得)`)
- 成功時の処理を記載する:
- 非同期リクエスト: 「成功したとき:」の後にサブ項目で画面更新を記述
- 同期リクエスト: 「成功したとき、○○画面へ遷移する」と記述
- 同期リクエストで同じ画面に遷移する場合: 「成功したとき、この画面をリロードする」と記述
- 画面更新は「画面のどの要素を更新するか」を書く
### 文脈オブジェクトの明示
複数のオブジェクトに対して処理する場合、「それぞれについて」で文脈を明示する。
```markdown
- それぞれについて、以下を実行する
- キャンセルする
```
これにより、以降のサブ項目の主格が「リレーション全体」ではなく「1つのインスタンス」であることが明確になる。
## 表記ルール
### パラメータの出所
ビューから送信されるパラメータは、どの画面項目から来るのかを明確にする。
### enum値・ステータス
翻訳がある場合は日本語訳を先に、英語キーを括弧内にバッククォートで囲んで記載する。
```コントローラ設計書の要件
- メソッドの見出しは「日本語名(英語メソッド名)」の形式で記載する
- 日本語名は、画面設計書に記載したときに意味が通るようにする
プロンプト
```markdown
# コントローラ設計書作成ガイド
## ファイル構成
app/controllersのファイル構成に合わせる。
```
docs/design/controllers/
├── {controller_name}_controller.md
├── {namespace}/
│ └── {controller_name}_controller.md
└── concerns/
└── {concern_name}.md
```
## アクションごとの記載
見出しにアクション名を記載し、処理内容を箇条書きで記載する。
## Concernへの分離
コントローラのconcernは `docs/design/controllers/concerns/` 以下に切り出す。コントローラ設計書からは「〜する(ConcernName)」と参照する。
コントローラからの参照は、Concern設計書のメソッド見出し(日本語名)と一致させる。
### Concern設計書の構造
メソッド見出しは「日本語名(英語メソッド名)」の形式で記載する。
## 表記ルール
### モデル参照
初出時は日本語名の後に括弧でクラス名を付記する。
### enum値・ステータス
翻訳がある場合は日本語訳を先に、英語キーを括弧内にバッククォートで囲んで記載する。
### 箇条書きのルール
#### コロンの使い分け
サブ項目が親項目の**実装詳細**である場合、親項目の末尾にコロンを付ける。
サブ項目が親項目とは**別のアクション**である場合、コロンは付けない。
#### 文脈オブジェクトの明示
複数のオブジェクトに対して処理する場合、「それぞれについて」で文脈を明示する。
### 自動生成メソッド
`.valid?`、`.save`、`.submitted!` など、Railsやenumが自動生成するメソッドについては「メソッド呼び出し」自体の明示不要。
```これらの設計書を開発フローに適用
課題ごとの設計書を作成する代わりに、全体設計書の差分をコミットします。
- 要件を .specs/{課題番号}/requirements.md に配置する
- この課題による設計書の差分をコミットする。
- 上記差分をこの課題の設計とみなして、通常の進行をする
コーディングエージェントはgit diffの扱いが苦手のようなので、以下のような形で差分を明示すると良かったです。
Git: developとHEADの共通祖先からHEADまでの変更。 **git diff ではドットを3つ書く必要があります** 例: develop...HEADできたこと
- 設計書のレビューが楽になったし、早めに齟齬に気づけるようになった
未検証事項
- この全体設計書をもとに、継続的にスムーズに実装できるか?
- 全体設計書がコンテキストを圧迫しないか?
- 例えばView Specと画面設計書(View Design)はどちらが(あるいは両方存在することが)役に立つか?
- コードコメントとどちらが(あるいは両方存在することが)役に立つか?
