AIエージェントを使って実際にアプリ開発→リリースした経験・知見を共有する

先日、Claude Code（コーディング用のAIエージェント）[^1]を使って作ったiOSアプリ **『電光石火』** をリリースしました。

<img width="24%" alt="電光石火" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/630123aa-2edc-41b9-ab62-b3954d7c85e7.png">
<img width="24%" alt="たしざん" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/45fb5c55-8454-4895-87e9-95d160967f4c.png">
<img width="24%" alt="県庁所在地" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/1326e028-af99-492e-847e-5b5b02c64b1d.png">
<img width="24%" alt="結果画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/3ff1389a-3775-4821-897d-9d3894288849.png">

https://apps.apple.com/jp/app/%E9%9B%BB%E5%85%89%E7%9F%B3%E7%81%AB/id6743498354

『電光石火』は、「九九」や英語の「代名詞」、「県庁所在地」など、反復練習ですばやく答えられるようになるべきものを、ゲーム形式で手軽に身につけられるiOSアプリです。「たしざん」「ひきざん」「L / Rの聞き分け」「炎色反応」「東西南北」など、定番のものから少し変わったものまで、様々なコンテンツを提供しています。

たとえば、小学1年生は毎日宿題でリングカード等を使って足し算の練習をしますが、『電光石火』を使えば、それをゲーム感覚で楽しく行うことができます。

<img width="49%" alt="足し算とリングカード" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/14f35612-7a6c-45df-9623-39c01aacf4ad.jpeg">
<img width="49%" alt="足し算とアプリ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/c0829118-e53e-40ec-afae-d49ac8f723f7.jpeg">


**AIエージェントを使ってコードを書いた話はたくさん耳にしますが、実際にプロダクトをリリースするところまで行った体験談は少ないと思います。** この記事では、AIエージェントを使って『電光石火』を開発・リリースしたことで得られた経験・知見を共有します。

:::note info
なお、この記事はAIを使わず人手で書きました（画像生成と校正にはAIを利用）
:::

## まとめ

- AIエージェントを使うと体感で3〜5倍速くらいで開発できた
- AIのコストは低いので、まずAIに書かせてみて、ダメだったら人間が作業をする
- メンテ不能にならないように適宜人間が手をいれる必要がある
- まずAIにコードを書かせてから、人間が共通化・抽象化の設計をする
- 一度できた設計に沿ってAIに開発させるのは簡単
- AIエージェントとテストファーストは相性が良い
- 同じモデルでも、チャットAIよりAIエージェントの方が賢くなる
- AIエージェントに適した言語・適さない言語がありそう
- コーディングツールというよりも、AIとのチーム開発だと考える
- コミュニケーションコストの高いチームではAIエージェントを活かしきれなそう
- AIの特性を考慮してアプリの仕様を検討すると良さそう
- 漫然と使うのではなく、AIエージェントが機能する方法を試行錯誤する

## Claude Codeとは？

Claude Code[^1]は、Claude[^2]を開発しているAnthropic社が提供するエージェント型コーディングツールです。コマンドラインで動作し、指示に従ってコード生成・ビルド・テスト・コミットなどを自動で行います。

![Claude Code](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/6de867d3-3730-4905-a900-a8bada632ff5.png)

[^1]: Claude Code: https://docs.anthropic.com/ja/docs/agents-and-tools/claude-code/overview
[^2]: Claude: https://docs.anthropic.com/ja/docs/intro-to-claude

AIエージェントは内部でAIモデルを利用しますが、僕が利用したモデルはClaude 3.7 Sonnet[^3]です。

[^3]: Claude 3.7 Sonnet: https://www.anthropic.com/news/claude-3-7-sonnet

## 経験と知見

### AIに動作するコードを高速に作らせる

**AIの最大の魅力は速さです。** 人間ではまったく太刀打ちできない速さでコードを書くことができます。

『電光石火』では最初に「たしざん」のコンテンツを作りましたが、そのときは次のように指示をしました。

> 一桁のたし算を練習するためのViewを追加し（新しいファイルを作ってください）、中身を実装してください。

