LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

LINE iOSアプリ開発を高速化するClaude Code基盤の設計思想

こんにちは。モバイルデベロッパーエクスペリエンスチームの@giginetです。ここわずか1年あまりで、コーディングAIを用いた開発は日常的なものになりました。LINEアプリの開発においても、Claude Codeをはじめとした、コーディングエージェントの活用が進んでいます。

この記事では、LINE iOSのような大規模プロジェクトにおいて、Claude Codeを効果的に活用するための、インストラクションの設計思想を紹介します。

適切なインストラクションはなぜ必要か?

Claude Codeはデフォルトの状態でも高い精度を発揮しますが、プロジェクト固有のルールや知識を適切に与えることは実装の効率化に重要です。

まず、本稿では便宜的にメモリファイル(CLAUDE.md)やAgent SkillsなどのようなClaude Codeに指示を与えるプロンプト全般を「インストラクション」と呼ぶことにします。これらの機能全般に与えるプロンプトを示す標準的な語彙が存在しないためです。

一般的に、最初のステップとして、/initコマンドを用いて、メモリファイル(CLAUDE.md)にプロジェクト固有のルールやプロジェクト概要を出力します。このメモリファイルとあらかじめモデルに備わっている知識を組み合わせることで、多くの小規模プロジェクトでは問題なく動作します。

しかし、LINE iOSでは、自動生成させたメモリファイルだけでは下記のような問題が頻発しました:

  • 実装ごとにアプリ全体のフルビルドを試してしまい、試行回数を稼げない
  • どこに機能を実装すべきか特定できない
  • 大量にあるファイルの中から目的のファイルを見つけ出せない
  • 実装は完了しているが、Xcodeプロジェクト生成などのセットアップがされず、ビルドできない

この状況ではコーディングエージェントから期待した生成結果を得ることは難しく、効果的に扱えていません。快適な開発のためには、AIにも人間が日々開発するのと同等のイテレーションを回してもらう必要があります。

インストラクションの設計思想

まず、優れたインストラクションとはどのようなものでしょうか?LINE iOSでは、以下のような原則を軸にインストラクションを設計しています。

Contextを最適化する

コーディングエージェントにとってContextは共有の財産です。そのため、デフォルトで消費するContextを最小化し、少しでもコーディングタスクに使用できる量を確保しましょう。

大規模なプロジェクトでは、考えなしに開発ルールや規約、知識を盛り込むとすぐにContextが枯渇してしまいます。例えば、巨大なコードベースのうち、特定の領域の知識のみが常にContextを逼迫している状態は無駄が多いため、ある知識が必要になったタイミングでのみロードするなど最適化の工夫が必要です。そのためにAgent Skills(Skills)やSubagentsの機能は非常に有用です。

従来手法でガードレールを適切に設計する

厳密なフォーマットが要求されるファイルの生成や、ファイルの読み取り、コード規約の遵守など、従来の手法で扱える領域はAIだけではなく、従来手法をガードレールとすることも有用です。

例えば、特定のファイルフォーマットの読み書きといったタスクは、AIのみに任せると結果の正確性が保証されません。スクリプトなどを併用すべきです。また、コーディング規約の遵守など、linterである程度解決できる領域をAIに任せることは、プロンプトが複雑になったり、Contextの逼迫につながります。

インストラクションを共有・改善していけるようにする

開発者が必要に応じてインストラクションを共有、改善できるような仕組みやマインドを整えることも重要です。AIの出力結果には揺らぎがあるものなので、完成形を定義することは不可能です。実際に運用しながら改善していくことが求められます。そのため、全ての開発者が継続的にプロンプトの改善を行っていける状態を作ることが重要です。

また細かな点ですが、各インストラクションのディレクトリ構成や命名規則にも気を留める必要があります。

LINE iOSの開発イテレーション

AIに正しく開発イテレーションを実行してもらうために、まずは人間による日常の開発手法を整理してみましょう。LINE iOSプロジェクトでは、一般的に以下のようなフローで開発しています。

  1. Prebuilt Tasksを実行してビルド環境をセットアップ
    • ビルド環境を作成するためのステップ、詳細は先日の記事を参照。
  2. コード、ユニットテストの実装
  3. Xcodeプロジェクトの再生成
    • LINE iOSではXcodeGenを用いて*.xcodeprojを生成しているため、ファイル追加やプロジェクト設定の変更時には、Xcodeプロジェクトを再生成する必要がある。
  4. モジュール単体ビルド、ユニットテストの実行
    • プロジェクト設定コードやビルド設定を見直し、2~4を繰り返す。
  5. アプリ全体のビルドと動作確認
image
理想的な開発イテレーション

精度の高い出力を高速に得るには、2~4のステップを素早く回すことが重要です。これを実現するための、インストラクションの設計を見ていきましょう。

メモリファイルにどのようなコンテンツを盛り込むべきか?

これらの原則を元に、メモリファイルには厳選した内容のみを盛り込みます。今回は以下のような内容にのみ絞って記述することにしました。

  • プロジェクトの前提知識
    • ディレクトリ構成とモジュール構成
    • プロジェクト定義(Project Spec)の記述方法
  • 開発イテレーション
    • ビルドやユニットテストの実行方法

