マルチプロダクト戦略の実現を目標として掲げ、急速にプロダクトを増やしているSmartHR。
そのような中、これまでプロダクトごとに分断されていたデータを相互に利用できるようにすることで、価値を高める試みが始まっています。この活動の中心となっているプロダクト連携ユニットに、現状と今後の展開を聞いてみました。
f440: それでは、プロダクト連携ユニットのインタビューを始めたいと思います。よろしくお願いいたします。
一同: よろしくお願いします。
f440: お時間を取っていただきありがとうございます。突然呼ばれてびっくりしていると思うんですけれども、個人的に一番興味あったのがプロダクト連携ユニットだったので、この度はインタビューしたいと思いまして。
最初に自己紹介から始めさせてください。まずは私から。現在プロダクト基盤開発部で作業をしているf440です。権限周りを担当していて、例えば、ある従業員がこのシステム上ではこういったことが出来る、といったことを管理するための仕組みづくりをしています。
2018年入社で、今日参加してもらっているmotsatさんとは同じ月に入社しています。入社当時はSmartHRの基本機能を開発していて、そのあとオプション機能、そして現在の基盤づくり等、ひと通り開発してきているので、データ基盤チームがやってくれていることの意義も理解しているつもりですし、期待も大きいです。今日はよろしくお願いします。
次は、motsatさんお願いできますか?
motsat: はい。f440さんと同じ月に入社で、SmartHRの基本機能と呼ばれている部分のバックエンドエンジニアとしてだいたい4年ぐらい機能開発や負債解消に取り組んでいました。直近だと、今日インタビューさせてもらうプロダクト連携ユニットが作ったものを使って、キャリア台帳という最近リリースされた機能を開発するチームにいました。現在は非公開の新規プロダクトを開発しているので、そこはゴニョゴニョとしてもらえるとあれなのですが……。
一同: (笑)
motsat: そんな感じで過ごしています。以上です。
f440: それでは、プロダクト連携ユニットのkinoppydさんからお願いします。
kinoppyd: kinoppydといいます。2019年の9月に入社して、そのときはおふたりとは違って基本機能ではなく、らくらく分析、いわゆるBIツールのようなプロダクトのチームでエンジニアをやっていました。その後、今のデータ基盤チームのプロダクトマネージャーから「各チームのアプリをどうやって繋げればいいか」のプロトタイプを作りたいから協力してほしい、と声をかけられて。そのまま今のプロダクト連携ユニットの立ち上げから参加しています。それが2022年7月とかなので、だいたい2年くらいやっていますね。
プロダクト連携ユニットでは、各チームのデータを連携するための仕組みやそれを管理する方法を設計したり、プロダクトを横断した検索を提供するためのシステムを作ったりしてます。よろしくお願いします。
f440: 次、ikuto0608さんお願いします。
ikuto0608: ikuto0608です。よろしくお願いします。20年入社なんですけど、3年経つのにここでは新参者という……。
kinoppyd: 1年しか変わらない(笑)。
ikuto0608: 最初僕は、労務機能にジョインして、そこでは権限改善をしたり、APIの改善をするチームに1年ちょっといたと思います。そのあと、今のプロダクト連携ユニットの前身のチームにジョインしました。従業員情報を各プロダクトから集めて返す連携プロダクトについては作り始めて2年経つのかな。よろしくお願いします。
プロダクト連携ユニットの発足
f440: では早速ですが、プロダクト連携ユニットから話を聞く前に、現在SmartHRがどのような構成になっているのか、変遷を踏まえて説明しておきたいと思います。
SmartHRが会社として、またサービスとして始まったのが2013年頃で、当時は創業メンバーたちが作ったRuby on Railsのアプリケーションとして存在していました。無事サービスがどんどん拡大していき、利用者も増えて機能も増えるに従って、今後アプリケーションをどのように拡張していくのか、みたいな問題が当然起きてきますよね。時代的には大きくなってきたらAPIとしてマイクロサービスに切り出すみたいなことがブームだった気もするんですけど、僕たちとしては、新機能や基本機能の一部を独立した別のプロダクトとして切り出していくことを選択しています。これにより、独立したリリースサイクルを実現したり、それぞれに開発チームを組成したり、といった動きができるようになりました。具体的には、新機能として文書配布機能をつくったり、既存機能の年末調整機能を切り出したり、ですね。これによって開発チームを増やしていきやすくなり、今振り返ってもこの判断はとても良かったと思っています。
それからまた数年経つと、プロダクトが沢山あることによる課題が生まれてきました。1点目としては、プロダクトを横断して提供したい機能が生まれてきました。例えば僕がやっている権限のような、いろんなプロダクトを通じて提供することに価値が生まれるような部分ですね。2点目として、今回のテーマのデータ連携のような、プロダクト間で相互にデータを参照したい、といったニーズが生まれてきたのが最近の状況かと思います。というわけで、データ連携については皆が非常に期待しているので、今日のインタビューも楽しみです。
f440: それではさっそく、プロダクト連携ユニットに色々聞いていきたいと思うのですが、まずチームとしてはどのような構成になっているんでしょうか? 人数だったり、人となりだったりを教えてください。
kinoppyd: チームの構成は、プロダクト基盤開発部という大きなグループがあって、その中の1つのユニットとして存在しています。我々のプロダクト連携ユニットの他に、f440さんがいる権限基盤ユニットであったり、サブスクリプションの管理をするサブスクリプションユニットであったり、従業員のデータを専門に管理する従業員データユニットであったりと、今は4つのユニットがあります。
プロダクト連携ユニットは今3人で、もともとは私とikuto0608さんの2人で始めたチームでした。そこに先月1人ジョインしました。そして、プロダクトマネージャーとしてデータ基盤チーム全体を見ている疋田さんと、チーフとしてmeganemura……藤井さんという方がついている形です。
f440: 名前は後で変えられるので全然大丈夫です(笑)。人もどんどん増えているフェーズっていうことですね。会社としても力を入れている部分だと思うので、今後も増えていきそうだなという感じがしています。
kinoppyd: そうなってほしいですね。
f440: 最初は「ちょっとデータ連携やってみない?」みたいな感じで声をかけられたのですか?
kinoppyd: 一番最初は、今のプロダクトマネージャーの疋田さんが「プロダクト間のデータを連携するのにいくつかアイディアがあるんだけれども、どの方法を取ればいいのか悩ましいから検証のために手伝ってほしい」ということで、もともと居たチームから1ヶ月、貸し出された形で技術検証に協力しました。そのままいくつか技術選定とかプロトタイプ作成をやった後に、このまま続けてほしいという形になったので「じゃあ、会社のために頑張ります」ということでチームを抜けて合流しました。そのときにikuto0608さんも一緒に手を上げていただいて、2人でチームを始めた形です。
f440: 弊社あるあるですね。技術検証をしていたらいつの間にかチームになっていた。
kinoppyd: 僕は借りパクと呼んでいます(笑)。
f440: (笑)
具体的にどのような問題を解消するため、プロダクト連携ユニットは生まれたのでしょうか。
ikuto0608: そうですね……。当初SmartHRは労務領域向けのプロダクトでした。基本機能の中に従業員情報が溜まっていき、そこから必要な従業員情報をAPIを通して他のプロダクトに利用するような世界観だったんですよね。しかし、今では労務だけでなくタレマネ(タレントマネジメント)というもう一つの大きな柱がある。加えて、プロダクトもたくさん増えてきています。
そうなってくると、「あれ? 従業員情報って別に基本機能だけに溜まっているわけじゃないぞ?」ということに気付き始めたんですよね。例えばサーベイ機能の場合、溜まっているサーベイ結果から出てくるエンゲージメントスコアを使いたいよね、みたいなモチベーションがぞくぞくと湧いてきて。基本機能以外に溜まった従業員情報も、集約して他のクライアントアプリからとれる、みたいな世界観を叶えるためにこのチームが組成されたという認識です。
f440: なるほど。サービスの急拡大に対応するために生まれてきたのですね。
プロダクト連携を支える技術
f440: ここからは具体的に技術寄りの話をしていきたいと思います。どういったテクノロジーを利用して問題を解決しようとしているんですか?
kinoppyd: 我々が採用したのは Apollo Federationという製品です。具体的には、GraphQLのエンドポイントを各サービスが持って、そのエンドポイントを1つのスーパーグラフという形で1つにまとめます。利用者が Apollo Federation にアクセスすると、必要なデータをどのサービスから持ってくれば良いのかを判断して集めてきてくれるようになっています。
f440: これまでSmartHRの内部通信ではほとんどのケースでREST APIを採用していたと思うのですが、今回Apollo Federationを使ったGraphQLフェデレーションでいこう、というのはすんなり決まったのか、あるいはその過程で他にもなにか候補はあったのでしょうか?
kinoppyd: GraphQLフェデレーション以外に、データレイクを作ってそこにデータを定期的に同期して各アプリケーションから直接参照するパターンと、API Gatewayを使ってREST APIを集約しようみたいなパターンも選択肢としてありました。
その中でGraphQLフェデレーションを選択した理由としては、やっぱりクライアントとしてはデータのリアルタイム性が必要ということで、データレイクは早々に選択肢から外れたんですね。残るRESTとGraphQLのどちらとなったときに、クライアントが必要な情報だけを選択してデータを絞って取得できるという点からトラフィック面で有利なGraphQLが有力となりました。また、Apolloが提供しているApollo Studioでスキーマを管理できるので、管理面の容易さでもGraphQLを採用したほうが良いという形になりました。加えて REST APIに関して言うと、既に内部向けの REST APIが存在していたので、これをフェデレーション用に改修してしまうと後戻りが困難です。GraphQLのエンドポイントを新しく作る方法であれば、例えうまくいかなかったとしても実装を簡単に捨てられそうという判断もありました。
f440: なるほど。GraphQLって聞くとサーバーとブラウザやモバイルアプリとの通信みたいなイメージがあったんですけど、サーバー間連携にも使えるんですね。
kinoppyd: そうですね。さっき言った通りユーザーが選択したデータだけを取れるので、通信のコストを抑えたりとか、必要なデータに関して計算を行わないという面で、バックエンド同士での通信でもかなり有効です。また、きちんとスキーマが定義されるので、破壊的なことをしづらくメチャメチャなデータにならない点でも利用しやすいと思っています。その反面、GraphQLはやはりフロントエンドに対する知見は溜まっているのに対して、バックエンド同士で使おうとした時に知見がなくて最初の設計が難しく、かつ今もちょっと負債を抱えています。例えば、ページネーションなどの技術がバックエンドだとあまり適さないですね。
f440: たしかに、クライアント相手だと表示に必要な僅かな件数で済むんですけど、サーバー間だと大量にデータを取ったりするような局面も多そうなので、別の問題がありそうですね。
f440: Apollo Federationっていうのは、有償のソフトウェアですか?
kinoppyd: 有償のSaaSです。GraphQLフェデレーションを使う上でApollo Routerというものを我々は使っているんですけれども、それ自体はオープンソースです。Apollo Federation は、Apollo Routerが生成する情報やスキーマなど、様々な部分を管理してくれるサービスです。クライアントの管理や利用の統計も取れます。
f440: 僕は Apollo Client は使ったことがあったんですけど、Apollo Federationっていうのがあるんですね。
kinoppyd: そうですね。Apollo社はGraphQLが非常に強い会社で、いくつかデファクトスタンダードと言われるようなものを作っています。
f440: 僕たち以外にApollo Federationを使っているサービスって、あんまり聞かないですよね。導入するにあたって情報が足りなかったりして困らないのかなっていうのが気になりました。
kinoppyd: 端的に言うと困りましたね。困りましたけど、そこまで難しい話はなかったと思います。既存の技術の延長線上の話なので、ある程度ノウハウがある部分ではある。加えてフェデレーションする部分はApolloの独自規格なんですけども、そこだけ把握できればどうにかなるっちゃなる。ベースはGraphQLなので、データの流れとかは見える。ある程度自分たちでトレースすることは出来るので、そこまで何もわからなくて大変だったということは無いです。どちらかというと、どういうスキーマを設計するかとかの方がはるかに大変だったかな。
f440: 単純に使うことよりも、組織への展開みたいな、各チームにどうやってそれを浸透させるのかみたいなのは気になるところだと思います。このあたりはikuto0608さんに聞いていきたいんですけど、どういった形でGraphQLフェデレーションを他のチームに……多分、GraphQLのエンドポイントを皆に作ってもらうみたいなことをしなきゃいけなくなると思うんですけれど、スキーマの管理、そのあたりってどうやって進めていきましたか?
ikuto0608: そのあたりは今も改善中なんですが、始めた当初の願いとしては参加してくれるアプリが、比較的低い・少ないコストでフェデレーションに参加してもらうことを目的にしていたので、ライブラリを作りました。ファイルを生成することで、少ない工数でGraphQLのエンドポイントを立てられて、認証・認可とかもできるようにしました。あとはドキュメントを手厚くして、「こういったふうにフィールドを足すと動くんだよ」とか「フェデレーションの立ち上げ方はこうだよ」といった、ゼロからでもわかりやすく立ち上げられるようにすることは念頭に置いていました。それでも詰まったりするところはあると思うので、積極的にコミュニケーションを取るようにもしていました。
f440: 実際にプロダクトに組み込む側としてmotsatさんは経験があるかと思うのですが、やってみてどうでしたか?
motsat: 基本的には、使う側としてはGraphQLのクライアントになるっていうだけで、そんなに難しいことはなかったです。GraphQLの経験者がチームにいなかったというところにハードルが多少あったぐらいなんですけど、組み込み方とかスキーマとか開発環境がどうなっているかとかを親身にレクチャーしてもらえたこともあり、ハードルは全然高くなかったです。ただ、さっき話にあがったページネーションとかは、そのあたりをどうしたもんだろう、みたいなところはありました。でもそこも認識を合わせたくらいで、とても困ったみたいなのは全然無かったですね。
f440: え〜、じゃあすんなりいっちゃったんですね。
一同: (笑)
kinoppyd: すんなり行くためには結構たくさんドキュメントを書いたりとか、コミュニケーションを密に取ったっていうところが大きいんです。
f440: ちょっと困った話とかも聞きたいと思っていたんですけど、すんなりいっちゃったということで……どうしようかな……。
Apollo Federation経由で他のプロダクトのデータを取るようにしたことによる効果や問題点は見えていたりしますか? 僕の想像なんですが、GraphQLだとリクエストされる側って負荷が読みづらかったりだとか、想定されていない使い方をされちゃうみたいなトラブルが起きたりしてないのかな、と。そのあたりはどうでしょう?
kinoppyd: 負荷に関していうと、現状だと限られた利用しかされていないので、そこまで危険な水準までいってないです。アプリケーションの負荷に関しては我々はあまり感知できないんですけども、トラフィックの流量であったりとか、エラーのレートとかはモニタリングしています。いまのところエラーはほとんど出ないですね。
困った側面でいうと、例えばサーベイアプリが持っているエンゲージメントサーベイのスコアはデータベースに保存されていなくて、都度計算してユーザーに提示する値なんです。それを全従業員分一気に取得するとなると、全従業員分の計算が走ることになります。こういったGraphQLでデータを提供するには適していないデータ構造のプロダクトもまだまだあって、そこでどういうふうにパフォーマンスを上げていくか、今後課題として直面すると思います。
あと、検索で従業員情報の整合性で大きな課題がありました。アプリケーション間でデータの同期を行っているのですが、リアルタイムに通信するのではなく、基本機能から各プロダクトが従業員情報をAPIで吸い出して自分たちのデータベースに保存して……とやっているため、保存していない従業員も当然発生してきます。そうなると、検索時に各サービスが検索した結果を結合しても不整合が起きたりするわけなんですね。データベースは物理的に分かれている状態でどのようにアトミックな検索を実現するかに課題を抱えていました。
f440: それはなかなか難しい問題ですね。
motsat: 利用側でも、取得先のサービスがパフォーマンス的に重くなることがありました。この場合、GraphQLで本当は一発で取れるようなものを、UI上特定のサービスごとに取るみたいな設計にして回避しました。取得先のレスポンスが速くならないとどうにもならないところではありますね。
f440: なるほど。場合によってはアプリケーションの仕様を見直すこともありそうですね。
プロダクト連携ユニットの今後
f440: 今考えている「今後こうしたい」「ここが問題になっているので、解消しようと思っている」みたいな、改善であったり展望であったりってありますか?
ikuto0608: 検索の話をしますか……。検索は今なかなか、クライアント側にも苦労をかけていますね。
今出来ることとしては、検索値をフィルターで与えると、それにヒットする従業員のIDの配列を全部返すという結構ワイルドなことになっています。なぜそうなっているかというと、「正社員の人でかつ、こういうスキル情報を持っている、またはこういうスキル情報を持っている」みたいな検索が想定されるんですが、基本的にGraphQLフェデレーションってGraphQLのエンドポイントが個々に立っていて、そこから必要なフィールド情報を吸い上げている仕組みなわけです。正社員情報が基本機能のデータベースに溜まっていて、スキル情報・スキル管理アプリはこのデータベースに溜まって、みたいになっているので、それらを横断して AND / OR 条件で繋ぐのが難しく、さらに検索するときってたいていページネーションさせたくなるけど、それができず……。そのため、全従業員を返して、クライアント側で頑張ってもらうみたいなことをお願いしているんですが、しばらくそれは続く予定で……す。
一同: (笑)
f440: 解消しようと、今策を練っているところですか?
ikuto0608: 解決に向けて動いているんですけど、その話をしだすとGraphQLフェデレーションから話がズレてしまうので……。
f440: ズレても大丈夫です(笑)。
ikuto0608: GraphQLのレイヤーで結合して複雑な検索っていうのは無理だとわかったので、フェデレーションのレイヤーを1個下げようとしており、データベースフェデレーションを今検証中で、そろそろ導入できるところです。
考え方はGraphQLフェデレーションとおなじです。データベースフェデレーションの場合はデータベースのレイヤーとして入口となる一つのSQLエンジンを見立てて、実際は複数のデータベースに取得しに行って統合されるようになります。このデータベースフェデレーションの中でいい感じにページネーションとかAND / OR検索をしてくれるので、そこに頼りつつ。そうすると複雑な、僕らがしたい検索が叶えられるなっていうのが見えているので、その実装を始めています。
f440: そうなると検索エンジンみたいな準リアルタイムではなく、本当にリアルタイムでデータベースを組み合わせて使えるようになる、と。
ikuto0608: そうですね。
f440: データベースフェデレーションではどんな技術を使うのですか?
ikuto0608: Trino っていうオープンソースのソフトウェアです。
f440: ああ、7月10日の ミートアップ で ikuto0608 さんも登壇されるとか。簡単に説明してもらってもいいですか?
ikuto0608: Trinoはもともとはアナリティクスなどのために生まれたもので、大きなデータセットがある中で、リアルタイムに処理をするために作られました。構成としては、1つのマスターノードがあって、そこにぶら下がる形でいくつものノードのインスタンスを立ち上げることができるんですよね。そして、いろんなデータベースからデータを取得して、各ノードのメモリ内でジョインしたり、ソートしたりしてくれて、SQLのクエリをもとに結果を返却してくれます。
複数のアプリがあって、それぞれ違うデータベースに溜まったデータが存在している状況で、さも1つのデータベースに集約しているような感じで取得できるので、僕らに合っていたんですよね。そういったところが「いけるな」「使えそうだな」と選択した理由です。
motsat: 既存のREST APIによる内部通信の仕組みはフェデレーションを使った仕組みに一本化していくイメージですか?
kinoppyd: 置き換えられるんじゃないかなと思いますけどね。どうなんでしょう?
ikuto0608: その世界観の方がシュッとしてて良さそうなのは間違いなさそうなんですよね。
f440: 最終的には外部公開も?
kinoppyd: 作り始めた当初からいつか公開することになるだろうという話はしています。
ユーザーから見ればSmartHRにデータを入力しているはずなのに、内部ではどのアプリケーションで入力したかによってデータは分断されています。これはサードパーティーでアプリケーションを提供してくれる方々にとってもよくないので、いずれは開放したいとは思っています。
ただし、主に権限であったり、認証・認可であったり、セキュリティ面でも大きいハードルがあるということと、今のスキーマが最高のスキーマだとは思っていないのでそこはある程度整備してからじゃないと、人には渡せないという考え方もあります。いずれできるといいなと思っています。
motsat: 楽しみですね。めっちゃ夢がありますね。
kinoppyd: ただ、外部からのインターフェースとなるためには、それを意識して各プロダクトも準備をしてもらう必要があります。今までのような、どこかのチームのために必要なのでAPIを用意する、といった特別扱いはできなくなるので、マルチプロダクト時代のデータ設計をしないといけない。我々もまだ正解が見えていないので、ガイドラインを作りつつ各チームに提供していく、といったことを公開までにしていく必要がありそうです。
f440: 道のりは長そうですが、可能性を感じます。
ikuto0608: 今のSmartHRみたいに複数のプロダクトがあって、それぞれが受け持つビジネスドメインがあり、それを開発するチームがある。GraphQLフェデレーションだと、プロダクトがGraphQLエンドポイントを持つようになるので、チームの自律性が高まるんですよね。
GraphQLフェデレーションの選択は、自分たちのチーム構成にすごくマッチしていると思っています。
f440: お話を聞いていても、プロダクト間連携についての未来にワクワクさせられました。本日はありがとうございました!
We Are Hiring!
現在SmartHRでは、プロダクトをより高速に生み出すために開発を促進するための仕組み作りを積極的に行なっています。
基盤作りに興味がある方、ぜひ一緒に働きましょう!
写真:小山田 法師