自己紹介

すがわらまさのり氏:本日はSaaSのアーキテクチャについて、私の所属企業であるSmartHRの事例を紹介していければと思います。「SmartHR」は人事労務に関する処理をペーパーレス化できたり、人事データの一括・一元管理を行えるサービスを提供するSaaSです。

はじめに、簡単な自己紹介をさせてください。私はすがわらと言います。SmartHRに2年くらい在籍しています。職種はプロダクトエンジニアで、いわゆる開発をするエンジニアです。2021年の7月からチーフという役割をもらっていて、チームのマネジメント、1on1や評価を行いながら開発する、プレイングマネージャーという立場で働いています。

(スライドを示して)自己紹介ついでに少しだけ宣伝すると、趣味でRubyに関する本の執筆などを行っているので、こちらもよろしくお願いします。一応、趣味と書いていますが、実際はいつも半べそをかきながら書いています。というわけで、本日はどうぞよろしくお願いします。

「SmartHR」のサービス構造

アーキテクチャについて話す(前に)は、やはりアプリケーションがどういった特徴があるかを説明する必要があると思うので、簡単に「SmartHR」について紹介させてください。

私たちは「SmartHR」というサービスを提供しています。(スライドを示して)このあたりはインターネットに公開されている資料から抜粋ですが、特徴は人事労務業務の効率化や、人事データの一元化(をして)、それを活用できるクラウド型ソフトウェアです。

もう少し詳しく説明すると、入社手続きや引っ越し、家族ができたなど、会社が何らかの手続きをしなくてはいけないイベントが発生した時に、「SmartHR」を使うことで、オンラインでビシッとできて、従業員にとっても労務担当者にとってもいい機能を提供しています。

そういったイベントが積み重なることで、従業員のデータがどんどんたまっていきます。(スライドを示して)この資料でいう、上にある「従業員データベース」にたまっていきます。ここをいかにいい感じに蓄めていくかが、私が携わっているアプリケーションの機能となるデータや構造になっています。

さらに、蓄まったデータを活用できるということで展開しているのが右下の図です。従業員のデータがあるということは、社員名簿として使えるとか、店舗や小売業界ではアルバイトをたくさん雇う時に、各店舗に何名いるかなどを分析できるツールを提供しています。

(スライドを示して)「SmartHR」は、実は「SmartHR本体」と言われているアプリケーションと、各「分析レポート」「従業員サーベイ」などといった機能で別々のアプリケーションになっています。本体は一番大きなアプリケーションで、それ以外のことを「Plusアプリ」と呼んで区別しています。

(スライドを示して)それを簡単な図に表したのがこちらです。jQueryが気になるかと思うのですが、いったん目をつぶっていただいて。

左側が「SmartHR」の本体で「Core」と呼ばれている部分です。右側にあるのが「Plus」と呼んでいるアプリケーションです。ここの本体と「Plus」はRestAPIなどを使ってHTTPでアクセスする(だけ)にとどめていて、データベースの共有はしていません。

緑色の枠線では「文書配布」「年末調整」が枠1つで1リポジトリ。1Railsアプリケーションと考えてもらうと理解が進むと思います。

ここまでのまとめです。「SmartHR」では人事データを蓄めています。本体とPlusアプリがあります。この2つはHTTPで通信していて、データベースの共有はしていない状態です。

「SmartHR」アプリの本体が抱える「大きくてつらい」問題

ここまでは「SmartHR」の説明をしました。ここからは「SmartHR」というアプリケーションについて、もう少し詳しく説明していきます。

先ほど話した「本体」について話します。「SmartHR本体」は、普通のRailsアプリケーションです。ただし、まあまあ大きいという特徴があります。(スライドを示して)“でかい三銃士”をつれて来たよということで、「コードベースがでかい」「人事データに関するテーブルの規模がでかい」「関わるエンジニア人数がでかい」ということを挙げています。

もう少し具体的に見ていきます。(スライドを示して)例えばコードベースに関して、これは雑にrails statsした結果を持ってきたのですが、だいたいトータルで50万行ぐらいあります。スペックの割合が多いのは事実ですが、そうは言ってもコードを修正する時はテストで一緒に見直していくので、50万行だとまあまあの迫力がある状態になっています。