これだけで、メインの部分についてはリリース版の「たしざん」とほぼ同じものが出来上がりました。

<img width="24%" alt="初期のたしざん" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/f650b8a5-1e70-4ff2-981b-81cacf93e1f1.png">
<img width="24%" alt="リリース版のたしざん" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/f43fee58-4c13-4a17-9e07-f49d785bbd15.png">

:::note
最初に作られた「たしざん」（左）とリリース版の「たしざん」（右）
:::

自分で実装したとしても、「たしざん」のコンテンツを実装すること自体は難しくありません。しかし、

- どのような設計が良いか
- UIのレイアウトやデザインはどうするか
- 型や変数名をどうするか

など、考えることはたくさんあります。それらを **ゼロから考えるよりも、とりあえずAIに雑に動作するものを作らせてから、それをベースに考えた方がはるかに楽です。** わずか1分ほどで動作するコード（ロジック、View、画面遷移など）が出来上がったのはなかなか驚きの体験でした。

なお、「たしざん」の例のように、 **AIがいつも正しく動作するコードを作れるわけではありませんが、もし失敗しても大した問題ではありません。AIにコードを書かせるのは、時間もお金もほとんどかからないからです。人間がやる前にとりあえずやらせてみて、ダメだったら人間がやればいいのです。**

#### より複雑な例: ランキングの実装

より複雑な例として、ランキングのViewを実装したときの話を紹介します。

『電光石火』にはプレイするごとに記録を保存し、それをランキング形式で表示する機能があります。

<img width="24%" alt="ランキング" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/99f10ffe-d4d6-4151-8beb-3f34ae364e88.png">

ランキングのViewを実装する際には、次のようにAIに指示しました。

> RankingViewを実装してください。＜コンテンツの種類を特定するパラメータ＞を受け取り、それに対応したランキングを表示してください。

これだけで、 **SwiftData[^4]にクエリを投げてデータを取得し、UI上にランキング形式で表示するViewと画面遷移のコードが出来上がりました。** デザインやレイアウトは調整しましたが、データの取得や状態反映のコードはそのまま採用しました。しかも、勝手に「今日」「今週」「今月」「すべて」の期間を切り替えられるようにしてくれました。僕は全期間のランキングしか想定していませんでしたが、期間切り替えはなかなか良かったのでそのまま採用することにしました。

[^4]: SwiftData: https://developer.apple.com/xcode/swiftdata/

:::note info
事前にSwiftDataを使ってデータを保存する処理はAIに書かせていたので（スキーマ設計のみ僕が行いました）、それを前提にデータ取得と表示の部分を実装させました。
:::

### 共通化・抽象化は人間が行う

「たしざん」と同様に「ひきざん」「九九」を作った後で、「東西南北」のコンテンツを作りました。娘が、「北東とか言われても、方向がすぐにわからない」と言っていたからです。

<img width="24%" alt="東西南北" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/070d2895-ddaa-4595-b3c7-73f7fbd9f61d.png">

このように、 **様々なコンテンツを追加していくと、類似の処理が書かれたコードを共通化したくなってきます。それを怠ると、たとえばレイアウトやデザインを少し修正するだけでも、たくさんあるコンテンツのすべてを修正することになり、メンテが困難になります。**

しかし、「たしざん」と「ひきざん」のような単純な共通化ならともかく、様々な種類のコンテンツを統合する **複雑で高度な共通化や抽象化は、現時点ではAIには困難です。**

たとえば、『電光石火』には現状で、大きく分けて次の3種類のコンテンツがあります。

- 計算問題
- 選択問題
- 自由記述問題

<img width="24%" alt="計算問題" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/f43fee58-4c13-4a17-9e07-f49d785bbd15.png">
<img width="24%" alt="選択問題" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/85be24d0-db0b-4318-ad10-c70b5e0c61e4.png">
<img width="24%" alt="自由記述問題" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/1326e028-af99-492e-847e-5b5b02c64b1d.png">


さらに、それらにも様々なバリエーションがあります。選択問題であれば、次のような種類があります（実際にはさらに細分化されています）。

