タイミーが抱えていた課題

須貝俊 氏:続いて、タイミーがどうやってモジュラモノリス化を進めているかというところをより具体的に話していきたいと思います。

(スライドを示して)課題としてはスライドに示したようなものがあって、コード上で何が何に依存しているのか把握しきれない状態になっていました。上記に伴う変更による影響範囲がわからない。また、エンジニアの増加に伴ってチームも増えていくため、チームの責任範囲を明確にしていく必要があるという課題がありました。

前提の部分ですが、タイミーのRailsアプリケーションはだいたい中規模程度のモノリスかなと僕は考えていて、テーブルの数でいうとだいたい200個ちょっと、モデル数が500個弱ぐらいです。

以前、マイクロサービス化を試したけれどモノリスに戻したような経緯もあって。そのあたりの経緯は技術ブログに書いてあるので、良かったら読んでみてください。

モジュラモノリス化の進行

packwerkを導入したのですが、先ほども触れた試行錯誤の容易さや依存関係の検査容易性を重視して、packwerkを選択しました。2022年10月から本番環境に導入しています。

誰が進めているかというところは、最初は弊社の20%ルールを活用して、僕がサイドプロジェクト的に進めていました。

その後、もう少しモジュラモノリス化を優先してやっていこうという話になって、2023年7月からはチームが組成されて進行しています。ただ、兼務でやっているので、ここはけっこう難しいなと感じています。

体制としてはCTO室所属のシニアエンジニアと私の2名で進めています。ここでようやくタイトルにも絡んでくる疑問のところなんですが、「モジュラモノリス化は誰が進めていますか?」というところがやはり気になります。

今ここで何か回答がほしいとかではなくて、あとで懇親会の時間にでも話せればなと思っています。

ドメイン単位の分割について

(スライドを示して)次に、どう分けるかという話です。やはりドメイン単位で分けたいというのがあったのですが、ものによっては機能単位の分割になっている箇所もあります。

これも疑問なのですが、「パッケージの粒度をどうしていますか?」というところがやはり気になるところですね。現在弊社では小さめの粒度で切っておいて、あとからまとめようと考えています。

理想は1チーム1パッケージみたいなところはあるかと思うんですが、問題領域とチームが一致しているような状態です。ただ、弊社では組織の流動性がけっこう高いので、そこにこだわりすぎると組織の変更に追従しづらくなるかなと思って、あえて小さく切っているという感じです。

(スライドを示して)続いて、どこから分けるかというところです。特に複雑になってきている、スポットワークシステム領域から分割を進めています。

分割にあたっては、まずはその境界の探索をチームで行いました。まず、「Timee」を使ってくださるワーカーさまやクライアントさまが利用する上で発生するドメインイベントみたいなものを、機能とかも全部洗い出して「Miro」に書き出しました。

その次にグルーピング化して、まとまりみたいなものをパッケージにして進めていきました。

続いて、そのスポットワークシステム領域の中でも、さらにどこからパッケージとして切り出すかというところです。まず、請求まわりから分割していきました。理由としては、ドメインが比較的明確でイメージしやすかったからです。

最初は、依存関係はある程度無視して進める想定だったのですが、内向きの依存関係が少ない箇所から進めるというのは、けっこう良さそうなアイデアかなと思っています。

たまたまですが、同じような例が『モノリスからマイクロサービスへ ―モノリスを進化させる実践移行ガイド』でも紹介されていました。僕が所属しているチームはまさに請求まわりを担当しているのですが、現状はほとんど該当のパッケージだけで開発が完結するような状況になっています。

(スライドを示して)現状は、packs配下に14個ほどパッケージが生まれています。ファイル数は全体で1,600個ぐらいあって、そのうちの500個弱ぐらいがpacks配下に移動されています。だいたい3割ぐらいですね。「GitHub」のコードオーナー機能を活用して、オーナーを明示しています。コードのオーナーによるapproveはまだ必須にはしていない状況です。

今後の取り組み

今後どうしていくかという話をしたいと思います。ある程度、パッケージとして成功しているものが生まれてきています。当初のコードの影響範囲の部分や所有権の部分みたいなものが、良い状況になってきているということです。

そういう状況を受けて、今はCTOから「もっと早く(app配下の)全部のコードをパッケージ分割してほしい」というオーダーを受けています。

これに対して、どういうアプローチをするかについては、大きく2パターンあるかなと思っています。引き続きモジュラモノリスチームがトップダウンで分割していくというのと、もう1つはボトムアップ的にチームが主体となって分割するみたいなところです。

