こんにちは。認証グループの山下です。
今回は約2年前に行ったアカウント設定のフロントエンド開発における技術選定とこれまでの運用を振り返りたいと思います。
技術選定の前提と背景
「Chatwork」は長年にわたり機能追加やリファクタリングを重ねてきましたが、管理系機能のモバイル対応は十分に進んでいませんでした。
特に、モバイルのみを利用するユーザーにとって管理機能の使い勝手が悪く、改善の必要がありました。
そこで、管理機能の中でも比較的対応しやすく、かつ利用ユーザーの母数が多い「アカウント設定機能」のモバイル対応から着手することにしました。
対応の経緯
- 2023年5月:アカウント設定のモバイル対応をリリース
- 2025年1月:Web向けのアカウント設定とモバイル向けを統合し、リリース
この流れの中で、モバイル・Webの統一的な設計を意識した技術選定 を行い、長期的な保守性・拡張性も考慮したアーキテクチャを採用しました。
2年前の技術選定と設計
技術選定と設計
- Next.js
- Lambdaの活用
- Featureディレクトリ構成 + Container/Presentation
- Storybook + MSWによるインタラクションテスト
- OpenAPIによるスキーマファースト
- React Hook Form + Zodによるフォームのvalidation
振り返り
Next.jsの選定
モバイル側の JS処理を削減し、安定した表示速度を提供するために、SSR(サーバーサイドレンダリング)を行えるフレームワークの選定を行いました。
当時、Remix はまだプロダクションでの採用事例が少なく、React で開発を進める場合のフレームワーク選択肢は限られていました。さらに、Next.js の App Router はまだ Production Ready な状態ではなく、安定性を重視する中で、Pages Router を採用するほかない状況でした。
Next.js は当時から広く認知されていた SSR フレームワークであり、安定した開発体験とともに、モバイルでのパフォーマンス向上が期待できるため、選定に至りました。
実際に開発を進めて運用を行う中で、Next.js によるメリットは大きいものの、運用コストが高いと感じています。特に、現在は認証チームで管理していますが、フロントエンド、特に React や Next.js に明るい人が少なく、ライブラリや技術の保守コストが大きいと実感しています。この点については今後の課題となりそうです。
Lambdaの活用
事前調査として、既存のアカウント設定機能のアクセス数を分析したところ、一定数の利用はあるものの、チャット画面のように頻繁にアクセスされるものではないことが分かりました。
アクセス頻度がそれほど高くないことを踏まえ、フロントエンドのホスティングとしてLambdaを活用することでインフラコストを抑える設計を採用しました。常時アクセスがあるシステムではないため、Lambda のスケールの柔軟性を活かしつつ、運用コストを最適化できています。
また、デプロイ方式としてZipで固めるのではなくコンテナイメージとしてデプロイしています。将来的に Lambda から ECS などのコンテナ環境へ移行する際の負担を軽減するために、この方針を採用しており、運用面でもメリットが大きかったと感じています。
Featureディレクトリ構成 + Container/Presentationパターン
本プロジェクトでは、機能単位で管理する Feature ディレクトリ構成を採用しました。これにより、各機能を独立した単位で整理し、保守性を高めています。 さらに、Feature 内部では Container/Presentationパターンを適用し、ロジック(Container)と UI(Presentation)を分離することで、再利用性とテストのしやすさを向上させました。 また、Next.js を採用していることから、ルーティング対象となる機能は pages ディレクトリに集約し、Next.js に直接依存する部分を限定しています。Feature 内部で Next.js 固有の機能を使用する場合は、直接参照せずラッパーを挟む形で利用する設計としました。 このアプローチにより、将来的なフレームワークの移行コストを抑える設計を意識しています。実際に移行する機会が訪れた際、その効果がどこまで発揮されるかを検証できるでしょう。
Storybook + MSWによるインタラクションテスト
Storybook に MSW(Mock Service Worker)を組み込み、インタラクションテストを実施しています。これにより、ユーザー操作を伴う様々なケースをテストできるだけでなく、Storybook 上で UI の動作を可視化し、デザインレビューの場としても活用できています。
インタラクションテストの詳細については、別途アドベントカレンダーの記事で紹介していますので、興味がある方はそちらもご覧ください。
OpenAPIによるスキーマファースト
OpenAPI を活用したスキーマファースト開発を採用しました。スキーマを起点に設計を進めることで、API 仕様の議論がスムーズになり、フロントエンドとバックエンドの開発を並行して進めやすいというメリットがありました。
フロントエンドでは、openapi-typescript を使用してスキーマの型のみを自動生成し、各エンドポイントの型定義として活用しています。また、MSW のモック API の型にも同じスキーマを適用することで、テストと本番環境で型の乖離がないようにしています。
現在は自動生成された型をそれぞれの使用箇所でインポートする形ですが、今後はモックAPI等の自動生成も含めてさらに開発効率を高めたいと考えています。
React Hook Form + Zodによるフォームのvalidation
フォームのバリデーションに React Hook Form(RHF)と Zod を採用しました。
RHFは、制御されたコンポーネントを最小限に抑えつつ、高パフォーマンスなフォーム管理ができるのが特徴です。特に、再レンダリングの抑制やデフォルト値の管理が容易な点が、今回の要件に適していました。
Zod を組み合わせることで、スキーマベースのバリデーションを実装し、型安全性を担保しながらフォームのバリデーションルールを定義できます。また、エラーメッセージもスキーマ内で定義できるため、バリデーションルールとエラーメッセージを一元管理できる点がメリットでした。
実際に運用してみると、RHF の導入はしなくてもいいなと感じました。 再レンダリングの抑制というメリットはあるものの、それを管理するためのコストが発生し、さらに細かいバリデーションやエラーハンドリングを行おうとすると実装が複雑になりがちでした。結果として、運用コストの方が大きくなっているということからよりシンプルなフォーム管理の方法でも良かったのではないかという振り返りがあります。
まとめ
今回は2年前に行った技術選定について振り返りを行いました。
当時の選択肢としては、プロジェクトの要件に最適なものを選んだと感じていますが、数年経過した今では、さらに多くの選択肢が登場していることに気づき、技術選定の難しさを改めて実感しています。
その中でも、将来的な移行を見越した設計を行うことの重要性を強く感じました。技術は進化し続けるため、柔軟に対応できるような設計を行うことが、プロジェクトの長期的な成功に繋がると再認識しました。