また、「人事データに関するテーブルの規模がでかい」ということで、人事データを蓄めるところで、関連するデータやテーブルがけっこうあります。ざっと数えた感じだと30個以上で、全体的に言うと200個以上あります。

例えば、人事データに関してどんな関連テーブルがあるかと言うと、住所の情報や所属している部署、開発、マーケティングなどの部署情報を持つためのテーブルが関連テーブルとして存在しています。

ほかには、導入したお客さまごと、人事データとして保存するデータをカスタマイズしたいという要望があります。例えば資格や免許が必要な業種業態だと、誰がいつ資格を取ったかというデータを保存しておきたかったりします。

そういったことに対応するために、お客さまが自由に保存項目を作れるカスタムデータを作るためのテーブルもあります。また、テーブル数が多いだけではなく、そういったカスタムデータの組み合わせという複雑なものもあります。

さらにこれは余談になりますが、データモデルとして「Bitemporal Data Model」を採用しています。これに関する説明は、話がすごく長くなるので割愛しますがこれを採用している関係もあり、「テーブル数が多い×データモデルが複雑」というところで、ちょっと複雑度が高い感じです。

「関わるエンジニア人数が多い」。今30名ぐらいいます。ただ、実際には30名が好き勝手に開発しているわけではもちろんなく、「LeSS」と呼ばれる、スクラムを大人数で扱えるように拡張した手法をとって、複数チームに分かれて開発をしています。

それはそれとして、1railsアプリケーションに対して30名が日々開発しているのはまあまあの規模感なので、実際には足並みを揃えて開発していくことに対するコスト感も課題として挙がってきています。

事業の規模とともにアプリケーションを取り巻く環境も大きく成長してきたので、「大きくてつらい」という感じが迫ってきています。

「大きくなりました」が、まだまだ開発したいものはたくさんあります。今リリースしている機能も自分たちの理想に追いついていないものがたくさんあって、もっともっと開発したいです。そして、足りないものを開発するために、人数もコードベースも増えてきました。このままこのペースで走っていけるのかも、けっこう目の前の問題になっているかというところです。

(スライドを示して)現在、いわゆるモノリシックアプリケーションとして成長してきた「SmartHR」ですが、プロコン(Pros/Cons)を出すとこんな感じで、「Pros」は普通のRailsアプリケーションでなんとかなるというのがあります。

一方で、「大きくてつらい」のは、懸念として、これからどんどん大きくなっていく課題を抱えています。

「大きくてつらい」を解決するための共通認識作り

これに対してどう取り組んでいくかを今日は伝えていきたいと思います。

このままだと緩やかに身動きが取れなくなってしまいそうだというところで、「SmartHR本体のアプリケーションを長期目線で考えて、何か打ち手があるかを検討する会」を社内で発足させました。

とはいえ、集まったメンバーもそれぞれつらいと感じているポイントが異なるので、まずは「何がつらいか」と、「こうだったらいいな」というものを出して、認識を揃えることをやりました。

(スライドを示して)これは実際にホワイトボード的なものにいろいろ書き出した図です。公開していい範囲で少しピックアップしてみます。

例えば影響範囲が広いとか。コードベースもそうですが、アプリケーションの機能もたくさんあるので、影響範囲を読み解くのが大変だという話であったり、前述した人事データに関するテーブルやデータなどの絡みがあるとハチャメチャに大変ということがつらみとして書いてあります。

思い思いにみんなで付箋を貼ったのですが、グルーピングしていくと問題の方向性がだいたい見えてきました。そこで、いくつか問題の方向性を整えつつ、改めてつらいポイントを出してみました。

「こうだったら良いなあ take2」で、仕様の理解が困難だとか、影響範囲が大きいといった軸に沿って、何が問題なのかをあらためて発散させていきました。勘のいい方は気がついたかもしれませんが、今回のスライドのタイトルに使っている「大きくてつらい」はこの発散会を通じて生み出された言葉です。

「大きくてつらい」から、だんだん何が問題かわかってきました。わかってきたというか、薄々気がついていたのですが、参加者全員で解決する問題として捉える共通認識が生まれた感じです。

