Claude Code でLINEミニアプリを開発してみた - 実践から学んだポイント

Claude Code でLINEミニアプリを開発してみた - 実践から学んだポイント

2025.11.04

はじめに

こんにちは。アノテーションの及川です。

今回、Claude Code(Claude Sonnet 4.5)を活用して LINE ミニアプリを作成する機会がありましたので、実装からテスト、レビューまで全てを Claude Code との対話で進めた経験を共有したいと思います。

この記事で紹介すること

  • Claude Code を使った実践的な開発手法の一例
  • 15,000行規模のプロジェクトでの具体的な対話テクニック
  • 注意すべきポイントと課題

今回作成したもの

今回作成したのは、LIFF (LINE Front-end Framework) を使用したサーバーレス TODO アプリケーションです。

TODOアプリケーション

スクリーンショット_2025-11-01_14_49_21

AWS 構成図

スクリーンショット 2025-11-01 12.51.21

TODOアプリケーションの特徴

  • モノレポ構成: npm workspaces を使用した3つのワークスペース(web、server、infra)
  • サーバーレス: AWS Lambda + API Gateway + DynamoDB によるスケーラブルなアーキテクチャ
  • LINE統合: LIFF SDK による LINE 認証
  • 型安全性: TypeScript strict mode + OpenAPI 定義
  • セキュリティ: AWS WAF、CloudFront セキュリティヘッダー
  • CI/CD: GitHub Actions による自動テスト・ビルド・デプロイ(OIDC 認証)

Claude Codeとの対話で意識したこと

Claude Code を最大限活用して、機能・非機能要件を満たしつつ、可読性や保守性に優れた実装を担保するため、実際に気をつけた点を紹介します。

1. ステップバイステップで依頼する

多くの情報を一度に詰め込むと、以前に指示した内容や注意すること(例:実装方針が固まるまで勝手に実装しないように等)を忘れてしまうことがありました。そのため、作業を細かく分割して依頼することを心がけました。

実際の依頼例

  • 「バックエンドのDDDにおけるドメインの定義からお願いします」
  • 「DDDのユースケースの実装に沿ったテストコードの作成をお願いします」
  • 「TodoRepositoryインターフェースの実装をDynamoDBで行ってください」
  • 「OpenAPI定義に基づいたExpressのルーティングを設定してください」

基本的に1つの作業に絞って依頼することで、思わぬ方向への脱線を最小限に抑えられました。特にDDDのような複雑なアーキテクチャを実装する際は、ドメイン層→ユースケース層→インフラ層と順を追って進めることが重要でした。

2. まず現状を学習させてから依頼する

プロンプトを入力する際、いきなり依頼内容を書くのではなく、まず現状を理解してもらうことが重要でした。

  • 現在のソースコード(実装状況)
  • 画面のスクリーンショット
  • エラーログや実行結果
  • OpenAPI定義ファイル

例えば、新しい API エンドポイントを追加する際は、既存のエンドポイント実装を見せてから「同じパターンで○○機能を実装してください」と依頼することで、一貫性のあるコードが生成されました。

3. コンテキストを積極的に活用する

依頼内容が複雑になる場合は、別ファイル(マークダウン等)を用意して整理しました。

  • プロンプトには簡潔な依頼内容
  • マークダウンファイルには補足情報や詳細な要件

上記は面倒に感じる部分かもしれませんが、この手間を惜しまないことで、Claude Code が脱線せず、求める結果に近づけることができるものと実際に利用していて感じました。

実際に活用したコンテキスト例

  • liff-todo-app-openapi.yaml - API仕様
  • CLAUDE.md - プロジェクト全体のガイダンス
  • web/CLAUDE.md - フロントエンド固有のガイダンス
  • server/CLAUDE.md - バックエンド固有のガイダンス
  • infra/CLAUDE.md - インフラ固有のガイダンス

各ワークスペースごとにCLAUDE.mdを用意したことで、Claude Code が各層の責務を正しく理解し、適切な実装計画を提案してくれました。

4. メモリファイル(CLAUDE.md)を定期的にアップデート

/init コマンドで最初に作成したメモリファイルを、そのまま放置しないことが大切です。

