BPaaS が AWS Amplify Gen 2 を選択する理由

![01c2d60171edbd-a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569971/8b139e6b-4e5f-bc49-3b01-a4a5f3317710.png)

kubell Advent Calendar 2024 の投稿です。

:::note info
2024年7月1日、Chatwork株式会社は株式会社kubellへと社名変更しました。
:::

https://qiita.com/advent-calendar/2024/kubell

この投稿では、BPaaS プロダクト開発において AWS Amplify Gen 2 (Amplify) を選択した理由について書きます。

## tl;dr

- Amplify を選定した理由は、開発効率とスピード向上のため
- AWS サービスとのネイティブ統合で認証やデータベース設定が簡単
- 自動ビルド・デプロイ機能により迅速な開発とリリースが可能
- 柔軟な環境管理でチームの要件に適合

## 前提

### BPaaS サービスとは

- チャット経由で会計、労務、総務など様々なバックオフィス業務をアウトソースできる「Chatwork アシスタント」などのサービスです。
- 私たちは現在バックオフィス業務管理システムの構築を進めています。

https://assistant.chatwork.com/?adcode=orgic_platf_cwassistant_gm-om_corporate&utm_source=gm-om&utm_medium=corporate&utm_campaign=cwassistant&utm_term=non&utm_content=cid25

### スキルスタック

- 私たちの共通のスキルスタックは TypeScript です。Full-Satck TypeScript がチームの方向性として合致していました。
- Amplify は AWS CDK でインフラを構築でき、TypeScript との親和性が高いと思います。
    - 私自身の経験としても、CDK for Terraform (CDKTF) [^4] を使用して構築した経験があり、前職での経験が Amplify に対応しやすいものとなっていました。

### チーム状況

私たちがチームを構築したのは最近で、Developer は多くありません。そのため、効率的に開発を進める必要がありました。

## Amplify を選定した理由

### 開発効率とスピードの向上

市場志向のチームとして、開発効率とスピードの向上という明確な理由があります。Amplify は、簡単に安全でスケーラブルなアプリを構築することができます。

### プラグイン アーキテクチャの活用

- AWS の各種サービス、特に認証やデータベースとのネイティブな統合が特徴です。
- Amplify が持つこの特徴より、必要に応じて Amazon Cognito などの AWS サービスを組み合わせることができ、柔軟なシステム設計が可能です。

https://docs.amplify.aws/vue/build-a-backend/auth/set-up-auth/

- プラグイン方式の恩恵により、アプリケーションへの依存は、コードベースでほぼ存在しません。ローカル環境のみで起動できますし、AWS 環境への接続も AWS CLI があれば気軽に行えます。 `aws configure sso`
- Amplify で生成される設定ファイル (`amplify_outputs.json`) があります。フロントエンド アプリケーションがバックエンド リソースにアクセスするために必要な情報を含んでいます。

```mermaid
graph TB
    subgraph Frontend
        React[React Application]
        AmplifyCfg[amplify_outputs.json]
    end

    subgraph Backend Resources
        Auth[Cognito Auth]
        API[GraphQL API]
        Lambda[Lambda Functions]
        DynamoDB[DynamoDB Tables]
    end

    AmplifyCfg --> Auth
    AmplifyCfg --> API
    React --> AmplifyCfg
    API --> Lambda
    API --> DynamoDB
    Lambda --> DynamoDB

    classDef frontend fill:#e1f5fe,stroke:#01579b
    classDef backend fill:#e8f5e9,stroke:#1b5e20
    classDef config fill:#fff3e0,stroke:#e65100

    class React,Frontend frontend
    class Auth,API,Lambda,DynamoDB,S3 backend
    class AmplifyCfg config
```

### バックエンドの技術スタック選定

- バックエンドの Frameowork として NestJS を選定しました。

https://docs.nestjs.com/

- この選択により、フロントエンド・バックエンドどちらも開発することができ、メンバーの作業負荷状況に合わせて、フロントエンド・バックエンドに移動しながら開発できます。
- フロントエンド・バックエンド・インフラの重なる部分は、言語を意識する必要がありません。
    - 例えば、バックエンドの Read Replicas の Extension の追加と インフラの Reader Instance の設定を SRE が実装しました。
    - E2E Testing (Playwright) や 負荷試験 (k6) も TypeScript でカバーしています。 [^5]
        ```mermaid
        flowchart LR
            playwright[Playwright] -->|Record a HAR file| har[HAR]
            har -->|Genearte| js[JavaScript]
            js --> k6
            k6 -->|Request| app["Web App"]
        ```
