🤖

AI時代のモバイル開発 - コーディングエージェントが本気を出せる環境作り

に公開

はじめに

こんにちは、iOSエンジニアの長です。

現在、ウェルスナビのモバイルアプリ開発では、コーディングエージェントを活用しています。
この記事では、AI時代におけるモバイル開発の新たな挑戦と、コーディングエージェントが最大限に力を発揮できる環境作りについて共有します。

1. エージェント導入前の状況

コーディングエージェント(以下、エージェント)は大変便利です。
一方で、既存の開発環境が「エージェント向き」ではないと、良さが出にくいと感じました。
私たちの開発で影響が大きかったのは、次の3点です。

巨大で複雑なコードベース

アプリは長年の開発の積み重ねで、大規模で複雑なコードベースになっています。
特に、iOSアプリのビルドは、環境やプロジェクト構成により時間を要していました。

エージェントは提案と検証を何度も繰り返すため、ビルドが重いとフィードバックループが伸びます。
結果として、自律的に進める強みを活かしにくい環境でした。

設計方針と規約が暗黙知になりやすい

既存の実装には暗黙の前提が多く、設計方針や命名規則も追従が難しいです。

人間は経験で補えますが、エージェントは前提が不足すると迷いやすくなります。
そのため、生成後の修正が必要な場面が多くありました。

機能開発に仕様書更新を追従させるのが困難

ウェルスナビでは2週間サイクルでアプリをリリースしています。
そのため、頻繁な仕様変更を追い続ける必要があります。

開発中はドキュメント更新が後回しになりやすく、仕様の正確性や最新性が揺らぐことがありました。
仕様が曖昧だと、エージェントの提案の精度やテスト設計にも影響が出ます。

2. ただ導入するだけでは解決しなかった

最初は、汎用のエージェントをそのまま利用しました。
しかし、次のような点で「期待より伸びない」状態になりました。

  • 設計方針や規約の前提が不足し、修正の往復が増える
  • 仕様や画面の情報が曖昧で、意図とずれた提案が出る
  • ビルドが重く、検証が進まずに作業が止まりやすい

特に、ビルドの待ち時間は影響が大きく、
エージェントが自律的に進めようとしても、検証で止まってしまう状況が続きました。

人間の作業でも負担なので、ここは先に整える必要がありました。

3. エージェントが最大限に力を発揮できる環境作り3選

エージェントに期待するのは、「速く進む」だけではありません。
プロダクトの前提に沿って、安全に前へ進むことです。
そのために効いた施策を3つ紹介します。

3.1 カスタムエージェントに設計と規約を渡す

汎用のエージェントは、プロジェクト固有の前提を知りません。
そこで、GitHub Copilot Agentのカスタムエージェント機能を使い、モバイル開発向けの前提を明文化しました。
以下はiOSアプリ向けカスタムエージェント定義の一部抜粋です。

# GitHub Copilot iOSアプリカスタムエージェント定義

(省略)

## アーキテクチャ

### 基本設計パターン

