商品通報対応をgRPCとGraphQLとReactでリプレースしてみた

こんにちは。Mercari Advent Calendar 2019 14日目は、CSTool Domainチームの @Peranikov がお送りします。

メルカリではお客さまに安心して取引を楽しんでいただくため「あんしん・あんぜん宣言」に取り組んでおり、プロダクトの開発と同じレベルの課題感でカスタマーサービスの質の向上にも力をいれています。私の所属するCS(Customer Service) Tool Domainチームでは、カスタマーサービスのメンバーがお客さまからのお問い合わせ対応に使用するシステムの開発・運用を担っています。

商品通報対応とは

メルカリでは利用規約に反するような出品がされた場合、お客さまや権利者さまからの通報・ルールベースやMachine Learningによる監視などで違反出品を検知し、カスタマーサービスチームが確認・対応するという業務を行っています。

ただ、サービス成長に伴い監視業務の精度・生産性向上が経営課題となりはじめ、かつ全社的なマイクローサービス化の推進もあいまって、この通報対応部分を業務フローの見直しも含め、フロントエンドからバックエンドまでリプレースするプロジェクトが発足しました。

アーキテクチャ

まず、全体的なアーキテクチャ像として以下のような形になりました。

f:id:Peranikov:20191212171109p:plain

これらのサービスは他のマイクロサービスと同じくGKE上で稼働しています。それぞれのサービスの役割を説明していきましょう。

Gateway

弊社ではAPI Gatewayやmerpay-gateway など他のサービスへのルーティングや認証を行うGatewayを内製しています。私達のチームではこれらと同じ発想で新たにInternalなGatewayとして用意し、社内システム向けのサービスへのルーティングや認証・アクセス制限をここで実現しています。

Frontend Service

今回のプロジェクトは業務フローの見直しが目的の一つであったため、フロントエンドの刷新もマイクロサービスの一つとして開発しました。使用している主な技術としては以下のようになります。

特筆すべき点としては後述するGraphQL Serviceが後ろに存在するのでreact-apolloを使用してGraphQL ServerへのQuery/Mutationを行っています。さらにApollo ClientはClientのstateも管理できるので、reduxなどのフレームワークは用いていません。

GraphQL Service

このGraphQL Serviceは今回のプロジェクトを始める前に既に存在しており、Goとgqlgenを用いて書かれています。このGraphQL Serviceは各マイクロサービスから取得したデータを結合しフロントエンドに提供するBFFの役割を果たしているのと同時に、Apolloが提唱するIntegrity Principlesの一つであるOne Graphの思想に基づき、これから増えていくであろう社内システム各microserviceが持つデータにアクセスできるハブの役割も目指しています。

導入の背景としては同じチームメンバーである @icchy による MTC2018 – Customer Experience Improvement でも語られています。

Backend Service

ここは今回のプロジェクトでフロントエンドと合わせて新規に立ち上げたサービスです。このサービスは他のマイクロサービスと同様にGoとgRPCで書かれています。ここでは通報の生成から違反商品のマスク、お客さまへの制限など通報対応のドメイン範囲に限定したAPIを提供します。

このシステムを設計するに当たり、通報量は今後拡大していくであろうことが予想できたため、通報データの作成部分はPubSubとCloud Functionを通し、Cloud SQLに非同期にwriteすることでスケールしやすくしました。

他の多くのサービスではSpannerを使用していますが、私達のサービスではCloudSQLを選択しました。理由としては社内で使用するデータのみを扱うためそこまで巨大にはならないこと、既存のMySQLのクエリが流用できること、CloudSQLにはメンテナンスウィンドウによるダウンタイムがありますが、社内においてはそのスケジュールを調整しやすいため大きな問題にならないことが挙げられます。

リプレースしてみた感想

このプロジェクトをおおよそ6ヶ月に渡って開発を進めたのですが、そこで得た学びや感想をご紹介したいと思います。

幅広い技術のキャッチアップ

まず前提として、私達のチームのメンバーはバックエンドエンジニア4人で構成されています。実装が一番繁忙であった時期はフロントエンドエンジニアのヘルプを借りましたが、大まかな機能実装が終わったタイミングからはバックエンドエンジニアのみでフロントからバックエンドまでの開発を担いました。

私含めて上記で紹介した技術が初めてのメンバーも多く、新しいツールの仕様を把握しながら技術のキャッチアップも同時に進めていくのはとても大変でした。ただし、私達のチームでは各自が学んだことをメンバーにシェアする勉強会を毎週開催しており、そこで話すネタとしてキャッチアップをすることでモチベーションにも繋がり、結果的にほぼ全員が横断して開発を進めることができるようになりました。

複数のサービスを跨いだ開発

ここはマイクロサービス化していく中での弊害の一つかと思われますが、一つの機能を実装するためにDB Schema、protocol buffes、GraphQL Schemaを定義し、その変換部分を逐一開発していく必要があるのは開発のスピードを落とす一因になりました。今思い直しても将来の拡張性を考えると上記のアーキテクチャに行き着くだろうとは思いますが、人員の少ない中で管理するサービスが増えていくのはマイクロサービスのアンチパターンに近いものを思い起こさせます。

もちろんこの問題はチームメンバーも把握しており、将来的にはCSオペレーションのドメイン毎にチームを分け、よりマイクロサービスに適した組織編成にしていきたいと思います。

まとめ

今回はあまり表にはでてこないカスタマーサービスが使用するシステムについて、新しい技術への挑戦と苦労について書いてみました。メルカリではお客さまに安心して使っていただけるように目に見えない部分のシステムにも力をいれています。逆に言えば社内システムだからこそ大胆に技術に挑戦できる土俵があるとも言え、私達はそのようなチャレンジングな方と一緒に働ければ良いと思っています!

apply.workable.com