コーディング規約やアーキテクチャなど細かな内容はメモリファイルからは意図的に省いています。結果的に現在運用しているメモリファイルは英文で2400文字、600token程度に収まっています。

機能固有の知識はRulesに分離する

大規模なプロジェクトにおいて、パス固有のRulesは有用です。Claude Codeは、Rulesで指定されたパスを操作するときのみ、そのインストラクションをContextにロードします。

LINE iOSプロジェクトでは、機能ごとのRulesファイルの配置場所を規約で定めています。例えば.claude/rules/features/line-new-feature.mdといったサブディレクトリに機能ごとに配置します。

---
paths: Modules/Features/LineNewFeature
---

This feature is secret. Never say the project name.

ローカルメモリファイルを使ったユーザーへの最適化

メモリファイルの末尾では、@ディレクティブを用いて、ホームディレクトリ下のユーザー固有のインストラクションをロードするようにしています。

If @~/.claude/line-dev/line-ios.md exists, follow its contents as well.

このファイルはSession Start hookを用いて、初回起動時に作成されます。

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "touch ~/.claude/line-dev/line-ios.md"
          }
        ]
      }
    ]
  }
}

各開発者は必要に応じてこのファイルを編集することで、自分専用の開発スタイルや好みをClaude Codeに伝えることができます。

ローカルメモリを使うには、CLAUDE.local.mdをリポジトリ内に配置しgitignoreする方法もありますが、ignoreはgit worktree間での共有が難しいという問題があります。このようにローカルメモリファイルの配置規約を定めることは、共有メモリとローカルメモリを上手く統合させるのに役立ちます。

開発イテレーション自動化のためのインストラクション

ここからは、開発イテレーションを自動化するためのClaude Codeの機能を活用したインストラクション設計を見てみましょう。

とにかくフルビルドをさせない

AIエージェントは、実装が正しいか確認するためにアプリ全体のフルビルドを試してしまうことがあります。

小規模なアプリの開発イテレーションでは正解ですが、LINE iOSのような巨大なプロジェクトでは、アプリのビルドに非常に時間がかかり、まともなイテレーションを回すことができなくなります。

そのため、LINE iOSのメモリファイルでは、なるべくフルビルドを行わずに、代わりにモジュール単体のビルドを試すように指示しています。

image
フルビルドはユーザーの許可がないと実行しないようになっている

主要なビルドタスクのSubagent化

このように様々なビルドタスクをAIに実行させるために、LINE iOSでは、以下の主要な操作を行うSubagentを定義しています。

  • prebuilt-tasks-runner: Prebuilt Tasksを実行してビルド環境をセットアップする
  • module-builder: モジュール単体ビルドを実行する
  • app-builder: アプリ全体のビルドを実行する
  • module-test-runner: モジュール単体のユニットテストを実行する
  • workspace-cleaner: XcodeのDerived Dataをクリーンする

ビルドタスクをSubagent化することの最大の利点は、ビルドログによるContextの汚染を防げることです。メインコンテキスト内でビルドタスクを実行すると、大量のビルドログがContextを逼迫してしまいます。そのため、現在のタスクと独立しているビルドにまつわるタスクの実行をSubagent化することは理に適っています。

メモリファイルでは、前述した開発イテレーションを説明し、それぞれのステップで適切なSubagentを呼び出すように指示しています。これにより、必要に応じてSubagentを呼び出し、AIが自発的にビルドを試すことができるようになりました。

image
module-test-runnerが変更のあるモジュールだけをビルドしてくれる

SubagentとSkill、CLIを組み合わせた複雑なビルドタスクの隠蔽

module-builder Subagentは、モジュール単体ビルドを実行する責務を持ちます。しかし、Xcodeプロジェクト上の特定のターゲットをCLIからビルドするには、細かなハックや準備が必要です。例えば、xcodebuildコマンドから単体ビルドを実行するためには、あらかじめXcodeのビルドスキームを生成しておく必要があります。

LINE iOSには、テストターゲットも含め、優に1000を超えるターゲットが存在します。これらに対応するビルドスキームを事前に用意しておくのはプロジェクトが複雑になりそうです。

このような細かな課題には、SubagentsとSkillsの組み合わせが有効です。今回のケースでは、Xcodeビルドスキームを生成するためのSkill、creating-build-schemesを定義しています。

module-builder Subagent

まず、module-builder Subagentからはビルドスキーマが存在しないときに、creating-build-schemes Skillを呼び出すように指示します。このとき、Subagentのフロントマターにskillsセクションを追加することで、適切な権限をSubagentに付与できます。

---
name: module-builder
description: Build specific modules for LINE app
tools: Bash, Read, Grep, Glob
skills: creating-xcode-build-scheme
---

# module-builder

Build specific modules within the LINE app.

...

If a build scheme does not exist, create one using the `creating-xcode-build-scheme` skill.