- 単純な選択問題（英語の月）
- デコレートされた選択問題（炎色反応）
- 特殊なUIによる選択問題（東西南北）
- テキストではなく音声での出題（L / Rの聞き分け）

<img width="24%" alt="英語の月" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/85be24d0-db0b-4318-ad10-c70b5e0c61e4.png">
<img width="24%" alt="炎色反応" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/ec6e89d9-19b4-4f1f-89d5-66a28f824bf7.png">
<img width="24%" alt="東西南北" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/070d2895-ddaa-4595-b3c7-73f7fbd9f61d.png">
<img width="24%" alt="L / Rの聞き分け" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/8ee8a0fb-d4b1-4813-a024-14def4ac98fa.png">

このように複雑なバリエーションが存在する一方で、どのコンテンツであっても、出題し、正誤判定し、経過時間や残りの問題数を管理・表示するのは共通です。

**多種多様な問題に共通する処理を単一のコードで扱えるようにし、同時に、異なる部分だけを自然に記述できるようにするには高度な抽象化が必要です。現時点では、そのような抽象化は人間が設計して行う必要があります。**

#### 『電光石火』における抽象化の例

『電光石火』では、問題を扱う型は `ProblemProtocol` に準拠した型となっており、個々の具象 `Problem` 型で `Question` と `Answer` が自由に定められる設計としました。

```swift
protocol ProblemProtocol: Sendable, Equatable {
    associatedtype Question: Sendable, Equatable
    associatedtype Answer: Sendable, Equatable
    
    var question: Question { get }
    var correctAnswer: Answer { get }
    
    func isCorrect(_ answer: Answer) -> Bool
}

extension ProblemProtocol {
    func isCorrect(_ answer: Answer) -> Bool {
        answer == correctAnswer
    }
}
```

たとえば、単純な選択問題では `Question` や `Answer` は `String` ですが、「炎色反応」では元素に応じて選択肢のラベル色を変える必要があるので、 `String` ではなく `enum FlameTest.Element` 型として扱っています。View側で、もし `Answer` である `Element` が `.na` （Na: ナトリウム）であれば、それに応じてボタンのラベル色を黄色🟡にするなどしています。

実際には、抽象化はより複雑に階層化・細分化されています。選択問題は `ProblemProtocol` を継承した `SelectionProblem` として抽象化し、 `options` プロパティを追加するなどされています。同様に、View側も階層化・細分化された抽象化が行われており、最終的な個々のコンテンツのViewでは、そのコンテンツに特有の（「炎色反応」であれば選択肢に応じてボタンラベルの）部分だけが記述できるようになっています。

**そのような制御を（今の）AIに任せると、問題の種類に応じた分岐処理（ `if` 文や `switch` 文など）を多用するコードを記述しがちです。階層的に細分化されるものを分岐で書こうとすると多段ネストが必要となり、可読性が著しく低下します。対して、分岐を使わずに、前述のようなProtocol-oriented programmingに基づいた抽象化を人間が行うことで、コードの複雑化を避け、メンテナンス性を高めることができます。**

### まずAIにコードを書かせてから共通化・抽象化する

**共通化・抽象化を人手で行う上でも重要なのが、まずはじめにAIにコードを書かせるということです。** 最終的に人間が共通化・抽象化をするにしても、ゼロから抽象化の設計を考えるのは難易度が高いです。AIを使わずにコードを書く場合でも、ある程度コードを書いてから冗長になった部分の共通化・抽象化を考えることで、思考負荷を小さくすることができます。同じように、AIにコードを書かせる場合にも、 **先にAIの書いたコードがある状態で共通化・抽象化を考えると簡単です。**

**AIエージェントを使ったソフトウェア開発において、ボトルネックは人間です。** AIはものすごいスピードでコードを書くことができるので、人間の作業時間をどれだけ減らせるかが生産性向上の鍵です。 **ゼロから効果的な設計を考えて頭を悩ませるよりも、雑にAIに作らせてから共通化・抽象化した方がずっと効率的です。**