それぞれのPros/Consを雑に考えてみました。トップダウンでやっていると、チームが兼務でやっているので、「100パーセントリソース投下してもいいよ」と言われても、ポジションの特性上、本当に100パーセントフォーカスできるのかみたいなところはあって、そこは悩ましい点です。

そして「パッケージ分割ってけっこう可逆性が高い」と先ほどから言っていたのですが、ある程度正解を探したくなっちゃうので、けっこう時間をかけて分割していくことになるかなというところがあります。

一方で、ボトムアップでやると、おそらくコンウェイの法則が加速するような状況になるのかなと思います。トップダウンで分割するよりは早く進みそうではあります。

結果はどうなったかというと、ボトムアップのアプローチでいくことになりました。具体的なやり方としては、app配下のコードの修正を実質変更不可能にして、強制的にパッケージに切り出すことをやろうとしています。

導入直後は絶対に開発生産性が落ちると想定されているのですが、ここについてはCTOと合意済みです。

けっこう実験味が強い取り組みなので、これはどうなるのかが僕もすごく気になるところなので、機会があればまた登壇するなり、ブログを書くなりしてやっていきたいと思っています。

packwerkを導入して悩んだ点1 Sorbetを入れるべきかどうか?

ちょっと時間が押しているのですが、最後にpackwerkを導入して悩んだ点を話そうと思います。

1個、たぶんやっていると悩む点として、Sorbetを入れるべきかどうかというところがあるかなと思います。SorbetはRubyの型チェックツールです。packwerkの仕組みとしてはソースコードをパースして定数を抽出して、その依存関係の違反のチェックを行っています。

だけど、そうするとメソッドの引数や戻り値は検査の対象外になってしまいます。

しかし、Sorbetを入れるとコード上に型を書くことになるので、packwerkの検査の対象になります。

ただ、タイミーだとすでにRBSやSteepを導入しているので、ここからさらにSorbetを入れるのかみたいなところは、今は躊躇しているところはあります。

あとは個人的な見解ですが、Sorbetを使ったRubyのコードを読むとわかるのですが、けっこう「これは本当にRubyなのか?」みたいな気持ちになってくるので、そこは抵抗があるところです。

次がアソシエーションですね。Railsのアソシエーションに非常に困っています。先ほどお話ししたとおりpackwerkは定数が検査の対象になりますが、例外としてRailsのアソシエーションも検出してくれるんですよね。

has_manyやbelongs_toを見て依存関係を検査してくれるのですが、ActiveRecordのassociationを経由すると他のパッケージのコードも普通に呼び出せるので、この検査自体は非常にありがたいですよね。

定義箇所は上記の検査でわかるのですが、そのアソシエーションを経由して実際にそれをどこで呼び出しているのかみたいなことを網羅的に検査しようとすると、けっこう大変です。

このあたりの話は、hacomonoさん(株式会社hacomono 志賀誠氏)の話でたぶん出てくるのかなと思うのですが、非常に参考になったので次の発表を楽しみにしています。

packwerkを導入して悩んだ点2 publicディレクトリをどうする?

もう1個はpublicディレクトリをどうするのという話があって、packwerkだと、packs/〇〇というパッケージの下にapp/publicというものを作ると、そこに置いたものは公開インターフェイス扱いになって、可視性のチェックの対象外になります。そうすると何をpublicなインターフェイスとして公開するかという話になります。

例えば、先ほどのアソシエーションが自由すぎる問題を解消しようとすると、リポジトリパターンを使って結果をPOROで返して、ActiveRecordのオブジェクトは返さないみたいなことが考えられます。一方で、そのActiveRecordのメリットが完全に失われることになるので、ここもけっこう悩ましいところです。

これはまさに最近freeeさんが公開していたスライドにも同じような話があったので、それもちょっと紹介したいと思います。

タイミーの場合は、パッケージ分割を先に進めているので、ドメイン境界がある程度固まったものに対しては、publicディレクトリをどうするかみたいな課題に向き合っていこうかなと思っています。一部のパッケージでは検証がけっこう進んでいるのですが、これからのフェーズかなという状況になっています。

最後にまとめです。タイミーはpackwerkを導入しています。気になった点については、懇親会の時などにぜひ話ができればと思います。また、配信で見てくださっている方も、僕のXでも質問や相談を受け付けているので、ぜひ話しかけてください。

以上です。ご清聴ありがとうございました。