「大きくてつらい」例として、「つらい」はアプリケーション全部を理解するのは難しいという話だったり、複数のチームでそれぞれ大きな開発をしていると、どうしてもほかのチームで何をやっているかがあまりよくわからないということが起きたり、お互いの開発でソース的な意味や仕様的な意味で影響し合ったりということもあります。

「よさそうなもの」からメリット・デメリットを考える

では、それをどう解決したらいいのかという例を挙げます。「大きくてつらい」という問題なので、小さいとうれしいのです。例えば、別サービスとして完全に分けてみたらどうかとか、rails engineなどを分けてみるとか、1つのアプリケーションの大きさを小さくしようとする案がいくつか出ていました。

そういったよさそうなものを、いったん冷静に、どういったメリット・デメリットがあるかを話しています。

例えば「こういう機能はあまり手を入れないし、切りやすいよね」という話も出たりするのですが、一方で「簡単に切り出しやすい機能を切り出しても、うまみが少ないのではないか」とか、一方で「どんどん切り出していくのであれば、練習としてそういったところからやっていくのもいいかも」という話が出たりしました。

また、そもそもの話として、我々が開発しているアプリケーションのコア機能は何かみたいな、哲学的な問いが生まれたりしています。

コア機能が何かを考えるにあたって、エンジニアだけで考えてもなかなか答えにたどり着けないと感じられました。

今後の開発方針などにさまざまな観点を入れたほうがとさそうだということで、PM陣を何名かも交えて、実際に機能やデータ構造を図に落とし込んだりして、「この機能はコアに含まれる? 含まれない?」などを検討していきました。 その結果、我々の「SmartHR」のコア機能は何かについて、一定の共通認識を得ることができました。

コア機能とそれ以外の機能もわかったことで、アプリケーションの切り口もだいたいわかってきました。しかし、前述した懸念点は変わらず、メンテナンスされない機能を切り出す時のメリットは、コストを上回る想像ができませんでした。

単にアプリケーションを切り出すだけだと、メンテナンスが大変です。切り出したアプリケーションに対してRailsをアップデートしなければいけないとか。「逆コンウェイの法則」に基づいて切り出した場合、「あまりアクティブではない機能に対してチームを割り当てるなんて何なの」という話にもなってくるので、いわゆるマイクロサービス的な打ち手だとちょっと難しいかもしれないというのが、この時の結論になりました。

アプリケーションの特性をもう一度考えるという意味ではとても有意義ですが、もともと解決したかった問題に対しての答えにはならなそうだというのが、この場での結論でした。

とはいえ、何らかの答えも出したいというところで、今まで理解を深めていた結果をもとに、もう一度何ができるかを考えてみました。このあたりは正直打ち手が見えなくて、しんどいと思いながらやっていた部分はあります。そこで、今後を見据えたリファクタリングは、今できそうだという話が出ていました。

ここまでだと「アプリケーションを分ける」という話ではなく、リファクタリングだったら地に足のついた感じで進められそうだということで、その中でモジュラモノリスという案も出てきました。

知見はあまり我々にはないのですが、ひょっとしたらモジュラモノリスは銀の弾丸なのではとちょっとざわつきました。リファクタリングの方向を考えつつ、モジュラモノリスについての解像度を上げていくといいのかなというのが、この場での結論になっています。

ここまでのまとめをすると、マイクロサービスに切り出すことは今ではなさそうです。一方で、テーブルの構造の見直しや、大きめのリファクタリングと向き合うのは、今後の展開も考えて価値がありそうという一定の見解を得ました。

また、話の途中に出たモジュラモノリスに関してはよさそうな気がするものの、まだまだ知見が足りないということで、この会議体のメンバーで各自の解像度を高めつつ、もう少し検討してよいかもしれないという状態になりました。

リファクタリングをどう進めるか

方向が絞れてきたので、リファクタリングとモジュラモノリスについて、2軸で進め方を検討してきました。

「リファクタリングどう進めよう(か)問題」ということで。ここまで取り組んだ断片的なリファクタリング候補が出てきたので、そこからどうリファクタリングに値する強度のものを抽出して、優先度を見ていくかを考えました。