なお、 **一度共通化・抽象化してしまえば、それに沿ってAIに開発させることができます。「Aを参考にBを実装してください」のように依頼すれば、AIは既存コードを参考に、人間の設計に沿ってコーディングしてくれます。**

:::note warn
あまりトリッキーな設計だとAIが理解できないかもしれません。特に抽象化については、一般的な方法で平易なコードを書いた方が上手く行きやすいように思います。
:::

### テストファーストで開発を行う

『電光石火』の開発を通して得られた知見の一つは、 **AIエージェントとテストファーストは相性が良い** ということです。

ChatGPTが普及し始めた頃、AIにテストコードを書かせると良いという話が広がりましたが、僕は懐疑的でした。AIが書いたコードを検証するために、テストこそ人間が書くべきではないかと考えていたからです。また、AIが書いたコードをAIが書いたテストで検証するのは、トートロジー的で意味がないのではないかとも考えていました。しかし、実際にAIにテストを書かせてみると、それが機能することがわかってきました。

人間の場合でも、仕様が与えられたとして、それを満たすロジックを書くのと、それを検証するテストを書くのでは、後者の方が簡単です。なぜなら、仕様をそのままコードに落とし込めば良いからです。たとえば、ソートアルゴリズムを実装するよりも、ソート済みの配列の要素が小さい順に並んでいるか検証する方が簡単なのは想像しやすいと思います。

**人間と同じように、AIにとってもロジックを実装するよりテストを実装する方が簡単なのです。** そのため、AIはテストを正しく書くことができても、ロジックを書くのに失敗するケースがあります。そんなときに **テストがあれば、AIエージェントはテストを実行し、ロジックのミスに気付くことができます。**

**AIにテストを書かせる上で注意が必要なのは、AIがずるをすることがある点です。実際に、AIがテストをパスすることを優先し、ロジックに合わせてテストを歪めてしまうことがありました。そんなときに有効なのは、先にテストを書かせることです。ロジックが未実装の状態であれば、その影響も受けません。ロジックを実装させるにはどうせ仕様を説明するのだから、そのまま仕様に沿ってまずテストを実装させてしまえば良いのです。**

:::note info
AIにテストを書かせるのは良いですが、テストの内容は人間がチェックした方が良いです。あくまで、ボイラープレートが多くなりがちなテストコードを人手で書かなくて良いということであって、内容の正しさが常に担保されるわけではありません。テストが間違っているとロジックの検証もできなくなるので、テストの内容はきちんとチェックした方が良いです。
:::

『電光石火』では、網羅的にテストを書かせているわけではないですが、要所でテストファーストで開発しました。

たとえば、「たしざん」では、「7 + 8」の次の問題として「7 + 9」が出題されると、「7 + 9」の答えを覚えていなくても、「7 + 8」の答えから簡単に「7 + 9」の答えを導けてしまいます。そのような出題が多いと足し算の練習になりません。そのため、できるだけ類似の問題を連続で出題しないように特殊なシャッフルが必要です。

そのときは、まずそのようなシャッフルが実現できているか評価するテストをAIに書かせ、それからシャッフルを実装させました。残念ながら、AIは特殊シャッフルを正しく実装することができず、僕が自分で実装することになりましたが、テストに関してはAIが有効なものを実装してくれました。テストの結果を元にAIがロジックを修正できれば良かったのですが（他のケースではそういうこともありました）、AIがテストを書いてくれることで、手軽にテストファーストで開発を進められるのはなかなか体験が良かったです。

:::note info
『電光石火』では、単にAIにコンテンツを実装させるだけでなく、このような細かい調整も行なっています。そのような作業は、まだAI任せでは、僕の実現したいクオリティに届きません。明らかにクオリティコントロールがボトルネックになっているので、開発効率とのトレードオフの取り方を模索中です。
:::

### AIエージェントはチャットAIより賢い

意外なことですが、 **同じモデルを使っていても、ChatGPTのようなチャットでコードを書かせているより、エージェントとして開発させた方がAIは賢くなります。それは、AIが試行錯誤を繰り返し、コードを改善することができるからです。**