- リポジトリは開発の効率を考慮し Monorepo を採用しています。 Nx [^2] や Turborepo [^3] は検討しましたが、2024年5月当時 Amplify の Framework 検知に誤作動があったため、見送りました。
    - リポジトリ ルートの package.json の dependencies に `next` が含まれる場合、当該アプリのフレームワークが Next.js と認識される動作となっていた。
    ```bash
    [ERROR]: !!! CustomerError: Can't find required-server-files.json in build output directory
    ```

https://docs.npmjs.com/cli/v7/using-npm/workspaces

### 自動デプロイと環境管理の柔軟性

![alt text](/images/01c2d60171edbd-b.jpg)

- Amplify には default で GitHub と連携して自動的にビルドやデプロイを行う機能があり、開発チーム全体のフローを円滑にする役割を果たしています。
- 特に私たちのように素早いプロダクト リリースとフィード バックサイクルを目財しているチームにとって、Amplify の自動デプロイ機能は非常に魅力的だと思います。
- Amplify Console の利用により、異なるブランチを異なる環境（例えば Staging や Production）に割り当てることができるため、環境ごとのテストや確認がスムーズに行えます。

## 課題

### Amplify Managed の制約

- Amplify Managed Frontend は CloudFront、Lambda で構成されています。この構成は、開発者の作業を省力化するメリットがありますが、一部の制約も伴います。
- 特に、Lambda の設定を変更することができないという課題があります。具体的には、Lambda でアクティブ トレースを有効化し、ログにトレース ID を出力することが望まれますが、Amplify の Managed 環境では現時点でこの設定がサポートされていません。[^1] この制約により、トラブルシューティングやパフォーマンス監視の効率が低下する可能性があります。

https://github.com/aws-amplify/amplify-hosting/issues/3515

### `ampx` コマンドのエラー解析の難しさ

- `ampx` コマンドでデプロイ時に発生するエラーから原因を特定するのはその時点では難しいと感じられました。
    - 例えば、ログに記録されている `current_account-current_region` は、Amplify が内部的に使用している CDK にて、CDK が内部的に使用しているアセット の destinationId の値となります。成功する場合にも `current_account-current_region` はコマンドの出力結果に含まれるので、これが当該事象の要因ではありません。
    ```bash
    The CloudFormation deployment has failed.
    Caused By: ❌ Deployment failed: Error: Failed to publish asset 7af0558dad8eb937cbd5c43b7fe6bec9b1f611815c892643b5099811a28c3480:current_account-current_region
    ```

- 一方 `cdk diff` `cdk deploy` の警告や StackTrace は多くの情報を与えてくれます。`ampx` コマンドと比較して。

### Stateful な構成要素の扱い

```mermaid
flowchart TD
    subgraph aws["AWS Cloud"]
        subgraph amplify["Amplify Managed Frontend"]
            cloudfront["CloudFront
            (CDN)"]
            lambda["Lambda
            (Server-side Render)"]
        end
        subgraph account["AWS Account"]
            alb[ALB]
            ecs["ECS
            (API)"]
            rds[("RDS
            (Database)")]
        end
    end
    browser --> cloudfront
    cloudfront --> lambda
    lambda -->|Traffic in the AWS network| alb
    alb --> ecs
    ecs --> rds
    cicd["Amplify CI/CD"] -.->|npx ampx pipeline-deploy| amplify
    developer -.->|cdk deploy| account
```

- 当初はカスタムリソースとして、全てを Amplify で定義するつもりでした。

https://github.com/danny-yamamoto/buttermilk-backend-app/blob/main/amplify/backend.ts

- しかし、 Database などの Stateful な構成要素は変更が必要なタイミングが限られており、アプリケーションのデプロイサイクルとは異なります。
- 原理的にはカスタム リソースを用いれば、Database を含め Amplify で構成することも可能でした。私がサポートに確認した時点では、サポートの見解も同様でした。しかし、最終的にカスタム リソースの全面的な採用は断念しました。

https://docs.amplify.aws/react/build-a-backend/add-aws-services/custom-resources/

- Amplify で稼働している Lambda (Render) から Backend API の Endpoint である ALB への通信は、リージョン内およびリージョン間のトラフィックになります。

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/how-it-works.html#what-is-aws-global-network

---

記事は以上です。

この投稿をみていただい方はいいねをお願いします。

それでは次回のアドカレでお会いしましょう👋


[^1]: https://github.com/aws-amplify/amplify-hosting/issues/3515

[^2]: https://nx.dev/

[^3]: https://turbo.build/repo/docs

[^4]: https://developer.hashicorp.com/terraform/cdktf

[^5]: https://zenn.dev/dannya/articles/7dafc5d0a40640