とはいえ、リファクタリング自体手間で進められるようなものではないものも多いので、一方で、まずはコストとベネフィットをマッピングすることで優先度を検討してきました。ここで「コスト感が少なくて、うれしい度が高いもの」はすごくお得なので、そういうのをやりたいという思惑がありました。

実際にやってみたのですが、だいたいベネフィットとコストは揃ってしまいます。そのため、あまりお得なアイテムではなく、がんばってやっていくような感じの結論になってきています。

ここに挙がったリファクタリングの具体例としては、テーブルが複雑に分割されているものを統合できないかとか、新画面と旧画面の2つの画面が残っていて旧画面でしか使えない機能が残っていて消せないことをどうにかできたらいいというのがあります。

でも結局、着手するにはリソースやタイミング、ほかの機能も開発の兼ね合いなどを見ながら地道にやっていくしかないだろうという結論になりました。リファクタリングに関しては、やれる箱を見ながらやっていくのがいいだろうということです。

モジュラモノリスについての検討

モジュラモノリスについても並行して検討を進めてきました。モジュラモノリスが何かをすごく大雑把に説明すると、デプロイ単位の1つのアプリケーションの中でコンテキスト単位でモジュールの境界を分けていて、越境するお互いの公開APIを介することで依存関係を明らかにする方針を取ります。

実際、僕らはあまり知識がないので、Shopifyの例を見ながら独自に情報を咀嚼して、どのように適用できるかを検討しました。いくつかメリットや懸念点が出てきたものの、自分たちに経験がないので、決め手に欠く状態に陥ってしまいました。

その時、当時CTOで2022年からCEOになった芹澤(芹澤雅人氏)が、ウルテクを使って実際に導入している企業から話を聞けるチャンスを作ってくれました。スカラーで実践している会社と、Railsで実践してる会社の2社からヒアリングをさせてもらいました。両社ともモチベーションは複雑な依存関係を解決したいということで、そのためのアプローチとしてモジュラモノリスを採用していました。

一方で、モジュラモノリスできっちり分けていくという意味だと、早いうちから意識的に選択肢を取っていくか、やれるところからやっていってなんとかやりきることを考える感じが大切だという知見を得られました。その節は貴重な話を聞けて本当に参考になりました。

そういった知見を得つつどんな結論を出したかと言うと、みんな試行錯誤しながら進めているんだなということや、そうは言っても銀の弾丸ではないという、当たり前のような感想が出ています。実際、有望な選択肢である認識はありますが、一方でそれに伴う覚悟も必要そうだというところで、やりきるためのある程度の準備は必要だろうという感触を得ました。

現在は短期組成したチームで対応中

ここからが結論です。(スライドを示して)「大きくてつらい」に対する我々のアプローチはこうなりました。現在は、今のモノリシックアプリケーションのままで行くことになっています。

ただ、リファクタリングをすることが次の一手として選択されています。

リファクタリングを進めていくのを、やっていくぞという気持ちだけでは解決できません。できるならとっくにやれているので。そうすると、どうやって進めるのかという問題が出てきます。

組織的にどう進めるかという課題になっていくので、そこをテコ入れしたほうがいいというところです。実際にやることが明らかな場合は、スクラムチームに入れてやってもいいと思うのですが、やれるかどうかわからないものや非常に大きなものだと、スクラムチームのタスクにバッと入れるのは難しいです。

一方で、あるチームの特定のメンバーだけ別のタスクをやるのは、スクラムチームとしてはちょっと動きにくいという問題があります。なかなかシュッと進められそうにないところがありました。

そのため、「SmartHR」ではこんな感じの対策をして進めようとしています。「LeSS」を使っているのですが、そことは別に短期間、別チームを組成しました。そこでは今後の開発の足かせになりそうな部分の整備や、リファクタリング、先ほどのテーブル構成の変更なども実証実験を踏まえながら変えられるところを調査したり、実際にやってしまうところを目指した別チームを設けて進めています。

そして、お決まりの「大きくてつらいこと」を私たちと一緒に解決したいと思った方の応募を待っています。直接私にコンタクトを取ってもらっても大丈夫なので、ぜひよろしくお願いします。「みんな一緒にリファクタリングがんばっていこうな」ということで、ご清聴ありがとうございました。