僕ら人間でも、コンパイルして初めて型エラーに気付くことはよくあります。これはAIにとっても同じことです。

チャットAIに書かせたコードをエディタに貼り付けたら、型エラーが出てイラッとしたという経験は、多くの人がしているのではないかと思います。しかし、人間と同じように、AIも一度で完璧なコードを書けるわけではありません。コンパイラからのエラーメッセージというフィードバックを受けてコードを修正することで、問題を解決することができます。

さらに、AIエージェントはテストを実行し、問題を発見し、コードを修正することもできます。そのようなフィードバック込みで動作させると、チャットで話していたときには解決できなかった問題を、AIが自分で解決できるようになります。感覚的には、チャットよりもAIが一段も二段も賢くなったように感じられます。

**僕が一番驚いたのは、AIエージェントがprintデバッグを始めたときです。** 単体テストは関数単位で実行されますが、そのとき、AIは関数という粒度のフィードバック（戻り値が想定と異なるという結果）からはロジックのミスを見つけられませんでした。そこで、AIは関数実行中の内部状態を調べるために `print` を仕込み、テストを実行して内部状態を観測し、それによって問題を解決しました。まるで人間の行うデバッグのようです。

このように、チャットAIだけを使っているとAIの実力を見誤りかねません。僕自身、AIエージェントに興味がありながらも長い間手を出さなかった理由の一つは「AIエージェントの能力は結局、基盤となるAIモデルに依存するため、チャットAIの利用経験からその限界は予想できる」と考えていたからです。しかし、実際にAIエージェントを使ってみると、予想していたよりも賢く動作して驚きました。

**まだAIエージェントを使ってソフトウェア開発をしたことがない方は、是非一度体験することをおすすめします。**

### AIエージェントに適したプログラミング言語

ChatGPTなどのチャットAIを用いる際には、PythonやJavaScriptなど、Web上に情報が豊富な言語がAIに適しているように感じられました。しかし、AIエージェントでは事情が異なるように思います。

前述のように、 **AIエージェントにとってフィードバックは重要な手がかりです。静的型付けによって厳密にチェックされる言語の方が、コンパイラのフィードバックを得てエージェントが機能しやすいように思います。**

そんなことを考えていたら、おもしろいポストを見かけました。

https://x.com/mizchi/status/1914654942142587396

『電光石火』を開発する過程では、このようなストレスを感じることはありませんでした。『電光石火』はiOSアプリなのでSwiftで開発しましたが、エラーハンドリングに関するストレスを感じなかったのは **Swiftがエラーハンドリングの必要性を静的型付けするから** ではないかと思います。

Swiftでは、 `throws` が付与された関数を呼び出す際には必ず呼び出し箇所に `try` を付与し、 `catch` するか、呼び出し側の関数にも `throws` を付与しなければなりません。そうでなければコンパイルエラーとなります。逆に、 `throws` が付与されていない関数の呼び出しに `try` を付与したり、 `catch` しようとするとコンパイル時警告となります。

```swift
func foo() throws { ... }

func bar() {  // ⛔️ throwsがなくcatchされていないのでエラー
    foo() // ⛔️ tryがないのでエラー
}
```

```swift
func foo() { ... }

func bar() {
    do {
        try foo() // ⚠️ fooにthrowsが付与されていないのにtryしているので警告
    } catch { // ⚠️ throwsが付与された関数の呼び出しがないのにcatchしているので警告
        ...
    }
}
```

そのようなフィードバックや、呼び出す関数の宣言（ `throws` が付与されているかどうか）から、AIはエラーハンドリングの必要性を判断することができます。そのため、前述のポストで述べられているような問題を起こさなかったのでしょう。SwiftやJavaのような、エラーの可能性の有無が静的型付けされた言語は、エラーハンドリングの観点でAIエージェントに適しているのかもしれません。

僕は10年近くもSwiftのエラーハンドリングに関する言語仕様の素晴らしさを訴えてきましたが（下記）、まさか静的型付けされたエラーがAIに活用される日が来るとは思いませんでした。

https://zenn.dev/koher/articles/three-stories-about-error-handling-in-swift