- **Coordinator パターン**: 画面遷移の制御
- **ViewStore パターン**: 独自の Unidirectional Data Flow
  - `ViewState<Content, Failure>`: 4つの状態(idle, loading, completed, failed)を持つ
  - `ViewCommand`: View から Store への命令(命令形で命名: `fetchData`, `toggleFlag`
  - `ViewAction`: Store から View への通知(過去分詞形で命名: `fetched`
  - `ViewEffect`: 揮発するUIイベント(命令形で命名: `presentError`
- **Stateful プロトコル**: イミュータブルな状態更新

### プロジェクト構造

app/
├── Scene/           # 画面関連(ViewStore, View, ViewController)
├── Domain/          # ドメインロジック(Repository)
├── Data/            # データ層(API, DataSource)
├── Service/         # サービス層
├── UIComponent/     # 再利用可能なUIコンポーネント
├── Utility/         # ユーティリティ
├── Resource/        # リソース(Assets, Config)
└── Coordinator.swift # 画面遷移の制御

(省略)

アプリの設計パターンとプロジェクト構造を、エージェントに明示します。
ここでのCoordinatorパターンは、画面遷移の責務を分離する設計です。
ViewStoreパターンは、画面状態と操作を一方向に流す構成を指します。

この前提があると、生成物の方向性が揃いやすくなります。
結果として、アプリアーキテクチャに沿った提案が増え、手戻りが減りました。

なお、ウェルスナビアプリの独自アーキテクチャについては、以下の記事で詳しく解説しています。是非ご覧ください。
https://zenn.dev/wn_engineering/articles/1a105882a63b2f

# GitHub Copilot iOSアプリカスタムエージェント定義

(省略)

## コーディング規約

(省略)

### 命名規則

#### ViewStore パターン

- **State**: 状態を表す構造体(例: `DebugViewState`, `HomeOpeningViewState`
- **Command**: 命令形(動詞 + 目的語)
  -`fetchPortfolioData`, `toggleDenomination`, `changeGraphTerm`
  -`portfolioDataFetched`, `denominationToggled`
- **Action**: 過去分詞形(目的語 + 動詞の過去分詞)
  -`portfolioDataFetched`, `denominationToggled`, `graphTermChanged`
  -`fetchPortfolioData`, `toggleDenomination`, `changeGraphTerm`
- **Effect**: 命令形(動詞 + 目的語)
  -`presentAlert`, `triggerNavigation`
  -`alertPresented`, `navigationTriggered`, `dataLoaded`
- **ViewStore プロトコル**: `<画面名>ViewStore`
- **ViewStore 実装クラス**: `<画面名>ViewStoreImpl`
- **Mock**: `Mock<画面名>ViewStore`

(省略)

## 開発ガイドライン

### SwiftUI 実装時

1. `ViewStore` プロトコルを継承
2. `@Published``state` を公開
3. `effect``AsyncStream<Effect>` で定義
4. `dispatchCommand` で非同期処理
5. Preview 用に `Mock<画面名>ViewStore` を実装

### UIKit から SwiftUI への移行

- `UIHostingController` でラップ
- Coordinator パターンは維持
- 既存の ViewStore を SwiftUI 対応に拡張

### 非同期処理

- **Swift Concurrency** (`async/await`) を優先
- RxSwift は既存コードの保守に限定
  - SwiftUI実装時には使用しない
- `@MainActor` を適切に使用
- `Sendable` プロトコルへの準拠

(省略)

続いて、コーディング規約と開発ガイドラインも定義しました。
これにより、ルールに沿った命名や実装が増え、生成されたコードの一貫性が向上しました。

3.2 ビルドのボトルネックを減らす

前述の通り、コードベースは大規模で複雑です。
そのため、エージェントが提案を検証するたびにビルド待ちが発生します。

そこで、特にビルドに時間を要しているiOSアプリのコードベースを分割し、ビルド時間を短縮できるように最適化を進めています(下図参照)。

  • Feature: アプリの主要機能ごとに分割
  • Core: アプリの基盤となる共通機能
  • DesignSystem: UIコンポーネントやテキストスタイルなど
  • Shared: 自社で開発しているアプリ向けの共通ライブラリ

コードベースの分割を進めていくことで、ビルド時間の短縮が期待できます。
結果として、エージェントの検証サイクルを短くできます。

3.3 仕様と確認観点を一元化し、前提を揃える

記事の冒頭で述べた通り、アプリは2週間サイクルでリリースされます。
そのため、仕様変更が頻繁に発生します。

一方で、リリースが近づくほど実装や不具合対応が優先されやすく、仕様や確認観点の更新は後回しになりがちです。
また、仕様と確認観点の更新場所が分散していると「どこを直せば最新になるか」が曖昧になり、更新漏れも起きやすくなります。

エージェントにやってほしいのは「実装」だけではなく、「仕様に沿っているかどうかの検証」まで含めて安全に前へ進むことです。
そのためには、画面や制約などの前提情報を含む仕様と、開発者テストで使う確認観点がどちらも最新で揃っている必要があります。
※ 開発者テスト: 開発者が実装に対して行う動作確認のこと

ところが、仕様変更が頻繁な状況で、仕様と確認観点が別々に管理されていると更新が後手に回りやすく、次のような問題が連鎖します。

  • 仕様が古いままだと、エージェントに渡す仕様も古くなり、提案がズレる
  • 確認観点が古いままだと、毎回作り直すことになり、動作確認が遅くなる
  • どちらか一方だけ更新しても、もう一方が追従していないと「仕様と確認観点が揃わない」ため、結局ズレが残る

そこで私たちは、「仕様更新が後手に回る」ことと「動作確認が非効率になる」ことを同じ根、つまり仕様と確認観点の同期ができていないこととして捉え、以下の施策を実施しました。

  • 仕様と確認観点を一元管理
    • 機能や画面ごとに仕様と確認観点を紐付けて管理する
    • 仕様変更時に"同じ場所で"確認観点も更新できるようにする
    • 既存の確認観点を再利用しつつ、差分に応じて追加・修正する
  • 仕様変更の開発プロセスへの組み込み
    • 仕様変更がプロセスから抜けないように、リリース後のアプリ仕様更新を必須化する

これにより、仕様変更に合わせて確認観点も更新されやすくなり、最新の仕様に基づく動作確認がしやすくなりました。
また、エージェントへのプロンプトに「仕様」と「確認観点」をセットで含めやすくなり、意図に沿った提案・テスト設計が出やすくなることも期待できます。

4. カスタムエージェント導入後の状況

カスタムエージェントと環境整備を進めた結果、次の変化がありました。

  • 設計方針と命名に沿った提案が増え、手戻りが減る
  • 変更の意図と検証がセットになり、安心して任せられる範囲が広がる
  • 仕様と確認観点が一致し、意図に沿った提案が増える

ただし、環境整備は一度で終わりません。
運用の中で前提が変わるので、エージェント定義や周辺の仕組みも更新が必要だと感じています。

さいごに

AI時代のモバイル開発では、エージェントに適切な前提を渡すことが重要だと考えています。
そのためには、設計方針や規約の明文化、ビルド時間の最適化、仕様とテストの一元管理が効果的でした。

今後も、開発の実態に合わせた環境作りを続けていきます。

WealthNavi Engineering Blog

Discussion