以下のタイミングで定期的にアップデートしました。

  • 機能実装が完了した段階
  • アーキテクチャの変更があった段階
  • 新しいワークスペースを追加した段階
  • 重要な設計判断を行った段階

これらにより、Claude Code の状況把握の精度が明らかに向上しました。特にモノレポ構成では、各ワークスペースの役割と依存関係を明確に記録しておくことが重要だと思いました。

5. Plan mode で事前確認

本実装に入る前に、Plan mode を活用して実装案や修正案を確認しました。

実際の活用例

  • 「DynamoDBの単一テーブル設計について、GSIの設計案を提示してください」
  • 「AWS WAFのルール設定について、セキュリティとコストのバランスを考慮した案を提示してください」
  • 「CI/CDパイプラインの構成について、環境別デプロイの実装案を提示してください」

回答内容に不満がある場合は、何が不満なのかを具体的に言語化して伝えることが重要です。言語化が難しい場合は、別のセッションで Claude Code等の生成AI関連のツールに相談して整理してもらうのも一つの手です。

6. セカンドオピニオンの活用

Claude Code のセッションで得た回答の妥当性を、別のセッションを立ち上げて確認することも行いました。

例えば、以下のような観点で納得がいくまで確認しました。

  • なぜこのアーキテクチャが必要なのか?
  • 他のアプローチは考えられないか?
  • セキュリティ上の懸念はないか?
  • パフォーマンスへの影響は?
  • 保守性、可読性は高いか?

特にセキュリティ観点では、以下のような確認を行いました。

  • AWS WAF のルール設定の妥当性
  • CloudFront のセキュリティヘッダー設定
  • LINE 認証トークンの検証ロジック
  • DynamoDB のアクセス制御

AIの回答の良し悪しを判断するには、私たち人間側の知識や経験も重要です。Claude Code をコード理解のために活用することも非常に有効だと感じています。

実装時に気をつけたこと

既存機能への影響を最小限にする

実装途中で既に動作している機能に影響を与えないよう、常に意識しました。新機能追加時も、既存のテストが Pass することを確認してから次のステップに進みました。

  • ユニットテストのカバレッジを80%以上に維持
  • E2Eテスト(Playwright)で主要フローを保護
  • 統合テストで各層の連携を確認

必要最小限の構成

コスト面でも構成面でも、必要最小限を心がけました。

  • DynamoDBをオンデマンドキャパシティに設定
  • 不要なログ出力を削減(CloudWatch Logs、AWS WAF)等

過剰な実装は避け、本当に必要な機能だけを実装することで、保守性の高いコードベースを維持しました。

作業の記録を残す

作業の途中や切りが悪いタイミングでエディタや PC を閉じる際は、そのまま閉じるのではなく、以下を Claude Code に記録させました。

  • どこまで実施したか
  • 次はどこからスタートするか
  • 未解決の課題は何か
  • 次回確認すべき事項

特にモノレポ構成では、どのワークスペースのどの機能を実装中だったかを明確にしておくことが重要だと思いますので、これらにより、次回の作業開始時には、スムーズに再開できました。

Claude Codeに依頼したこと

コードの作成とテスト(例)

  • Reactコンポーネント(Toast、Modal、Layout等)
  • カスタムフック(useTodos、useLiff等)
  • React Hook Form + Zodによるフォームバリデーション
  • レイヤードアーキテクチャ(Domain、UseCase、Infrastructure、Controller)
  • InversifyJSによるDI設定
  • OpenAPI定義に基づいたバリデーション
  • AWS CDKスタック(API Gateway、Lambda、DynamoDB、S3、CloudFront等)

コードレビュー

  • フロントエンドからバックエンド間の処理の流れの確認
  • 実装範囲の把握(なぜ?、どうして?)
  • セキュリティ観点
  • パフォーマンス観点

アーキテクチャ設計

  • DDDに基づいたドメイン設計例(抜粋)
TODOクラス
export class Todo {
  /**
   * TODO ID
   *
   * @example '1234567890123'
   */
  readonly id: string;

  /**
   * タイトル
   *
   * @example 'Buy groceries'
   */
  readonly title: string;