https://qiita.com/koher/items/a7a12e7e18d2bb7d8c77

<iframe width="560" height="315" src="https://www.youtube.com/embed/YtRra0lVaBA?si=YWqjoe_TEBmXQGNN" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

エラーハンドリング以外の例としては、Swiftコンパイラは並行処理において、データ競合が発生し得るコードを静的に検出し、コンパイルエラーとします。これは新しい仕組みなのでAIの学習が足らず、AIエージェントが問題を上手く解決できないケースも見られます。

https://x.com/koher/status/1895821741966180667

しかし、将来的に学習が進めば、そのような言語仕様もAIエージェントに適したものになるのかもしれません。

:::note info
AIがデータ競合を起こし得るコードを記述するのを防止できたという意味では、たとえAI自身が問題を解決できなくても、AIに適した言語仕様だと言えるかもしれません。
:::

SwiftがAIエージェントに適しているかはもっと評価が必要ですが、 **AIエージェントが上手く機能するかどうかに、言語仕様は意外と大きな影響を与えるのかもしれません。**

### コーディングツールではなくAIとのチーム開発だと考える

ある水準以上のソフトウェアエンジニアであれば、1行1行自分の書いたコードの隅々まで、なぜそのように書いたか、それが最善である理由にこだわりを持っているのではないでしょうか。しかし、AIエージェントを利用する場合、AIの書いたコードにもそれを適用するのは得策ではありません。

AIエージェントを「コーディングを助けるツール」だと考えていると、AIに生成させたコードも自分のコードとして、隅々までこだわりたくなってしまいます。重要なのは、 **AIエージェントをツールではなく、チーム開発のメンバーだと捉えるメンタリティです。チーム開発においてメンバーのコードをレビューするときには、自分が最善だと考えるスタイルを細部まで適用させたりしないと思います。** AIにもそれくらいの温度感で接するのが良いと思います。

繰り返しになりますが、 **AIエージェントを使った開発においてボトルネックは人間です。AIに、自分の考える理想のコードを書かせようとすると、その分だけ生産性が低下します。** 細かなコーディングスタイルのようなところまで修正させていては、AIエージェントを使っている利点を損ねてしまいます。AIに自分の理想を押し付けすぎないことが重要です。

また、指摘すれば次から修正してくれる人間と違って、AIには物事を教え込むことも難しいです。プロンプトに入れることである程度制御はできますが、細部に至るまでコントロールしようとすると手間に見合わないことも多いです。むしろ、AIのスタイルをある程度受け入れて、それに乗っかって開発を進めた方が楽なことが多いように思います。

:::note info
ただし、どこまでAIのスタイルを採用するかは内容によります。Swiftのコードを書かせる場合、Claudeは非同期処理をコールバックで記述しがちです。これは、Swiftの `async/await` が比較的新しい機能であるため、旧来のコールバックによる記述を多く学んでいるからでしょう。

しかし、Claudeは `async/await` についても知っているので、依頼すれば `async/await` ベースで非同期処理を書いてくれます。 `actor` を使ったり、 `withChecked(Throwing)Continuation` を使ってコールバックによるAPIを `async/await` に変換させることもできます。

僕は、今更コールバックを使って非同期処理を書くのは耐えられないので、必ず `async/await` で書かせるようにしています。
:::

一方で、 **要所は人間が押さえる必要があります。**

- セキュリティ
- 計算量やパフォーマンス
- 永続化のためのスキーマ

などは、問題が起こらないように人間がコントロールした方が良いでしょう。

『電光石火』でも、記録を保存するスキーマは後から極力マイグレーションが必要ないように慎重に設計しました。また、パフォーマンス上の問題を引き起こしそうなコンポーネントは最初から分離して自分で実装しました。

これも、 **AIエージェントはジュニアレベルのチームメンバーだというメンタリティで接すれば、自然と要所を押さえられる** のではないでしょうか。どこが重要そうかの判断は、 **ソフトウェアエンジニアとしての経験と勘所が役に立つ** と思います。

