Webフロントエンドのリアーキテクチャに向けた課題整理と解決の道筋
目次
はじめに
こんにちは!ハイヤールーの共同創業者の谷合です。
弊社はエンジニアのスキルチェックのためのコーディングテストサービス「HireRoo」を運営しています。
読者のみなさんもよくご存知の通りサービスリリースから日数が経過するにつれて、技術負債が溜まっていきます。
HireRoo も 2021/3 月にローンチされて約 2 年が経とうとしていますが、技術負債の蓄積から課題が露見するようになりました。
サーバーサイドも同様に問題を抱えておりましたが、一足先にリアーキテクチャが完了し、いくつかあった問題も解消されました。 (詳しくは HireRoo のインフラ基盤を Cloud Run から Kubernetes へ移行しモノレポで管理し始めた話 を参照ください。)
ただフロントエンドの課題は解消されていないため、今後開発のボトルネックとなっていくことが目に見えて分かったため、現在フロントエンドのフルリニューアルプロジェクトを進めています。
今回はなぜリニューアルするに至ったのかという部分と、それに対してどう対処しようと思っているのかについて紹介したいと思います。
リニューアルプロジェクト自体が開始されたばかりということもあり、今回の記事では課題の紹介についてがメインとなります。
TL;DR
- さまざまな要因によってリリース速度の低下が開発組織のボトルネックとなり、フロントエンドのフルリニューアルを開始した
- バックエンドにフロントエンドのユースケースを吸収させていた部分をBFF を導入することによって解決しようとしている
- モノレポのアーキテクチャを採用することで、チームをサービスごとに分離しレビュー時間の短縮やオーナーシップを明確にしたい
アーキテクチャと開発体制について
課題について触れる前にまず、HireRoo がどのようなアーキテクチャを採用しているのかと、どのような開発体制で開発しているのかを紹介させてください。
現状のフロントエンドのアーキテクチャについて
HireRoo のフロントエンドでは React を採用しており、状態管理には Redux を利用しております。
バックエンドはマイクロサービスのアーキテクチャを採用しているため、フロントエンドとバックエンド間は grpc を利用して各サービスに対してリクエストを送っています。
BFF(Backend for Frontend)層は存在せず、基本的にはフロントエンドが必要な情報を都度各マイクロサービスに問い合わせて情報を取得しています。
リニューアル前の詳しい構成についてはHireRoo のフロント基盤のご紹介の記事を参照ください。
フロントエンドの開発体制について
ハイヤールー(2022 年 10 月現在)はエンジニア 7 名で開発をしています。
人数も多くはないため、クライアントとバックエンドを全員で開発しています。
最近フロントエンドエンジニアのHimenonが入社してくれたおかげで、少しだけ分業が進みましたが、基本的にはバックエンドの開発をしつつフロントエンドの開発をするという体制に変わりはありません。
現アーキテクチャの課題
現状の課題を以下にまとめました。大きく 3 つの課題に分類することができました。
1.リリース速度の低下
特定のバックエンドにフロントエンドのユースケースが集中する問題
- バックエンドの一部のエンドポイントにフロントエンドが要求する複数の責務が集中し、ロジックの変更が難しい
- 類似実装がフロントエンドとバックエンド複数の箇所に散見されるようになり、一つのロジック変更で複数箇所に手を入れなくてはならないといったことが発生していた
責務の分離ができていないことによる開発時間の増加
- UI の表示ロジックとビジネスロジックがコンポーネント内に混在してしまい、テスタビリティが下がっていた。
- コンポーネントが最低限しか使いまわせないため、機能実装のたびに作り直していたそれにより一つの PR が肥大化する傾向があり、レビュー時に時間がかかるようになった
- モノリスなフロントエンドのアーキテクチャによる開発効率の低下機能が増えたことによって依存関係が複雑化し、実装からリリースまでの時間が伸びたモノリスのアーキテクチャであるため保守する人が全体を意識しなくてはならない部分が多い
モノリスなフロントエンドのアーキテクチャによる開発効率の低下
- 機能が増えたことによって依存関係が複雑化し、実装からリリースまでの時間が伸びた
- モノリスのアーキテクチャであるため保守する人が全体を意識しなくてはならない部分が多い
2.UI/UX の問題
- 機能実装するエンジニアが UI を考えて作っていたので、人によって出来上がるもののクオリティにばらつきがある
- また、統一感のない UI になり顧客に対して一貫した UX を提供できなくなっていた
3.バグや不具合の検知
- フロントエンド側のエラーを顧客からの通知で気づくことが多くなった
- リリース後に依存関係のある機能の不具合が発生し、パッチをあてる時間が取られる
プロダクトが成熟していないフェーズでは高速で PDCA を回すために新機能のリリースやバグフィックスを素早く顧客に届けることが求められます。
それ故に「リリース速度の低下」はハイヤールーにとってかなり致命的な問題だと考えました。
そのため今回のリアーキテクチャは、主にこの課題を解消することを重点に置き、検討することにしました。今回の記事もこの「リリース速度の低下」に関する課題について深くご紹介したいと思います。
リリース速度低下をどう解決するか
前のセクションで列挙した「リリース速度の低下」についての課題をピックアップして深掘りしたいと思います。
特定のバックエンドにフロントエンドのユースケースが集中する問題
- バックエンドの一部のエンドポイントにクライアントが要求する複数の責務が集中し、ロジックの変更が難しい
- 類似実装がフロントエンドとバックエンド複数の箇所に散見されるようになり、一つのロジック変更で複数箇所に手を入れなくてはならないといったことが発生していた
具体例を挙げて説明します。
コーディングテストを候補者が受験した場合、最大で以下の 5 つのサービスから取得したデータをフロントエンドで表示する必要があります。
- Spot(コーディングテスト情報)
- Challege(アルゴリズム形式の試験情報)
- Project(技術特化形式の試験情報)
- Quiz(選択問題形式の試験情報)
- SystemDesign(システムデザイン形式の試験情報)
現状これらの情報を取得するために、Spot サービスが各問題形式の情報をまとめて取得する役割を担っていました。
ただ、こうすることで Spot サービス自体の融通が効かなくなり、一つのエンドポイントのリクエストを変えると他のリクエストに影響が出るといった問題が発生するようになりました。
また、例えばレポート画面に表示させるスコアの計算ロジックはフロントエンドに実装されているのですが、PDF や CSV/Excel を出力するサービスにも同様のロジックが必要となってしまったことで、ロジックに変更を加えると複数のサービスにも変更が必要な状態になってしまいました。
これらの問題については、BFF を採用することによって解消を図ろうと考えています。
具体的なアーキテクチャについては、また移行プロジェクトの進捗とともに共有できればと思いますが、現時点ではGraphQLを利用してBFF の API Gateway パターンを利用し、フロントエンドのユースケースに応じたスキーマの定義を BFF 層で行うことで極力依存を生まない設計を実現しようと考えています。
またユースケースごとに個別で集計ロジックを実装していた箇所も、BFF 層に移行することで、アーキテクチャレベルで DRY を徹底的に実践することができると考えています。
責務の分離ができていないことによる開発時間の増加
- UI の表示ロジックとビジネスロジックがコンポーネント内に混在してしまい、テスタビリティが下がっていた
- コンポーネントが最低限しか使いまわせないため、機能実装のたびに作り直していた
- それにより一つの PR が肥大化する傾向があり、レビュー時に時間がかかるようになった
これら一つ一つは目に見える形で露見する問題ではなく、ジワジワと開発効率を下げていく毒のようにプロダクトに蓄積していきます。
しかもパッチ的な対応で即効性のある打ち手が出しにくいという側面もありかなり厄介な課題です。
以前弊社でも Storybook を導入したり E2E テストを導入したりといくつか打ち手を試したものの、開発効率向上には効果が得られませんでした。
これらに対して、かなりシンプルではありますが、フロントエンドの「依存関係の整理をする」ことである程度解決できるのではないかと考えています。
有名なクリーンアーキテクチャいわく、関心の方向を整理することが本質であるため弊社にあった構成を現在検討中です。
フロントエンドのアーキテクチャはバックエンドのアーキテクチャをそのまま使えるというわけではない(なかった)ので、今回はその反省を活かして依存関係の整理と責務の分離を意識した設計を行う予定です。
その上で Storybook や E2E テストを導入し、さらなる効率化を図っていければと思っています。
こちらに関してはそれ自体で 1 本の記事にできそうなので、別途記事にしたいと思っております。
モノリスなフロントエンドのアーキテクチャによる開発効率の低下
- 機能が増えたことによって依存関係が複雑化し、実装からリリースまでの時間が伸びた
- モノリスのアーキテクチャであるため保守する人が全体を意識しなくてはならない部分が多い
現状すべてのサービスがページごとに配置されているだけであるため、一箇所実装するためには複数のファイルに横断して変更する必要があることがあります。
それ故に依存関係をかなり気にした実装をする必要があり、リリースまでの時間が伸びたり、最悪の場合はリリース後に不具合に気づくということが増えました。
この課題に対しては、バックエンドがマイクロサービスのモノレポであるため、フロントエンドでもモノレポを採用し、各サービスごと(あるいはいくつかのまとまりごと)にパッケージ化して責務を分離したいと考えています。
弊社でもNext.jsやPrismaといった有名プロジェクトでも採用されているpnpmを利用したモノレポのアーキテクチャを採用する予定です。
そうすることで、例えば必要に応じて各パッケージで最適な State 管理ライブラリを選択できるようになったり、チームにオーナーシップを持ってもらいやすくなりフロントエンドでも各サービスごとにチーム分割できるようになったりと、様々なメリットを享受できると考えています。
それが実現できれば、各サービスのドメインロジックを知っている開発者が、自分の担当するサービスのみの機能追加に集中できるため、それ以外の部分に意識を向ける必要がなくなるためレビュー時間を今より少なくすることができるようになります。
また依存関係が少なくなることによって、リリース後の予期せぬバグも減るのではないかと考えております。
さいごに
今回の記事では、HireRoo の現状のフロントエンドの課題とそれに対する打ち手について紹介いたしました。
移行のプロジェクト自体はまだ始まったばかりなので、具体的な部分について紹介できない箇所もありますが、これからプロジェクトが進むにつれて紹介できる知見も増えていくと思いますので、もし今回の記事で興味を持っていただけたら、ぜひ次回の記事もお楽しみにしてください。
移行がすべて終わり、しばらく運用した後にこの設計が正しかったのかという答え合わせの記事も出す予定です!ぜひそちらもご期待ください!
最後までお読みいただきありがとうございました!