日頃は事業やマーケからプロダクトマネジメントまで幅広く業務をしているtettuanです。
週末や連休に開発コードを書いて自分用のアプリケーションを作っているのですが、
Cursor/Yolo, Roo-ClineなどのAIコーディングが発展してきて、非常に、かつてないほど助かっています。
主旨
これまで、
開発が本職では無いため、セキュリティやパフォーマンス要件を細かく詰めていくことはほとんどしていませんでした。自分用のアプリケーションに閉じる用途でもあったためです。
しかし、Cursorで自動化することで、ベストプラクティスを取り入れたコードを書くことが自然とできるようになりました。
例えば認証の要件を強化したり、エラーハンドリングを強化したり、キャッシュの利用を強化したり、・・・といったことが実現できます。
限られた時間のなかで、自分一人でできる範囲にレバレッジをかけることが、相当できるようになりました。
とくにGeminiのAPIが安価で提供されていることもあって、事業内容の分析をVector化するためのRAG構築や、RailsサーバとPythonクライアントのAPI連携なども、Cursorで広く自動化できるようになりました。
そんなふうに、
開発時間が限られているがゆえに、自動化能力を最大限引き出す工夫を凝らしてみたので、そのプロセスを振り返りながら紹介します。少しでもお役に立てば幸いです。
アウトライン
- ドキュメント作成を自動化する
- 要求から始め、課題→タスク分解する
- GitHubとIssue連携する
- AIリーダブルにする
- スコープを厳格化する
- ブランチ戦略を持つ
- 自動実行のstateを管理する
- テストを書く
- リファクタする
- 気軽に捨てる
アプリケーション概略:
例えばEDINETからAPIで開示書類を取得して、Railsに置き、それを別のPythonアプリケーションがAI分析のために使うAPIサーバを想定しています。
1. ドキュメント作成を自動化する
自動開発を始めてから、しばらくして、ドキュメントの自動生成に取り組みました。Cursorの強みは、コードだけでなくドキュメントの生成も得意としている点です。私の場合、以下のような流れで活用しています。
- プロジェクトの概要文書の生成
- 開発内容のスコープや仕様書作成
- 開発指示書(タスク指示)の作成
単にドキュメント作成を依頼するのではなく、「ドキュメント作成コマンド」を用意しました。
これによって、要求が何度出てきても、どんな機能を追加したくなっても、
「〜を実現するために、@crate_project.md を用いてProject作成を実行して。」と指示するだけです。
これと同程度の文面を、
「〜を実現するために、@create_issue.md を用いてiessue作成を実行して。」
「issue md と @create_task.md を用いて、task 作成を実行して。」
と続けていきます。
(実際、ほぼコピペなので、GitHubのWikiにまとめて、コピペ指示しています。)
将来的には、この部分を Roo-Cline のようなオーケストレーションAIに渡したいと考えています。
2. 要求から始め、課題→タスク分解する
Cursorに限らず、AI側へ渡せる情報量には限りがあります。
コードベースを持っていても、全てを読み込みながら処理しているわけではなさそうです。
従って、一定の文脈を作る必要がありそうでした。
そこで、きちんと要件を切っていくことからスタートしました。
AI開発は、文章化を突き進めれば進めるほど、コンテキストの共有が可能となると判断しました。
(AIの認識=テキスト化された情報)
取り組み:
- 要求仕様から技術要件への分解
- 機能単位でのタスク分割
- 依存関係の整理と実装順序の決定
これらを、 Xで見かけたやり方などを参考に、agentフォルダに保存していきます。以下のようになります。
agent/projects/
agent/issues/
agent/tasks/
agent/guidelines/
:
記法はMarkdownを用い、 agent/ 配下には .md ファイルが並びます。
コーディングが得意なAIですから、要件詳細化も大変得意のようです。
- 「やりたいこと」が先にあって、「具体的な技術に落とし込むところが大変」という開発が、
↓ - 「やりたいこと」があれば「具体的な技術に落とし込むところは任せる」開発
に変わった瞬間でした。
自分でググりながら調べていた認証方式も、モデリングも、キャッシュ処理も、SQL最適化も、すべて考えて案を作ってくれます。
3. GitHubとIssue連携する
課題管理とソースコードを連動させるため、GitHubとの連携を徹底しました。先ほどの agent/ 配下の projects と issues は、GitHubにも同期されています。
これにより、GitHubのProjectにはIssueが並び、READMEにProject概要が書かれています。
さらにIssueツリーは相互に関連性を持った状態になっており、以下のように課題間をgraph化しています。これらは md ファイルで実現しているため、特にDBも何も使いません。
ちなみに以下の方式はCursorから提案してくれているので、自分で発案していません。
(mermaid)
graph TD
A[Project Context] --> B1[Base Implementation]
A --> B2[Data Retrieval]
A --> B3[API Endpoints]
B1 --> C1[Single Feature Tasks]
:
4. AIリーダブルにする
これまでの開発コードは、歴史的経緯もあって一貫したコードになっていません。
そのままAIで自動開発すると、すぐに暴走して、モデル名が見つからないとmigrationファイルを作り始めたりしました。
かといってリファクタリングするのも慎重に行う必要があります。なぜなら、理解できないコード、少ないテストの状況で、適切なリファクタリングは実現できないからです。
従って、まずはドキュメント、指示書、現在のコードを理解する方法をAIリーダブルにしました。
- 明確な命名規則の採用
- ディレクトリ構成のルール化
- 作業内容の構造化
- オーケストレーションしやすい指示書
例えば、agent/tasksディレクトリには実装タスクを番号付けして配置し、かつIssueやProjectへの参照を持っておきます。タスク指示だけでも、Cursorが文脈を理解しやすい構造にしています。
(必ず読みにいくわけでは無いため、タスク指示にも概略を示しています)
タスクにも種類があるため、単一作業と複数作業など、いくつかの視点を持ってタスク生成する必要があります。これらの種類も指示書に加えます。
AIリーダブルというと「読みやすさ」にフォーカスしがちですが、大事なのはコンテキストです。
前後関係、今のタスクが何に紐づいているのか。ここを明示的に示すためのドキュメント作成力が必要です。
5. スコープを厳格化する
複数の理由で、スコープを厳格化しました。
例えば
- ハルシネーション予防
- コード破壊防止
- タスク明確化目的
- コミット単位の最適化
などです。
特に、実装対象と実装範囲外、変えて良いコード範囲と変更を禁止する範囲を明示しました。
これらはProjectの概略からIssue段階に至るまでに、自動で決められています。routes や migration を維持すれば、大きなスコープ変更は起きないため、防衛ラインはこの2つになるかと思います。(APIエンドポイント変更を禁止するケースもありえるかもしれません)
例えばProjectでは、以下のようにスコープが自動生成されます。
## Scope
### Included Scope
- RESTful API endpoints for EDINET data access
- ActiveRecord enums for document types and status
- Domain-specific error handling
- Response time optimization
- Data integrity validation
- i18n support for static data
### Excluded Scope
- Changes to existing non-EDINET APIs
- Database migrations
- EDINET data fetching from edinet-fsa.go.jp
- Route changes outside EDINET endpoints
Issue単位では以下のようなスコープが自動生成されます。
## Scope
### Included
- List endpoint implementation
- Detail endpoint implementation
- Search functionality
- Response optimization
- Rate limiting
### Excluded
- Database changes
- Authentication system (implemented in base)
- Data retrieval logic (separate service)
スコープの厳格化を進めたのには理由があります。
雑な指示で最後まで一気に完成して欲しい気持ちはありつつ、手戻りポイントを作りながら進めた方が効率がよいためです。
週末開発では特に重要で、段階的な開発のほうが中断できて安心です。一定量のタスクを用意すれば、きっとRoo-Cline のようにオーケストレーションされる時代がすぐやってきて、連続実行に困らないだろうとも思います。
6. ブランチ戦略を持つ
効率的な開発フローのため、明確なブランチ戦略を採用しています。
といっても、一人開発で、複数のブランチを渡り歩くわけではありませんから、AIが混乱しないための命名規則と、将来的に並列稼働できることを見越した戦略になっています。
- base branch は develop で固定
- feature/タスク番号_機能名の命名規則
- ドキュメントは develop でコミットし、コードはfeatureブランチでコミットする
といった具合です。
これにより、Cursorとの協働がよりスムーズになります。agent 配下への変更がfeatureブランチに紛れ込んだり、指示の変更を他ブランチが持たずに済むなどの分離が可能となっています。
将来的に並行稼働した場合、コンフリクトしないためにも、指示は一貫して整合させられるよう develop に置いています。
7. 自動実行のstateを管理する
ドキュメント自動生成を行なってからしばらくしたのち、コーディング自動化の過程自体の「状態管理」を重視するようになりました。
何度もやり直してみて思ったのですが、CursorのComposerに渡す文脈が切れる瞬間があります。
前後のコンテキストを踏まえてくれるのは良いのですが、その分、Composerを切り直したりすると、引き継ぐ情報が減ってしまうのでしょう。
特に、例えばEDINETから取得するAPIと、Pythonアプリに渡すAPIは、用途もスコープも異なるのですがごちゃ混ぜになったことがありました。これがタスク処理の過程で唐突に起きたため、指示書だけでは限界があると考えました。(スコープ厳格化によって、出なくなっていたのですが。。)
そこで、作業がどこまで進んでいるのか分かっていれば、作業全体のコンテキストのなかで処理できるのではないか?と考えました。
ここは、いったんやってみている感じですので、今後の進展次第では不要になるかもしれません。ただ、コンテキストが2次元、3次元になるような方法は持っていた方が良さそうです。
8. テストを書く
テストコードの自動化は、取り上げるべきことは無いと思うほど、みなさん取り組んでいると思います。
Cursorを活用することで、テストコードの品質が大幅に向上し、メンテナンス性も高まりました。
一人開発ではサボりがちだったのですが、少し手間のかかるテストも気軽に入れられるようになりました。
なお、漠然と開発指示すると、テストコード作成もハルシネーションしがちです。
テストコードを開発しているはずが、通らないとテストを消したり、テストを通すためにmigration変えようとしたりする挙動が見られたりします。
こうした経験から、実現したいゴールを示す必要性はすぐに感じられました。
9. リファクタする
いわゆる既存コードのリファクタリングだけではありません。
- 一度生成したtask指示書を、実装に着手する前に Project/Issueと照らし合わせ、最適化すること
- 実施したタスクを振り返り、実現できたことやProject/Issueの目的に照らして相応しく無いこと・足りないこと
などをリファクタリングします。タスク単位(あるいはブランチ単位)で実施しています。
タスク完了時点での最適化を行なったのちに、役割を終えたプロジェクト〜タスクのドキュメント全てを、遠慮なく廃棄することができます。
この段階で、agent/ 配下に存在する Markdown ファイルは削除し、GitHub側の Issue もCloseします。
GitHub側は、本来コードベースでマージされれば勝手にCloseされます。
しかしAI自動開発のミスをリカバリーするため、マージされず捨てられることを前提にブランチやIssueを作るため、ここでCloseしておくほうが無難だと考えています。やり直しの場合は、Issueやタスクを再利用することはほとんどなく、常に最新状態から仕切り直します。
捨てられたドキュメントはGitHubには残っています。
仕様はコメントや、GuidelinesやOutlinesとして、他の資料に適宜反映するフローを持っておくことが重要です。参照すべき情報は充足します。そのため自動生成した指示書ドキュメントは、一過性のものとして遠慮なく捨てていきます。
その他、通常のリファクタリングとしては、APIの仕様書から enum 定義を書き起こしたり、考えられるパターンを作成したり、agent/guidelines を書き換えたりなどのUpdateも適宜実施しています。
もちろんこれらも、Projectの作成からタスク化まで、ドキュメント指示書を作成することで叶います。ただし、こうなってくると、もはやリファクタリングというよりも、やりたいことを示す開発指示に相当します。
10. 気軽に捨てる
最後に重要なのは、コードを気軽に捨てることです。
捨てても作業が無駄にならないように
- 指示が無駄にならない仕組み
- 再生成によって同じコードベースが再現できる
この2点を重視しました。
コマンドラインから GitHub CLI を利用して連携させるのも、このためです。
agent 配下にドキュメントを配置しておくことで、コミットした指示が残ります。
さらに branch へ移動して指示を書き換えたり、タスクを増やしても、ブランチ戦略によって元に戻ることができます。
この状態を作ることに成功してから、コードそのものを捨てることに躊躇しなくなりました。Composerへの指示も、リセットしたいときには、いつでもリセットできます。
まとめ
Cursorを活用した開発自動化は、個人開発者の可能性を大きく広げてくれます。特に週末や限られた時間での開発において、その効果は絶大です。
上記の10個のポイントは、私がXでの発信をみたり、実際に試行錯誤しながら見出した方法論です。もちろん、これらは私の経験に基づくものであり、プロジェクトや目的によって最適な方法は変わってくるでしょう。
おおまかに指示をまとめると、例えば次のようになっています。
agent
├── command
│ ├── create_issue.md
│ ├── create_project.md
│ ├── create_tasks.md
│ │ :
├── guidelines
│ ├── README.md
│ ├── api
│ │ ├── serializers.md
│ │ │ :
│ │ └── versioning.md
│ ├── cache.md
│ ├── models
│ │ └── ...
│ └── naming_conventions.md
├── issues
│ ├── 991_edinet_api_base.md
│ ├── 992_edinet_data_retrieval.md
│ └── 993_edinet_api_endpoints.md
├── outline
│ ├── ...
├── projects
│ ├── 5_api_openapi_refactor.md
│ └── 6_edinet_api_implementation.md
└── tasks
├── 991_1_edinet_api_base_tasks.md
├── 991_2_edinet_error_handling_tasks.md
├── 991_3_edinet_serializer_routing_tasks.md
├── 992_1_edinet_data_retrieval_tasks.md
├── 992_2_edinet_caching_tasks.md
├── 992_3_edinet_error_handling_tasks.md
├── 993_1_edinet_api_endpoints_tasks.md
├── 993_2_edinet_detail_endpoint_tasks.md
├── 993_3_edinet_search_tasks.md
└── task_status.md
今後
これまで「個人開発だから・・」と小さく維持することを考えていました。
バージョンアップなどのメンテナンスや、セキュリティ対策など、大きなシステムになるほど運用不可が高まるためです。
しかし、今は自動化の流れの中で、考え方を大きく変えました。
小さな体制でも「レバレッジが効く」ため、もう少し大掛かりなサービス開発をしてみようと考え始めています。
ほぼ自動化されることによって、開発リソースは人的な意味を持たなくなる可能性が高くなっていると感じます。
おまけ
中小企業のAI活用や、DX化など、何からどうしていいかにお悩みの方に向けて。
- 現在の事業優先度に基づいた判断
- 限られたリソースのなかで撮りうる最善案の提案
- 開発案件の要求整理
などのコンサル業務もご相談受け付けています。お困りごとがあって、周囲に相談できずに悩んでいる方は、よろしかったらお気軽にどうぞ。
お問い合わせ先