なお、僕は **AIを完全に自律的に働かせるのではなく、都度生成されたコードをチェックする形で開発を進めています。そのため、とんでもない爆速で開発を進められるわけではないですが、完全に自分の手でコードを書いた場合と比べて、体感で3〜5倍速くらいに感じます。** コードのメンテナンス性を保てるようにコントロールしながら開発を進めるには、これくらいの使い方がちょうど良いのではないでしょうか。

## 考察

### コミュニケーションコストが高いチームはAIエージェントが真価を発揮しづらい

『電光石火』は僕の個人プロジェクトなので、一人で開発しました。しかし、 **チーム開発、特にコミュニケーションコストが高いチームでは、AIエージェントが有効に機能しづらいのではないかと思います。**

何度も書きますが、 **AIエージェントを使った開発におけるボトルネックは人間です。人間の指示を待つ時間をいかに短くできるかが生産性向上の鍵です。そう考えると、人間同士のコミュニケーションにかかる時間を無視できません。**

例として、デザイナーがアプリのデザイン・レイアウトを考えて、それをエンジニアが実装するようなチームを考えてみましょう。あるとき、与えられたデザイン・レイアウトに基づいてエンジニアが実装をしてみると技術的な問題が発覚しました（たとえば、可変数の要素について、数が多いと現在のデザイン・レイアウトでは機能しないことがわかりました）。そこで、エンジニアは対応策を考えてデザイナーに提案しました。しかし、エンジニアの提案内容はデザイン上許容できず、別の対応策を色々と話し合い、検討しなければいけませんでした。

![デザイナーとエンジニア](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47085/4a112664-25ca-4249-bcc8-da6bca642ccb.jpeg)

このようなコミュニケーションは、AIエージェントの価値を損ねてしまうかもしれません。 **AIエージェントによってコーディングの時間が短縮されるほど、それ以外の部分に要する時間の影響が支配的になります。** コミュニケーションコストが大きなチームでは、AIエージェントによってコーディングが効率化されても、全体に対する影響は限定的になるでしょう。

そう考えると、 **AIに指示を出す作業者自身が判断を下して開発を進められる体制の方が、AIを待たせる時間が減り、AIの利点を活かしやすいように思います。** よりコンパクトでコミュニケーションコストの小さなチームや、作業者が複数のロールを担当し、より多くの決定権を持つようなチームが有利になるかもしれません。

そもそも、AIがない時代から、コミュニケーションコストが大きいチームは望ましくありませんでした。しかし、 **もしAIエージェントによって実作業の効率が飛躍的に高まった場合、コミュニケーションコストの小さなチームと大きなチームで圧倒的な生産性の差が生まれるかもしれません。そうなると、もはやコミュニケーションコストの大きなチームは、抜本的な開発体制の見直しを必要とされるでしょう。**

### AIの特性を考慮してアプリの仕様を検討する

今回、『電光石火』を開発してみて感じたのは、 **AIエージェントをフル活用するためには仕様レベルからAIの特性を考慮することが重要** だということです。

AIのスピードは圧倒的です。これまでの常識では考えられないほどの速度で開発を進めることができます。一方で、現時点ではAIにできること・できないことがあり、AIに苦手なことをやらせようとしてもうまくいきません。

そう考えると、AとBの二つの仕様のどちらを採用するか決定する際に、Aが90点、Bが85点だったとしても、AだとAIで開発しづらく、Bだと一瞬で実装できる場合には、Bを採用するような局面が増えてくるかもしれません。

**古の時代から、DXにおいて重要なのは、業務に合わせてシステムを作るのではなく、システムに合わせて業務フローを見直すことだと言われてきました。似たようなことがAIについても言えるのではないでしょうか。仕様に合わせてAIに作らせるのではなく、AIが作りやすいように仕様を調整することが求められるようになるかもしれません。**

AIエージェントの活用に圧倒的な経済的合理性があれば、それに適応できない組織は競争力を保てません。もしそのような生産性の差が生まれるのであれば、どのようなプロダクトを作るか考える段階から、AIエージェントで開発しやすいかを考慮する必要に迫られるでしょう。

