コーディングエージェントでRailsプロジェクトの設計書を生成する

はじめに

既存の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が自動生成するメソッドについては「メソッド呼び出し」自体の明示不要。

```

これらの設計書を開発フローに適用

課題ごとの設計書を作成する代わりに、全体設計書の差分をコミットします。

  1. 要件を .specs/{課題番号}/requirements.md に配置する
  2. この課題による設計書の差分をコミットする。
  3. 上記差分をこの課題の設計とみなして、通常の進行をする

コーディングエージェントはgit diffの扱いが苦手のようなので、以下のような形で差分を明示すると良かったです。

Git: developとHEADの共通祖先からHEADまでの変更。 **git diff ではドットを3つ書く必要があります** 例: develop...HEAD

できたこと

  • 設計書のレビューが楽になったし、早めに齟齬に気づけるようになった

未検証事項

  • この全体設計書をもとに、継続的にスムーズに実装できるか?
  • 全体設計書がコンテキストを圧迫しないか?
  • 例えばView Specと画面設計書(View Design)はどちらが(あるいは両方存在することが)役に立つか?
  • コードコメントとどちらが(あるいは両方存在することが)役に立つか?
役に立ったらシェアしていただけると嬉しいです
  • URLをコピーしました!
  • URLをコピーしました!
目次