この記事は「連載:技術基盤強化プロジェクト「RFS」の現在と未来」として書かれたものです。
メルカリ JP の CS Tool チームの @AHA_oretama です。
私たちのチームでは、CS Tool (Custmer Service Tool)の開発を長年の間行ってきました。その中で積み重なった負債を解消するために、フロントエンドのリプレイスプロジェクトを立ち上げ、PoC(Proof of Concept)として3か月ほどの期間で1画面のリプレイスを行ってきました。今回の記事は、CS Toolのフロントエンドのリプレイスプロジェクトの成り立ち、リプレイスの開発とその成果を紹介していきたいと思います。
CS Tool チームの他の取り組みは、
- @hukurou さんによる「メルカリCSツールにおけるDBの疎結合化への取り組み」
- @monkukui さんによる「GKE 移行を進める上で発見したシステムの問題をどの様に解決したか」
で紹介されているので、興味がある方はそちらも是非御覧ください。
既存のCS Toolに山積されている課題をいかに解消していくか?
CS Toolフロントエンドにおける技術的負債
CS Toolはメルカリアプリのローンチ前から開発が開始され、その間に多くの機能追加がありました。その一方で、担当エンジニアが少ない時期が長くあり、メンテナンスや改善があまりされていませんでした。その結果、CS Toolでは負債が積み重なり、現状では特にフロントエンドのメンテナンスが非常に困難な状況になってしまっています。
おもに負債となっているポイントをあげていくと、フロントエンドでは作られた時期によって使われていたフレームワークが異なり、それらが混在している点があります。PHPのテンプレートエンジンであるTwig、OSSのフロントエンドフレームワークであるtupai.js、数年前に一部置き換えを行ったReactの3つがいまも存在しています。これらが混在していることで、求められる知識の量と幅が増え、改修の難易度をあげています。
とくにtupai.jsは非常に大きな問題となっています。OSS自体が長年メンテナンスされていないため、周辺ライブラリをアップデートできないだけでなく、新しいライブラリ(例えばTypeScript、Testing Libraryなど)をインストールすることもできません。加えて、ドキュメントやナレッジがあまり存在しないため、新たに参画したメンバーがtupai.jsの画面を改修するハードルを高めています。
ローカルでの開発体験が悪いことも大きな負債となっています。CS Toolはフロントエンドとバックエンドが密結合しており、バックエンドを起動しなければフロントエンドを動かすことができない状態です。そのバックエンドも複数の他サービスに依存しており、ローカルで起動することができません。そのため、フロントエンドの改修は共用の開発サーバにアップロードするという方法をとっており、DX(Developer Experience)を著しく下げています。
テストが書けない状態にある、というのも大きな負債の1つです。さきほど述べた通り、tupai.jsは現在メンテナンスされてないため、Testing Library(Reactの場合はReact Testing Library)を導入することができません。そのため、tupai.jsのコードに対してテストを書くことが非常に困難な状態です。また数年前に一部置き換えを行ったReactの部分は、React Testing Libraryを導入することはできますが、CS ToolにあるReactのコンポーネント自体がテスタブルに作られてこなかったため、これもテストを書くことが困難な状態にあります。
解除されないCodeFreezeと、これまでのMicroservice化の問題点
技術的負債以外の大きな課題としてCodeFreezeをしつづけていることがあります。近年、メルカリでは全社的にMicroservice化が推し進められており、CS Toolでも同様にMicroservice化を進めてきました。既存の機能が追加・改修されている状態でMicroservice化を行うと、既存のCS Toolに改修が加え続けられた分だけMicroservice化のスコープが増え続け、Microservice化が終わらない可能性さえ出てきます。このような状態を避けるために、Microservice化を始めるにあたり、CS Toolのすべてのコードの修正を原則、禁止にしました。これをCodeFreezeと呼んでいます。
数年前から現在までCodeFreezeの状態は続いており、その間にMicroservice化を進めてきましたが、現在のところCS Toolに数十ある機能のうち数機能しかMicroservice化できていません。このままMicroservice化を進めていった場合、10年単位の時間が必要になることが想定されますが、その間CodeFreezeをしつづけることは現実的ではありません。
またこれまでのCS ToolのMicroservice化では、ドメインを1つのアプリケーションに切り出し、画面・仕様を1から再定義してきました。しかしながら、この方法にはいくつかの問題点がありました。
- 画面・仕様を定義しなおすために開発に大きなコストがかかる
- CS Toolを利用しているカスタマーサービスの運用の変更を伴う作業になり、移行に非常に大きなコストがかかる
- カスタマーサービスの人々が切り出した分だけ複数アプリケーションを使わなければならない
- 本来のMicroservice化はバックエンドを主とするが、Microservice化のスコープにフロントエンド・バックエンド両方を含み、開発の規模が大きくなっている
このように、この方法はMicroservice化を長引かせる要因となっていました。
フロントエンドのリプレイスという選択
これまで見てきたようにCS Toolにはいくつかの大きな課題が残っていました。これらの解決策として、フロントエンドのリプレイスを行うことに決めましたが、ここでリプレイスをしていこうと決めた理由を説明しておこうと思います。
1つは、上記にあげた技術的負債をリプレイスすることですべて解消できる点にあります。最も重要な点は、3つの混在したフロントエンドフレームワークを1つのモダンなフレームワークに統一できることです。これにより、学習ハードル、DX、テスタビリティの改善が見込まれます。
2つ目は、新たなCodeFreezeの解除条件の設定です。これまでの基準はMicroservice化の完了が条件でしたが、これは10年単位の時間が必要と予想されているため、現実的ではありません。Microservice化の完了に代わる新たな基準が必要です。フロントエンドがリプレイスされていることを新たな解除基準とすることで、最後の理由で説明するように比較的短期間での解除が可能になります。
3つ目は、フロントエンドのリプレイスはこれまでのCS ToolのMicroservice化の問題点への対処法になっている点です。
- リプレイス(仕様・画面を原則、維持)の場合、開発コストが比較的少なく、移行の必要性がない
- カスタマーサービスの人々が使うアプリケーションが増えずに済む
- フロントエンドのリプレイス後はバックエンドのMicroservice化のみにフォーカスできる
最後に、リプレイスのコストが思った以上に低いということがわかったためです。比較の対象となったのはGroundUp Webプロジェクトで、「メルカリWebのマイクロサービス化、その4年」で述べられているように、最終的にはメルカリのWebサービスは1年前後の開発期間を経てリプレイスされました。CS ToolのフロントエンドはそのGroundUp Webのリプレイス元となったWeb-2のコードの1/10ほどしかコードがないことがわかりました。人員や元々の機能に違いがあるため安易には見積もれませんが、1/10ほどのコードであれば半年以内でリプレイスできる可能性も見えてきました。
プロジェクトの成り立ち
ここでは、CS Toolのフロントエンドのリプレイスプロジェクトの成り立ちについて説明していきます。
私は去年からCS Toolチームに参画し、1〜2か月ほどのオンボーディング期間を経て、その後チームの開発を本格的に行うようになりました。半年ほど開発を進めていく中で、開発体験や品質の悪さをひしひしと感じるようになりました。その原因が上記に挙げた負債によるものと察するのはそう難しくありませんでした。そこから負債による問題を緩和もしくは解決する方法を、自分の手の空いた時間を使いながら模索していきました。いくつかの調査を行った結果、自分の中でフロントエンドのリプレイスが現実的な解決策であるという結論に達したため、現状の問題点を言語化し、調査結果とリプレイスするという提案をDesign Docにまとめあげました。
その後、そのDesign Docをチーム→Camp(チームの上部組織)の順でシェアしていき、リプレイスという提案に対して、概ね賛同を得ることができました。Design Docにまとめる際には短期的なゴールを設定したことで現実的な作業内容が見えるようになったことが賛同を得やすくなったことの一因かと思っています。短期的なゴールはPoC(Proof of Concept)として3か月ほどの期間で1画面のリプレイスを行うことで、そのPoCの結果を受けて今後リプレイスを全画面に拡大するかどうかを判定することとしました。またメルカリの「Go Bold」という文化があったため、いちメンバーのこのような提案を後押しする結果になったとも感じています。
このようにしてプロジェクトが始まり、現在までPoCとして3か月+αの期間でインフラの構築(後述のStranglerパターンの導入)と1画面のリプレイスを行ってきてきました。このブログの執筆時点では、ほぼ実際の開発作業は完了し、リリースとPoCの振り返りを行うのみとなっています。
実際の開発
まず始めに既存のCS Toolサービスの前段にProxyサーバを導入し、既存のCS Toolサービスへのリクエストを維持しつつ、一部のリクエストのみをリプレイスしたフロントエンドサービスへプロキシできるようにしました。これは[Stranglerパターン]と呼ばれるパターンで、レガシーサービスを徐々に新規サービスへ置き換える手法として知られています。
admin-gateway: CS Toolなどのメルカリ内部向けサービスのアクセスを管理するサービス
CS Tool: 既存のCS Tool。フロントエンド、バックエンドを提供している。
new proxy: 今回新たに導入したProxyサーバ
new frontend: リプレイス後のフロントエンド
リプレイスしたフロントエンドサービスはSPA(Single Page Application)で、Kubernetes (K8s)上のPodからアセットを配信しています。フロントエンドサービスをK8s上に配置した理由は、admin-gatewayからのアクセスしか許可しないようにするためにはadmin-gatewayと同じK8s上に配置するのが一番簡単なことと、同様の構成を以前に実施した知見があったためです。
フロントエンドの開発で使っている主なツールはこれらになります。
- Vite
- TypeScript
- React
- Tailwind CSS
- SWR
- Lint
- テスティング
- etc
これらを使った効果や感想については次の章で少し触れたいと思います。
リプレイス後の効果
当初の狙い通り、リプレイスすることで最初に挙げた負債について著しい改善が得られました。とくに開発生産性、品質の面で大きな改善となりました。
開発生産性の面では、フロントエンドをローカル環境で起動することができる仕組みを2パターン導入し、ローカルで開発できるようになり、開発速度が劇的に向上しました。この仕組みの1つは、起動する前に少し準備が必要(Cookieの設定、VPNの設定など)ですが共用の開発環境のAPIサーバに接続してローカル環境でフロントエンドを起動する方法です。もう1つはMock Service Workerを使い、MockしたAPIと通信する方法です。後者はローカルですべてが完結するため、準備や外部との接続がないのが利点です。
品質面では、開発初期からCIを導入し、UnitテストやLintを実行することで品質を担保できる仕組みができています。チームメンバーのほとんどはフロントエンドのテストに関する知識があまりない中ではありましたが、必ずUnitテストを書いてくれたのが非常に大きかったです。
それ以外にもTypeScriptを導入したことで、フロントエンドで実際に利用しているAPIのフィールドが明確になり、バックエンドのAPIの改善に今後使えることや、SWRを導入したことでリクエスト数が減り、パフォーマンスの改善が行えたこと、開発を通して開発している画面の仕様理解が深まったなど、いくつかよい効果がありました。
今回一番苦労したことがフロントエンド開発に関する知識、経験不足でした。ほとんどのメンバーはフロントエンドの開発の経験がなかったため、その部分のキャッチアップが非常に大変で、慣れるまでに思った以上に時間がかかってしまいました。この問題に対して、チーム内で週2回各30分程度の勉強会を開き、知識、ナレッジの共有を行いました。簡易の形式の勉強会でしたが、チームメンバーが主体的に取り組んでくれたので非常に有意義なものとなりました。Tailwind CSSの勉強会から始まり、今後はテストやReactなどを継続して勉強していく予定です。
まとめ
メルカリアプリのローンチ前から開発され続けてきたCS Toolですが、とくにフロントエンドに負債が積み重なってきました。それに対して、フロントエンドをリプレイスするという提案をし、PoCとして1画面のリプレイスをおこなってきました。新しいフロントエンドの開発はいまのCS Toolと比べると非常に改善がされており、開発生産性、品質が大きく向上しました。
この記事の執筆時点では、PoCとしてリリースと振り返りを残すのみとなっています。今後はPoCの振り返りを行い、CSTool フロントエンドをすべてリプレイスする場合の工数やスケジュール、他のプロジェクトとのスケジュール調整などを行っていきます。今後、どこまでCSTool フロントエンドのリプレイスを行うか、何ヶ月ほどかかるかなどはまだわかっていませんが、このようなブログを通してフロントエンドのリプレイス状況を共有できればと思っています。
現在、メルカリでは「RFS」というメルカリのビジネス共通基盤の技術的な課題を解決していく全社横断的なプロジェクトに一緒に立ち向かっていく仲間を募集しています!ご興味が湧いた方は、以下のリンクをご覧ください。
Software Engineer, Backend Foundation (PHP/MySQL) – Mercari
Software Engineer – Mercari