株式会社ブレインパッドプロダクト開発部でRtoaster GenAIの開発をしている依田です。
Claude CodeにDesign docやPRを書かせていて、「情報量は多いのに、何を決めたのかがなかなか頭に入ってこない」と感じたことはないでしょうか。私は何度もあります。読んでいるあいだずっと気を張っていないと、一番知りたい結論を読み落としてしまう。あの独特の疲労感の正体を、実際のGitHub PRを使って確かめてみました。
対象読者
- Claude CodeなどのAIエージェントに設計書やPRを書かせている方
- Skillやプロンプトの設計を見直したい方
- 生成AIが書いたドキュメントのレビューに疲れた経験がある方
なぜAIの文章を読むと疲れるのか
内容が間違っているわけではありません。むしろ大抵は正しいことが書いてあります。それでも疲れる理由は、次の4つに集約されると考えています。
網羅と重要度を区別しない。人間がDesign docを書くときは、頭の中で「これは書くべき」「これは省いていい」という取捨選択を無意識に行っています。生成AIにはこの選別が働きにくく、思いつく観点をすべて同じ重みで並べてしまいます。結果として決定的な判断と自明な前提が同じ文量で説明され、読み手が重要度を仕分けする作業を肩代わりさせられます。
結論が最後に来る。人間の書き手であれば「結論から言うと〜」と先に言い切ってしまうことが多いですが、生成AIは検討の過程を順番に再生してから、最後にまとめとして結論を書く構成を取りがちです。読み手は結論にたどり着くまで、すべての情報を頭の中に保持し続けなければなりません。
テンプレートの見出しを律儀に埋める。「背景」「目的」「用語定義」「今後の拡張性」といった定型的な見出しを一度使うと、中身が薄くても律儀に埋めようとします。見出しの数だけ「読まなければならない」という圧力が生まれます。
自明な項目にも両論併記する。「メリット・デメリット」という型を一度採用すると、採用しなかった案にも同じ型を機械的に当てはめます。要件を読めば最初から成立しないとわかる案にすら、丁寧な説明が付きます。
言葉で説明しても実感が湧きにくいので、実際に手を動かして確かめてみます。
ECサイトのカート割引クーポンで確かめてみる
題材は、ECサイトのショッピングカートに対する割引クーポン適用ロジックです。要件は次の通りです。
- カートには複数の商品(カテゴリ・単価・数量)が入っている
- クーポンは金額固定割引・割合割引・送料無料の3種類
- 各クーポンには最低購入金額・有効期限・対象カテゴリという適用条件がある
- 併用不可のクーポンが1つでも含まれる場合は、最も割引額が大きいクーポン1枚だけを採用する
- 期限切れなど不正なクーポンは無視し、残りのクーポンで計算を続行する
DDD(ドメイン駆動設計)/OOP(オブジェクト指向)的な設計で実装することだけを指定し、Design docの書き方は指定していません。
同じ要件を、何も工夫していないSkillと、Design docの書き方に手を入れたSkillの両方で実装させ、実物のPRを見比べます。
工夫なしのSkillで作らせたBefore
Skillの中身は、「Issueを読み、Design docを書いて実装し、PRを作る」という手順を並べただけのものです。
Design docには、検討した設計方針やその背景、メリット・デメリットなどを詳しく記載してください。
実装者以外が読んでも設計の意図がわかるように、丁寧に説明を書いてください。
このSkillで生成したDesign doc・実装・PRがこちらです。
適用条件をSpecificationパターン(条件をオブジェクトとして表現する設計パターン)で表現するという判断1つにも、この調子でメリット・デメリットが並びます。
### Specificationパターンによる適用条件の表現
クーポンの適用条件(最低購入金額・有効期限・対象カテゴリ)を、それぞれ独立したSpecification
クラスとして実装し、`AndSpecification`で組み合わせます。
**メリット**:
- 各条件が独立したクラスになるため、単一責任の原則に従うことができます
- 新しい適用条件を追加する際に、既存の条件クラスを変更する必要がないため、
開放閉鎖の原則に従うことができます
- 条件の組み合わせ(AND/OR)を柔軟に表現することができます
**デメリット**:
- 条件の数だけクラスが増えるため、ファイル数・コード量が増加します
- シンプルなif文の羅列と比較して、間接参照が増え、コードを追うコストが上がる可能性があります
採用しなかった代替案も律儀に4つ挙げられ、そのうちの1つはこうです。
### 代替案4: 併用可否判定における優先順位フィールドの導入
各クーポンに優先順位(priority)フィールドを持たせ、併用不可の場合は優先順位が
最も高いクーポンを採用するという方式です。
**メリット**:
- 割引額の大小に関わらず、運用側が優先したいクーポンを明示的に指定できることが挙げられます
**デメリット**:
- 本Issueの要件には「最も割引額が大きいクーポンを採用する」と明記されており、
優先順位フィールドを導入すると要件と乖離することが挙げられます
- 優先順位の管理という新たな運用コストが発生することが挙げられます
この代替案は、要件に明記された「割引額が最大のクーポンを採用する」というルールと
合致しないため、不採用としました。
要件を読めば最初から成立しないとわかる案にも、採用した案と同じ分量の説明が割かれています。これは前段で挙げた「自明な項目にも両論併記する」がそのまま表れた例です。この調子で「用語定義」「今後の拡張性」まで章が並び、Design docは284行・8521文字・見出し32個まで膨らみました。PRの説明文も1232文字あり、実装したファイルの一覧を律儀に書き出しています。
コードそのものは正しく動きます。実際、生成されたコードはpytestのテスト24件がすべてPASSしており、動作自体に問題はありません。今回問題にしているのは、その設計判断を人間が追うためのドキュメントの分量です。
読んでいて疲れる理由は、情報が間違っているからではありません。ただ、「採用したのはどれで、なぜか」という一番知りたい情報が、不採用の選択肢の説明や自明なメリット・デメリットの列挙に埋もれてしまいます。読み終えても、結論を拾うのに時間がかかるのです。
Design docの書き方を指定したSkillで作らせたAfter
同じSkillに、Design doc・PRの書き方に関するガイドを追加しました。前段で挙げた4つの原因に、それぞれ対応させています。
## Design docの書き方
- 冒頭に結論(採用した設計とその理由)を3行以内で書く。詳細はその後に続ける
- 検討した代替案は表で比較する(案・却下理由の2列で十分。メリット/デメリットを毎回文章で書き下さない)
- 採用しなかった選択肢の説明は、却下理由が伝わる最小限の長さにする
- 「やらないこと(Non-goals)」を書き、スコープ外の一般論・将来の拡張可能性の羅列は書かない
- 用語定義・背景・目的・対象読者のような定型セクションは、読み手がその技術用語を知らないと
判断できる場合のみ書く。自明な場合は省略する
- 見出しは意味のある単位でのみ作る。同じ内容を複数の見出しで繰り返さない
- 迷ったら削る。書いた後に「このセクションがなくてもレビュアーは意思決定を理解できるか」を
自問し、できるなら削除する
「Non-goals」は網羅と重要度を混同させないための対処です。「結論を先頭に書かせる」は結論が最後に来る問題への対処、「用語定義などの定型セクションを省く」はテンプレートの見出しを律儀に埋める癖への歯止めにあたります。「代替案は表」は自明な項目への両論併記を防ぐ対処です。
同じIssue・同じ実装内容で作り直したのがこちらです(実装は#5と完全に同一にし、Design docとPRの書き方だけを比較できるようにしています)。
4つあった代替案は、表1つにまとまりました。
## 検討した代替案
| 案 | 却下理由 |
|---|---|
| if-else直書きで適用条件を判定 | 条件が増えるほど1つの関数が肥大化し、条件ごとの単体テストもしづらい |
| バリデーション関数の集合(Specification不使用) | 条件が状態(最低金額の値など)を持てず、クロージャが必要になりかえって読みにくい |
| ルールエンジン(外部DSLで条件定義) | 非エンジニアが条件を変更できる利点はあるが、今回の要件規模には過剰 |
| 併用可否を優先順位フィールドで判定 | 要件が「割引額最大のクーポンを採用する」と明記しており、優先順位フィールドは要件と乖離する |
「結論」を読めば採用した設計と理由が3行でわかり、代替案の表を見れば却下理由もひと目でわかります。用語定義や対象読者といった定型セクションは省きました。Specificationパターン・Strategyパターンという言葉を使ってはいますが、この記事の読者であれば説明なしでも読めると判断したためです。
定量的に比較する
同じ要件・同じ実装内容で、Design docとPRの説明文がどれだけ変わったかをまとめます。
| 項目 | Before(#5) | After(#6) |
|---|---|---|
| Design doc 行数 | 284行 | 41行 |
| Design doc 文字数 | 8521文字 | 1239文字 |
| Design doc 見出し数 | 32個 | 6個 |
| PR description 文字数 | 1232文字 | 396文字 |
Design docは行数・文字数ともに7倍前後、PRの説明文もおよそ3倍の差になりました。実装は一字一句同じなので、この差はすべて「ドキュメントの書き方」から生まれています。
Skill設計のポイント
今回の比較を踏まえて、Design doc/PRを書かせるSkillに入れておくとよいと感じたポイントです。冒頭で挙げた「疲れる理由」への対処として整理し直すと、次のようになります。
- Non-goals(やらないこと)を明記させ、スコープ外の一般論を書かせない(網羅と重要度を混同させない)
- 結論を先頭に書かせる。詳細は結論を補強する形で後ろに続ける(結論が最後に来る問題への対処)
- 用語定義や背景説明のような定型セクションは、本当に必要な場合だけ書かせる(見出しを律儀に埋める癖への歯止め)
- 代替案の比較は表にする。文章でメリット・デメリットを書き下すと、それだけで数行ずつ増えていく(自明な項目への両論併記を防ぐ)
- 「このセクションがなくてもレビュアーは意思決定を理解できるか」を判断基準として与える
どれも特別な工夫ではありません。ただ、これを明示的にSkillへ書かない限り、生成AIは網羅する方向にしか倒れないというのが、今回の実験で得た実感です。
まとめ
生成AIの文章を読むと疲れる理由は、内容の正しさではなく、重要度を選別せず・結論を後回しにし・型を律儀に埋め・自明な項目にも両論併記するという4つの癖にあります。同じ要件でも、Skillにこれらへの対処を明示するだけで、Design docの分量は7倍近く変わりました。生成AIの文章を読みたくないと感じたときは、AIの出力そのものを疑う前に、まずSkillやプロンプトに「何を書かないか」を指定できているかを見直す価値がありそうです。
今回使ったIssueと2本のPRは、そのままリポジトリに残しています。気になった方は実際のDesign docとPRの説明文を見比べてみてください。
- Issue: https://github.com/Taketo-Yoda/Qiita/issues/4
- Before PR: https://github.com/Taketo-Yoda/Qiita/pull/5
- After PR: https://github.com/Taketo-Yoda/Qiita/pull/6
【Appendix】実際に使用したSKILL.md
Before/Afterそれぞれで実際に使ったSKILL.mdの全文です。
- Before(工夫なし版)
- After(改善版)