  /**
   * 説明
   *
   * @example 'Milk, bread, eggs'
   */
  readonly description?: string;

  /**
   * 完了状態
   *
   * @example false
   */
  readonly completed: boolean;

  /**
   * 期限日
   *
   * @example '2024-12-31'
   */
  readonly dueDate?: string;

  /**
   * 作成日時
   *
   * @example new Date('2024-01-01T00:00:00Z')
   */
  readonly createdAt: Date;

  /**
   * 更新日時
   *
   * @example new Date('2024-01-01T00:00:00Z')
   */
  readonly updatedAt: Date;

  /**
   * ユーザーID(LINEユーザーID)
   *
   * @example 'U1234567890abcdef'
   */
  readonly userId: string;

  constructor({
    id,
    title,
    description,
    completed,
    dueDate,
    createdAt,
    updatedAt,
    userId,
  }: TodoProps) {
    this.id = id;
    this.title = title;
    this.description = description;
    this.completed = completed;
    this.dueDate = dueDate;
    this.createdAt = createdAt;
    this.updatedAt = updatedAt;
    this.userId = userId;
  }

  /**
   * 新しいTODOを作成します
   * @param params TODOの作成パラメータ
   * @returns 新しいTODOインスタンス
   */
  static create(params: {
    id: string;
    title: string;
    description?: string;
    dueDate?: string;
    userId: string;
  }): Todo {
    const now = new Date();
    return new Todo({
      id: params.id,
      title: params.title,
      description: params.description,
      completed: false,
      dueDate: params.dueDate,
      createdAt: now,
      updatedAt: now,
      userId: params.userId,
    });
  }

  /**
   * TODOを完了状態にマークします
   * @returns 完了状態の新しいTODOインスタンス
   */
  markAsCompleted(): Todo {
    if (this.completed) {
      throw new TodoAlreadyCompletedError("このTODOは既に完了しています");
    }

    return new Todo({
      id: this.id,
      title: this.title,
      description: this.description,
      completed: true,
      dueDate: this.dueDate,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      userId: this.userId,
    });
  }

  /**
   * TODOを未完了状態にマークします
   * @returns 未完了状態の新しいTODOインスタンス
   */
  markAsUncompleted(): Todo {
    if (!this.completed) {
      throw new TodoAlreadyUncompletedError("このTODOは既に未完了です");
    }

    return new Todo({
      id: this.id,
      title: this.title,
      description: this.description,
      completed: false,
      dueDate: this.dueDate,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      userId: this.userId,
    });
  }

  /**
   * TODOのタイトルを更新します
   * @param newTitle 新しいタイトル
   * @returns 更新されたTODOインスタンス
   */
  updateTitle(newTitle: string): Todo {
    return new Todo({
      id: this.id,
      title: newTitle,
      description: this.description,
      completed: this.completed,
      dueDate: this.dueDate,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      userId: this.userId,
    });
  }

  /**
   * TODOの説明を更新します
   * @param newDescription 新しい説明
   * @returns 更新されたTODOインスタンス
   */
  updateDescription(newDescription?: string): Todo {
    return new Todo({
      id: this.id,
      title: this.title,
      description: newDescription,
      completed: this.completed,
      dueDate: this.dueDate,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      userId: this.userId,
    });
  }

  /**
   * TODOの期限日を更新します
   * @param newDueDate 新しい期限日
   * @returns 更新されたTODOインスタンス
   */
  updateDueDate(newDueDate?: string): Todo {
    return new Todo({
      id: this.id,
      title: this.title,
      description: this.description,
      completed: this.completed,
      dueDate: newDueDate,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      userId: this.userId,
    });
  }
}

OpenAPI定義の作成例(抜粋)

OpenAPI定義
paths:
  /todos:
    get:
      summary: 全てのTodoを取得する
      tags: [Todos]
      responses:
        200:
          description: 成功
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Todo"
        500:
          description: サーバーエラー
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

困ったときはベストプラクティスを読む

Claude Code のベストプラクティスドキュメントを読み返すことで、多くの問題が解決しました。

https://www.anthropic.com/engineering/claude-code-best-practices

