Cline+Claudeでの開発を試してみた感想
2年くらい前からCopilotやCursorによるコーディングサポートを受けた開発は実際に行なっていたのだけど、先週くらいからコーディングエージェントによる開発にも本腰を入れて調査を始めた。以下はその際に雑に調べた情報まとめ。
そんでこの土日くらいまで毎日、主にCline+Claude(その他versionや派生系クライアントも含む)を使って色々とコード生成させたりして実験したのでその感想を書く。
試してみたこと
最初は簡単なpromptを入力してポン出しで生成させるToDoリストとか管理画面みたいなものを作らせてワイワイしてた。だけど何回かやったら流石に飽きてきたので、もう少し規模の大きなタスクに取り掛からせることにした。
既存プロジェクトへのテスト追加
まず最初に、個人開発してるモンハンnowのTA走者向けのwebサイトが現状テストゼロだったので、これに対してClaude 3.5 sonnetとClineを使ってテストカバレッジをどこまで上げられるか検証してみた。
技術スタックとしてはHono/TypeScript/jsx/Bun/SpreadSheetで、SSGしたビルド結果をCloudflare Pagesにデプロイするようなもの。規模的には大体20コンポーネントに700行前後のビジネスロジックのファイルがある感じ。
まずは.clinerules
を作成し、テスト環境の整備から始めた。.clinerules
は下記。
.clinerules
あなたは高度な問題解決能力を持つAIアシスタントです。以下の指示に従って、効率的かつ正確にタスクを遂行してください。
まず、ユーザーから受け取った指示を確認します:
<指示>
{{instructions}}
</指示>
この指示を元に、以下のプロセスに従って作業を進めてください:
---
1. 指示の分析と計画
<タスク分析>
- 主要なタスクを簡潔に要約してください。
- 記載された技術スタックを確認し、その制約内での実装方法を検討してください。
- 重要な要件と制約を特定してください。
- 潜在的な課題をリストアップしてください。
- タスク実行のための具体的なステップを詳細に列挙してください。
- それらのステップの最適な実行順序を決定してください。
### 重複実装の防止
実装前に以下の確認を行ってください:
- src/components/ 内の既存コンポーネントの再利用可能性
- src/lib/ 内のユーティリティ関数の活用
- 共通のスタイル定義(src/styles/global.ts)の利用
- 多言語対応コンポーネントの統一的な実装方法
このセクションは、後続のプロセス全体を導くものなので、時間をかけてでも、十分に詳細かつ包括的な分析を行ってください。
</タスク分析>
---
2. タスクの実行
- 特定したステップを一つずつ実行してください。
- 各ステップの完了後、簡潔に進捗を報告してください。
- 実装時は以下の点に注意してください:
- src/components/ 内のコンポーネント構造の一貫性維持
- TypeScriptの型定義の厳密な管理
- ランキングロジックの整合性確保
- 多言語対応の一貫性維持
---
3. 品質管理と問題対応
- 各タスクの実行結果を迅速に検証してください。
- エラーや不整合が発生した場合は、以下のプロセスで対応してください:
a. TypeScriptコンパイルエラーの確認と修正
b. Viteビルドエラーの解決
c. コンポーネントのレンダリング検証
d. ランキング計算ロジックの正確性確認
- 検証結果は以下の形式で記録してください:
a. 検証項目と期待される結果
b. 実際の結果と差異
c. 必要な対応策(該当する場合)
---
4. 最終確認
- すべてのタスクが完了したら、成果物全体を評価してください。
- 当初の指示内容との整合性を確認し、必要に応じて調整を行ってください。
- 実装した機能に重複がないことを最終確認してください。
- 多言語対応の完全性を確認してください。
---
5. 結果報告
以下のフォーマットで最終的な結果を報告してください:
```markdown
# 実行結果報告
## 概要
[全体の要約を簡潔に記述]
## 実行ステップ
1. [ステップ1の説明と結果]
2. [ステップ2の説明と結果]
...
## 最終成果物
[成果物の詳細や、該当する場合はリンクなど]
## 課題対応(該当する場合)
- 発生した問題と対応内容
- 今後の注意点
## 注意点・改善提案
- [気づいた点や改善提案があれば記述]
重要な注意事項
- 必ず日本語で回答してください。
- Honoのドキュメントはhono_docs.mdに記載しています
- node_modulesの内容は読み込まずに無視すること
- .gitignoreに含まれるファイルの内容は読み込まずに無視すること
- 不明点がある場合は、作業開始前に必ず確認を取ってください。
- 重要な判断が必要な場合は、その都度報告し、承認を得てください。
- 予期せぬ問題が発生した場合は、即座に報告し、対応策を提案してください。
- 一定のタスクが完了した場合はgitコミットを行ってください。
- .envは読まないこと
- 秘匿情報はgitにコミットしないこと
- プロンプトを必ず含めること
- 実装した内容をリスト形式で書き記すこと
- 明示的に指示されていない変更は行わないでください。
- 特にランキングロジックの変更は慎重に行い、必ず承認を得てください。
- 多言語対応の一貫性を維持してください。
技術スタック
コア技術
- TypeScript
- Vite
- Hono
- JSX
フロントエンド
- React Components
- Global Styles
開発ツール
- Biome (コード整形)
- npm
- bun
プロジェクト構成
以下のディレクトリ構造に従って実装を行ってください:
mhn-leaderboard/
├── src/
│ ├── global.d.ts # グローバル型定義
│ ├── index.tsx # エントリーポイント
│ ├── components/ # Reactコンポーネント
│ │ ├── Archives.tsx # アーカイブ表示
│ │ ├── Changelogs.tsx # 変更履歴
│ │ ├── Guideline.tsx # ガイドライン(日本語)
│ │ ├── GuidelineEn.tsx # ガイドライン(英語)
│ │ ├── Header.tsx # ヘッダー
│ │ ├── History.tsx # 履歴表示
│ │ ├── Home.tsx # ホーム画面
│ │ ├── Layout.tsx # レイアウト
│ │ ├── LinkLists.tsx # リンクリスト
│ │ ├── LinkMonsterLists.tsx # モンスターリンクリスト
│ │ ├── MonsterTable.tsx # モンスター一覧
│ │ ├── RankerTable.tsx # ランキング表示
│ │ ├── RankerTitle.tsx # ランキングタイトル
│ │ ├── SupportUs.tsx # サポート情報(日本語)
│ │ ├── SupportUsEn.tsx # サポート情報(英語)
│ │ ├── TableTitle.tsx # テーブルタイトル
│ │ ├── UpdateHistory.tsx # 更新履歴
│ │ └── UpdateInfo.tsx # 更新情報
│ ├── lib/ # ユーティリティ
│ │ ├── constans.ts # 定数定義
│ │ ├── ranking.ts # ランキングロジック
│ │ └── utils.ts # 共通関数
│ └── styles/ # スタイル定義
│ └── global.ts # グローバルスタイル
配置ルール
- グローバル型定義 →
src/global.d.ts
- エントリーポイント →
src/index.tsx
- Reactコンポーネント →
src/components/
- ユーティリティ関数 →
src/lib/utils.ts
- 定数定義 →
src/lib/constans.ts
- ランキングロジック →
src/lib/ranking.ts
- スタイル定義 →
src/styles/global.ts
テスト規則
テストファイルの配置
- コンポーネントのテスト →
src/components/__tests__/
- ユーティリティのテスト →
src/lib/__tests__/
テストの実装規則
- テストファイルの命名
- コンポーネント:
[ComponentName].test.tsx
- ユーティリティ:
[utilityName].test.ts
- テストの構造
- describeブロックでテストをグループ化
- itブロックで個別のテストケースを記述
- 期待される結果を明確にコメントで記述
- モック化の規則
- 外部APIやデータベースアクセスは必ずモック化
- モックデータは現実的なデータ構造を反映
- beforeEach/afterEachでモックのセットアップとクリーンアップを行う
- vitest の vi.spyOn を使用してモック関数を作成
- テストの実行と検証
- 各テストファイル作成後は必ずテストを実行
- すべてのテストが成功することを確認
- TypeScriptのエラーがないことを確認
- テストカバレッジの確認
- コンポーネントテストの注意点
- Honoのhtmlヘルパーを使用してレンダリング
- レンダリング結果を文字列として取得し検証
- クラス名、テキスト、属性値などの存在を確認
- 多言語対応のテキストが正しく表示されることを確認
- ユーティリティテストの注意点
- 関数の入出力を厳密にテスト
- エッジケースを考慮したテストケースを作成
- 日付や時刻に依存するテストは固定値を使用
- テストメンテナンス
- コンポーネントやユーティリティの変更時は対応するテストも更新
- テストが失敗した場合は原因を特定し修正
- テストコードの重複を避け、必要に応じてヘルパー関数を作成
コマンドラインの実行結果をClineが読み取れないという問題にハマったせいもあって、初期段階のテスト環境のセットアップとサンプルテストの作成だけで$1.5程度かかった。正直今振り返るとこの問題を解決するのが一番大変だった。LLMに聞いても教えて来れないし。。
この最初のセットアップさえ終わればあとはテストを書き始めさせるだけ。
srcディレクトリ配下のcomponentsとlibの中にあるファイルのテストを書いてください。src/components/__tests__ディレクトリにはすでにいくつかのテストがあるので参考にしてください。テストを書いたら必ずbun testでテストを実行し全て成功するまで次に進まないでください。bun testを実行するときは対象のテストファイルのみを指定して実行してください。
上記のようなpromptを書いて、Auto-approve(Read/Write/Command)にした状態で実行させればあとはテストが勝手に書かれていった。書き終わるのを待つ間はYouTubeを見たりモンハンをしたりしてた。
途中、コンテキストウィンドウがいっぱいになったら新しいセッションを立ち上げて途中から再開してもらう、というのを何回か繰り返す必要はあった。その場合はどこまでテストが完了済みかを確認して、先ほどのpromptに加えてooo.tsxのテストが途中まで書かれています。このファイルからテストを書き直してください。
みたいな感じで指示を出して再実行させるというのが何度も発生してた。これは結構面倒だった記憶...。
まぁ結果的にはほとんどのファイルでテストカバレッジ(特にFuncs)は100%にできた(でもBranchとかPathはもっと少なそう)。
一部のファイルは設計的に微妙だったり、bun test --coverage
でcoverage対象の除外ができない問題があったりして低い数値が出てるけど、実質的にはかなり高いカバレッジを達成できた。
変更対象は31ファイルで、追加削除が+14505-10行。総額で$15程度かかったけど、これだけの量のテストコードを自分で書くことを考えると、かなりコスパが良いと思う。
社内向けツールの開発
次に、Roo Code(以前はRooClineと呼ばれてたやつ)を使って、「スプリント早わかりカレンダー」という社内向けツールを作ってみた。
これはゼロから要件定義をして実際に望み通りのツールを作らせてみる実験。最初の実験でいきなりデカいwebアプリを作ろうとするとコンテキストウィンドウをオーバーして面倒そうという予感があり、比較的シンプルでかつ明確にニーズのあるものをということでこれにした。前々から雑に欲しいね〜みたいな話をチームでしていたスプリント期間を視覚的に表示するペラいちのWebページ。
今回はmizchiさんのailabにある.clinerulesを試してみようと思って、それを活用した(結果的にはDenoも不要なサイトだからあんまり恩恵は受けられなかった感...)。
最初のプロンプトでは、背景・やりたいこと・機能などの要件を詳細に記述し、どのような設計でどのようなコードを書くべきかをAIに検討させた。そして、その設計計画をREADME.mdにまとめてもらった。使ったpromptは以下。
prompt.md
以下の要件仕様を参考にどのような設計でどのようなコードを書こうとしているのか検討しなさい。そしてその設計計画をREADME.mdにまとめなさい。
---
# 背景
私の会社ではagile開発を取り入れています。開発からリリースまでに大体2週間かかります。現在抱えている課題としては1スプリントの中で今は何をしている期間なのか?というのが把握しづらいということです。
例えば現在我々は、開発が2025/01/14から始まったとすると翌週の月曜日(2025/01/20)にコードフリーズが行われ、その翌日の火曜日(2025/01/21)から6日間のQA確認が開始され、次の火曜日(2025/01/28)にリリースされます。まとめると2025/01/14から2025/01/20までが開発期間、2025/01/21から2025/01/27までがQA確認期間、2025/01/28がリリース日という形です。そして同時に2025/01/28からまた次のスプリントの開発期間が始まります。
# やりたいこと
開発期間とQA期間とリリース日について、それぞれのエンジニアが今はスプリントにおける何の期間なのか?次のリリース日はいつなのか?といったことが一目でわかるようなwebページが作成したいです。
# サービス名
スプリント早わかりカレンダー
# 機能
- 開発期間/QA期間/リリース日をクエリパラメーターとして設定できる
- 設定された各期間に応じてカレンダーに期間が色分けされて一目でわかるようになっている
- 今日についてもまた別の色で一目でわかるようになっている
- スプリントは長い場合もあるので月を跨ぐ可能性もあります
- レスポンシブデザインにする
# 技術的な制約
- Deno/TypeScriptを使用すること
そしてこれで作成したREADME.mdを元にコードを生成してもらった。
驚いたのは、初回の生成でほぼやりたいUIと機能が完成したこと。
ここまでの作業にかかった費用はわずか$0.8程度で、30分以内に完了。初期実装までにかかった総費用も$1.5程度だった(上記スクショは色々調整後の最終版なので初期実装より多少はリッチ)。
割と雑な要件定義から始めたけど、初回実装で出てきたものがUIとしてはまさに欲しかったものそのままだったから体験としては非常に良かった。あんまり脳内にある仕様とそれを表現するUIがビジュアル化できないから、不格好でも自然言語を基にざっくりとしたUIの叩き台を生成してくれるのはかなり嬉しい。
ただし課題もあって、その後のロジックの詳細を詰めて考えていく段階で色々と仕様変更が必要だとわかり、右往左往するクソPdMムーブをかましてしまった結果、完成まで無駄に回り道することになってしまった(人間だったら激ギレされてたはず)。その度に適度にセッションを新しくしたり、READMEの要件定義を細かく書き直したりする作業が面倒だった。
最終的にはこんな感じのREADMEができている。
この実験で気づいたのは、機能仕様だけでなく、その機能仕様を満たす場合の実際の表示UIやデータの状態を具体例としてREADMEに記載すると上手くいきやすいということ。抽象的な要件だけでなく、具体例(今回だとREADMEの「機能要件を満たした場合の表示の具体例」というやつ等)があることでAIの理解が深まるっぽい。また、人間の開発と同様に、雑な要件定義からの仕様変更はAIプログラミングでも避けた方が良いということも学んだ(それはそう)。
試行錯誤
コンテキストウィンドウの制限との戦い
コーディングエージェントを弄っていて最も頻繁に直面する課題は、コンテキストウィンドウの制限。既存プロジェクトのコードはどうしてもトークン消費が早いので、いちいちセッションを新しくするのが面倒だった。5000兆tokensのコンテキストウィンドウが欲しい、というのが正直なところ。
特に具体的に苦労したのは、テスト実行結果のdiffがデカすぎてClaude 3.5 Sonnetのinput promptに載らない問題。例えば、bun test --coverage
の出力が大きすぎて「prompt is too long: 203969 tokens > 200000 maximum」というエラーが出ることがあった。
この問題に対処するため、Gemini 2.0 Flash(inputで約1m tokens)も試してみて、確かにプロンプトに乗りはするんだけどテストのモックデータとかの生成精度が低すぎて使えなかった。
結局、テストの出力がデカすぎる場合はコマンド実行結果をinputに食わせられないので、その部分だけ自分で手直ししたりしてた。
AIの知識の限界と対応策
Honoで作っていた個人サービスのテスト環境をCline+Claude 3.5 Sonnetでゼロから整備しようと色々実験してた時、AIがそもそもHono+jsxでのテストの知識をあまり持っていないことに気づいた(普通のReact Appのテスト手法をやろうとしてこけたりしてた)。
これについては最初はうまくいかなかったけど、HonoにはLLM用のペライチドキュメント(hono.dev/llms-full.txt)があることを発見。それをルートディレクトリにテキストとして置いておき読ませたところ、想定通りのセットアップとサンプルテストを書かせることができるようになった。LLM.txtはこのように便利であるものの、Docsのテキストってtokenを食うし、そもそもMCPを提供してくれてRAG的に使ってくれた方が楽な気もするし、LLM.txtは過渡期のソリューションかも。
テスト実装の難しさ
テスト実装で特に苦労したのは、モックデータの生成。複雑なUIコンポーネントのテストでは、レンダリングに必要となるデータが複雑でコードから読み取れないケースがあった。
例えば、モンハンnowのTA表のコンポーネントであるMonsterTable.tsx
というやつのテストでは、AIがモックデータを適切に生成できず、最終的に自分で手直した。あとは「勝手に存在しない嘘の固有名詞を作り上げる」という問題やAIが実際には存在しないモジュールや関数を想定してテストを書いてしまうことはちょいちょいあり、それが自爆の原因になることもしばしばあった。
個人的に気づいたこと
.clinerules設定の重要性
コーディングエージェントとの開発では、.clinerules
(もしくは.cursor/rules
など)の設定が重要。ここで大まかなコーディングクライアントの行動様式を定めておくとセッション中に意図した行動をしてくれやすくなる。
自分はkinopeee/cursorrulesから良さそうなruleファイルを参考にして自前のプロジェクト用のrulesを作成してくれ、というオーダーをAIに最初に出して、カスタムルールのファイルを作るところもやらせてた。
TDDの難しさ
社内ツールの開発では、最初はTDDで実装を進めたいという目論見があったけど、AIはとにかく一気に生成したがるため、割り込んでマイクロタスクを実行させるのが面倒だった。
自分で実装方針の大枠はできていても、細部にわたって実装計画が立っていない場合は、TDDをどう進めるかを人間が考える時間がボトルネックになりそう。そのため、ある程度の大きな単位で機能を実装させ、その機能に対してテストを実装させるみたいなやり方の方が上手くいく感じもした。
Auto-approveの使いどころ
初期段階の設定ファイルをいじる工程などは、Auto-approveにしないで確認しながら進める方が良さそう。軌道に乗るまでは慎重に進めた方が、暴走を防いで手戻りが減らせる。
コーディングエージェントは敷かれたレールの上を走るのはめちゃくちゃ得意だからこちらが意図した通りに進んでくれるための高速道路を最初は整備してあげたい。ルンバが掃除しやすいように人間がある程度掃除するみたいなやつと似てる。
一方、すでにあるテストを参考に別のテストを実装する、のような定型的な作業がすでに出来る場面では、最初からAuto-approveにして自動で進めてもらうと良さそう。
フィードバックのある言語やツールが良い
実行前のビルド時やコーディング時点でコンパイルエラーやwarningを出してくれる言語やツールはAIに直接フィードバックを与えられる。これはAIとアプリケーションがコミュニケーションしやすいということだ。linterやtest周りのエコシステムが整っていたり、この辺のフィードバックが得意な言語は今後のコーディングエージェントでの開発で積極的に用いられていくのだろうなと感じた。
費用と時間
各プロジェクトでかかった費用をまとめると:
- テスト追加:総額$15程度
- 社内向けツール開発:初期実装$1.5、追加修正$3~4程度
特にテスト追加では、14,000行以上のテストコードをほぼ自分でコードを書かずに生成できたのは大きな収穫。その間YouTubeを見たりモンハンをしたりできたことを考えると、時間の節約という点でも非常に効果的だった。
社内向けツールの方に関しても、ずっと欲しいと思ってたし自分でも実装できるけど、なんか面倒だな〜みたいな開発タスクについて、数十分~せいぜい数時間でデプロイまでいけたわけなので中々コスパ良いと思う。
おわりに
ClaudeとClineを主に使ったコーディングエージェントの実験を通じて、その可能性と課題を体感することができた。特に既存のソースコードに対してどのようにClaude+Clineを適用できるのかという検証ができたのは大きな収穫。
今回はTypeScript中心だったけど業務ではRuby/Railsを使っていることが多いので、これらの業務アプリでも活用できないかは今後検証していきたい。
また、新規開発の話より既存のコードベースへの適用の方が多くの職業プログラマにとっては気になるところだと思うので、n番煎じでも良いのでこういう自分のような試行錯誤のアウトプットが増えていって欲しい。
Discussion
すごく参考になりました!👏