**『電光石火』では考え方を逆転させ、AIエージェントの活用を前提にどのようなプロダクトを作るかを考えました。『電光石火』が効率的に開発できたのは、AIエージェントを前提としてプロダクトを考えたからという面も大きいと思います。**

これまではリリースと本記事の執筆を優先していたので、『電光石火』へのコンテンツ追加にあまり力を入れてきませんでした。しかし、 **このGWには休日を活用して大量のコンテンツを追加開発しようと考えています。共通の仕組みの上でAIにコンテンツを開発させるのは、これまでにも増して効率が良いはずです。従来であれば数百万〜2・3千万円規模の見積もりとなるアプリを、個人がたった数日で開発できるかもしれません。**

:::note info
なお、『電光石火』のリリースまでにClaudeのAPI利用料として費やした金額は$200程度です。安くはないですが、人間（僕）の稼働コストの方がずっと高いので、そちらを節約できるのであれば十分にペイすると考えています。
:::

ただ、AIが作りやすいものを作っても、それはすぐにレッドオーシャンとなり、結局は人間にしかできないことにこそ価値が生まれるかもしれません。しかし、AIのできることがどんどん拡大していくなら、人間にしかできなかったことが、ある日突然無価値になる可能性もあります。AIができる最前線を意識し、常にそれを取り入れていくことが重要なのではないかと思います。

:::note info
AIが急速に進化し続けた場合、そのようなキャッチアップにもあまり意味がないかもしれません。

Anthropicが米政府機関に対して3月に行った提言の中[^5]で、2026年末から2027年初頭にかけて、AIの能力は次のような水準に達すると述べています。

- ほとんどの分野において、知的水準でノーベル賞受賞者に匹敵するか超える
- 数週間に渡るような長期的かつ複雑なタスクを自律的にこなす
- ロボットなどを活用し、物理的に現実世界で作業を行う

[^5]: "Anthropic’s Recommendations to OSTP for the U.S. AI Action Plan": https://www.anthropic.com/news/anthropic-s-recommendations-ostp-u-s-ai-action-plan

もはや、このようなことが可能になった場合、ありとあらゆる分野でAIが作業を行うようになり、人間が必要とされるタスクは限定的になるかもしれません。

2年後にそのようなレベルに到達するというのはやや過激な意見かもしれませんが（それでも可能性はあると思いますが）、10年というスパンで見ればかなりの（50%以上の）確率で実現されるのではないでしょうか。
:::

### AIエージェントを上手く活用するには試行錯誤が必要

AIエージェントによるソフトウェア開発がすごいらしいと聞いて、漫然と使ってみても上手く行かないことが多いのではないでしょうか。 **AIエージェントが得意なこと・苦手なことを把握し、どのような使い方であれば機能しそうかを考え、試行錯誤することが重要だと思います。**

本記事で述べたような事柄（AIに雑に書かせてから人間が抽象化してメンテナンス性を保つ、AIに適した内容を取り扱うなど）は、そのような試行錯誤のヒントになるのではないでしょうか。どのような道具もそうですが、上手い使い方をしなければ上手く機能しません。AIエージェントに大きな可能性がある以上、自分の環境に適した使い方を模索する価値はあると思います。

## まとめ（再掲）

- AIエージェントを使うと体感で3〜5倍速くらいで開発できた
- AIのコストは低いので、まずAIに書かせてみて、ダメだったら人間が作業をする
- メンテ不能にならないように適宜人間が手をいれる必要がある
- まずAIにコードを書かせてから、人間が共通化・抽象化の設計をする
- 一度できた設計に沿ってAIに開発させるのは簡単
- AIエージェントとテストファーストは相性が良い
- 同じモデルでも、チャットAIよりAIエージェントの方が賢くなる
- AIエージェントに適した言語・適さない言語がありそう
- コーディングツールというよりも、AIとのチーム開発だと考える
- コミュニケーションコストの高いチームではAIエージェントを活かしきれなそう
- AIの特性を考慮してアプリの仕様を検討すると良さそう
- 漫然と使うのではなく、AIエージェントが機能する方法を試行錯誤する