上記の他にも公式のガイドラインは非常に参考になるので、定期的に確認することをお勧めします。

https://www.anthropic.com/news/context-management

TODO アプリケーションの規模感

Claude Code を使用して作成した今回のプロジェクトは、以下のような規模になりました。

  • 総ファイル数: 200以上
  • 総コード行数: 約15,000行(テストコード含む)
  • ワークスペース数: 3つ(web、server、infra)

これだけの規模のアプリケーションを、Claude Code との対話だけで作成できたことは、正直驚きでした。ただし、それは適切な対話の進め方を意識したからこそだと感じています。

実際に感じた効果

開発速度の向上

従来であれば数週間ほどかかるような実装が、Claude Code との対話により大幅に短縮されました。

  • 定型的なコードの自動生成: DI コンテナ設定、Express ルーティング設定など
  • テストコードの作成: ユニットテスト、統合テストのパターン生成
  • CDK スタックの実装: インフラコードの記述

コード品質の向上

Claude Code に以下の観点でレビューを依頼することで、コード品質が向上しました。

  • 一貫性: 命名規則、コーディングスタイルの統一
  • 保守性: 適切な抽象化、責務の分離
  • 可読性: わかりやすい変数名、適切なコメント
  • セキュリティ: 脆弱性の指摘、ベストプラクティスの提案

学習効果

Claude Codeとの対話を通じて、以下のような学習効果がありました。

  • DDDの理解: ドメイン駆動設計の実践的な適用方法
  • サーバーレスアーキテクチャ: AWS各サービスの連携方法
  • TypeScriptの型システム: 高度な型定義の活用
  • テスト戦略: 効果的なテストの書き方

注意点と課題

コンテキスト管理

Claude Code は大きなコンテキストウィンドウを持っていますが、それでも以下のような工夫を行うとより効果的だと感じました。

  • 作業を細かく分割する
  • 実装しようとしているコードに関連するファイル(仕様、スクリーンショット、関連のコード)をコンテキストとして設定する
  • 「バックエンド全体を実装して」ではなく、「TodoRepositoryの実装」→「TodoUseCaseの実装」と段階的(ステップ・バイ・ステップ)で指示する
  • 定期的にCLAUDE.mdを更新することで、Claude Code が「今どこまで進んでいるか」を正確に把握できる

生成されたコードの検証

Claude Codeが生成したコードは、必ずしも完璧ではありません。そのため、以下の確認も必要でした。

  • 動作確認: 実際に動かして期待通りの動作をするか
  • テスト実行: 既存テストが通るか
  • セキュリティチェック: 脆弱性がないか
  • パフォーマンス確認: 性能上の問題がないか

人間の判断が必要な場面

以下のような場面では、最終的に人間の判断が必要でした。

  • アーキテクチャの選択: 複数の選択肢から最適なものを選ぶ
  • トレードオフの判断: コストと機能のバランス
  • 要件の解釈: 曖昧な要件の明確化
  • 優先順位の決定: どの機能から実装するか

まとめ

今回作成した TODOアプリケーションは、フロントエンド、バックエンド、インフラストラクチャの全てを Claude Code との対話を中心に実装しました。モノレポ構成、DDDアーキテクチャ、サーバーレス構成、OpenAPI定義、CI/CDパイプラインなど、モダンな開発手法を可能な限り取り入れることができました。

また、Claude Codeを使った開発は、適切な対話の仕方を意識することで、効率的に進められることも確認できました。

特に重要だと考えるポイント整理

  • (とにかく)細かく、シンプルな指示で依頼する
  • 現状を理解させてから依頼する
  • コンテキスト情報を積極的に活用する
  • 定期的にメモリファイルをアップデートする
  • セカンドオピニオンで回答の妥当性を確認する
  • Plan mode で事前に実装案を確認する
  • 既存機能への影響を常に意識する

また、Claude Code のような AI ツールを使いこなすには、私たち人間側の知識やスキルも重要だと思いました(Claude Code との対話を通じて、実装内容を理解し常に振り返ることで、自分自身の理解も深まったと感じています)。

この記事が誰かのお役に立てば幸いです。

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。

参考資料

この記事をシェアする

FacebookHatena blogX

関連記事