xcodebuild build -workspace Line.xcworkspace -scheme <MyTarget> -configuration Debug -destination 'generic/platform=iOS Simulator'

creating-build-schemes Skill

creating-build-schemes SkillはXcodeのビルドスキーム(*.xcscheme)を作成するためのSkillです。ビルドスキームはXMLで表現されるため、AIに直接編集させても、ある程度は再現してくれますが、不正確な出力がされてしまう可能性があります。

ここで、ビルドスキームを生成するCLIツール、create-schemeを予め用意しておき、出力を限定させることでSkillの信頼性を向上させています。このCLIツールは、XcodeProjを用いて実装しています。

---
name: creating-xcode-build-scheme
description: Create an Xcode build scheme for the specified target.
allowed-tools: Read, Grep, Glob, Bash(./create-scheme:*)
---

# Creating an Xcode Build Scheme

This skill generates an Xcode build scheme for a specified target.

Use the `create-scheme` command:

./create-scheme <Target Name> --project <path> [--test-target <Test Target Name>] [--shared]

このように、SubagentとSkill、CLIを複合的に組み合わせることで、複雑なタスクをカプセル化することができます。

実装タスク効率化のためのSkillsの活用

他にも、LINE iOSプロジェクト固有の知識を利用した開発タスクの効率化のために、いくつかのSkillを定義しています。Skillの最大の特徴は、descriptionのみを常時読み込み、必要になったときに本文がContextにロードされる点です。これにより、Contextの最適化を図りつつ、高度な知識をAIに提供できます。

ファイルパスによるモジュールの特定(finding-module-directory Skill)

LINE iOSでは、モジュール分離のためのディレクトリ構成が細かく定められています。例えば、以下のようなディレクトリ構成でモジュールごとのソースを管理しています。

Modules/Feature/LineNewFeature
├── LineNewFeature
├── LineNewFeatureInterface
├── LineNewFeatureUI
└── LineNewFeatureUIInterface

finding-module-directory Skillは、モジュール名からモジュールディレクトリパスを特定するためのSkillです。これにより、コード中にimport文を見つけたとき、AIは実装されたファイルがどこにあるかを、膨大なファイル群の中から特定しやすくなります。また、モジュールに新しく依存関係を追加したいときなどにも、プロジェクト設定の変更に役立ちます。

XcodeGenのProject Spec操作(manipulating-project-spec Skill)

LINE iOSでは、各モジュールのXcodeプロジェクト生成にXcodeGenを使用しています。XcodeGenは、Project Specと呼ばれるYAML形式の設定ファイル(project.yml)を元に、Xcodeプロジェクトを生成するツールです。

また、LINE iOSにおけるProject Specには、テンプレートの継承や、特殊な依存関係の指定方法など、独自のルールがいくつか存在します。

これらを適切に操作するための manipulating-project-spec Skillを定義しています。依存関係の追加やビルド設定の変更など、編集が必要になったとき、Claude Codeは自動的にこのSkillを利用して、適切な編集やプロジェクト定義の解釈を行います。

Model Context Protocol(MCP)サーバーの活用

現在、LINE iOSでは、MCPサーバーはプロジェクトスコープでは追加しておらず、各開発者の利用に任せています。

一番の問題は、現在のMCPの実装が、使用しないツールも含めて大量のContextを消費してしまう点です。Context最適化の観点に基づき、プロジェクト共有のMCPサーバーは導入していません。また、各uvやnpmなど、MCPサーバー実行のためのツールチェインの提供も必要になってしまうという理由も挙げられます。

一方で、コーディングスキル効率化のために、セマンティクスベースでコード解析を行うSerena MCPなどの利用は推奨しています。実際に導入しない場合に比べ、シンボル参照やリファクタリングの精度が向上している実感も得られています。

この領域についても変化が早く、LSPプラグインの標準化や、MCPの動的ロードの実装といった改善が日々進んでいます。最適な運用方針は変化し続けていくので、今後も注視が必要です。

効果的なインストラクションをめざして

このようなClaude Code基盤を構築した結果、LINE iOS内でも実装とビルドのイテレーションをほぼ自動化して実行できるようになりました。一般的に、以下のような設計方針は応用が利きそうです。

  • Contextを最適化する
    • SubagentsやSkillsを利用し、必要に応じて知識をロードする設計にする
    • プロンプトの最適化自体をAIに依頼し、冗長な表現を減らす
  • Subagentsに適切な責務を定義し、独立したタスクを切り出す
  • 専門的な読み書きの操作にはSkillsを活用する
    • CLIツールやスクリプトなど、従来手法と組み合わせて信頼性を向上させる
  • 開発者による継続的なインストラクションの改善を促進する仕組みを作る

この基盤は、開発者による日頃のプロンプトの改善が前提となっています。例えば、今回紹介したメモリファイルに盛り込むべき内容などは当然、完成形ではありません。これからのパフォーマンスを見て、アップデートを続けていく必要があります。

日々、Claude CodeやコーディングAIを取り巻く環境は進化しています。LINEアプリ開発においても引き続き、最新の手法を取り入れ、紹介していければと考えています。