2024.10.21
お互い疑心暗鬼になりがちな、経営企画と事業部の壁 組織に「分断」が生まれる要因と打開策
リンクをコピー
記事をブックマーク
志賀誠氏:じゃあ今度は、モジュラモノリスの実現の方法について説明します。(スライドを示して)Railsでモジュラモノリスを導入するにあたって、パッと思いつくもので、このスライドにあるような問題があるかと思います。
1個は、やはりRailsはRubyなので、なんでも書けちゃうということがあると思います。もうやろうと思ったらいくらでも越境できちゃう境界区域とかがあると思います。
もう1個はActive Recordが強力ですよね。「Arel」もあると思いますが、けっこう自由に書けるので、「どこのテーブルに対して何のクエリを投げる」という制限をかけるのを真面目にやろうとするとなかなか大変だというような思いがあって。このあたりをhacomonoでどんな感じで対応したのかを説明します。
弊社も例に漏れずにpackwerkを使っています。packwerkの詳細については先ほどタイミー社さんから説明があったので、私のほうでは触れる程度にします。
弊社の場合だと、packagesみたいなディレクトリを切っていて、その中にパッケージを何個も作っているような状態です。論理的分割をしています。弊社もタイミー社さんと同じで、パッケージごとにコードオーナーを設定しています。これによって、「『GitHub』でほかのチームが修正した」とか、そういったことを検知できるようにして、安心して運用できるようにしようという取り組みをしています。
(スライドを示して)packwerkはYAMLでルールを設定するんですが、ざっくりとここに書いてあることができるようになっています。「エントリーポイントを外部のパッケージに公開するメソッドがこれですよ」みたいなものを定義できるエントリーポイントの定義と、パッケージが依存できるパッケージ。例えば「共通基盤パッケージ」と言えばいいですかね。メール配信だったりの共通の機能は依存したくなると思うので、そういったルールも書けるようになっています。
あとは「パッケージが一時的に依存するnamespace」と書いてあるんですが、既存のコードベースをパッケージ化する時に、一気にやるのは無理だと思うので、一時的な許容ができる仕組みがあります。「RuboCop」を使ったことがある方だと「.rubocop_todo.yml」みたいなものがあるイメージですね。
あとはパッケージのステータスですね。そのチームのパッケージを公開中か開発中かみたいなものも設定できるようになっていて、bundle execコマンドで静的に精査ができるようなものになっています。
弊社の場合だと、これに加えてもう1個取り組みを入れていて、パッケージの公開エントリーポイントに対しては、protoでどういうリクエストをもらうかと、どういうメソッドが生えているかを定義するようにしています。
protoファイルを各チームでパッケージを用意するチームが作って、それをRubyのコードにコンパイルして生成されたRubyのクラスを用いてやり取りするみたいなイメージです。後でちょっと実例のコードを紹介したいと思います。
protoを使っている背景は2点あります。冒頭の検討で「モジュラモノリスとマイクロサービス、どっちにするか?」みたいな話があったと思うんですが、弊社の場合だと、マイクロサービスはGoで作ろうという意思決定があるんです。
そうなった時に、protoでAPIの部分を定義しておいたら、protoを使ってそのままマイクロサービス化も比較的推進しやすいというのがあって、protoを一枚かませている状況です。
あとはRubyなので、protoの定義に沿った引数を渡してもらうという制約を設けることで、なんでも渡せちゃうという状況を排除している状況ですね。型チェックぐらいの役目としてprotoを入れています。
そのprotoからRubyのコードを生成するところは、gRPCが公式で出している「grpc_tools_ruby_protoc」というものがあります。これをprotoファイルにかませると、そこでRubyのコードが作られるイメージです。
(スライドを示して)ざっくり例が書いてあるんですが、mailer.protoみたいなものがあった時に、protoファイルに対してコンパイラをかませると、2個の成果物ができるんですね。
「mailer_pb」がメッセージみたいな情報を持っていて、RPCがどういうリクエストとレスポンスを扱うかの情報を持ったRubyのクラスみたいな「mailer_service_pb.rb」が生成されます。
実際の例です。プロダクトのコードそのままではないんですが、「こんなイメージで使っていますよ」というコードになります。見えなかったら後でスライドの確認をお願いします。
継承しているクラス、Mailer::MailService::Serviceがprotoコンパイラが生成したほうのクラスで、GetMailが私が実装したクラスですね。GetMailはRPCの名前で揃えている状況です。
外からの使い方としては、1クラス1RPCみたいなかたちでファイルを分割していて、それぞれのクラスがexecuteメソッドを持っている。外からAPIっぽく呼べるようなファイル構成にしています。
肝になるところが、rpc_descというやつが真ん中ぐらいにあると思うんですが、それが親クラスで持っているメソッドで、この中で「そのRPCがどういうリクエスト、レスポンスを扱うか」みたいなものが取れる、便利なメソッドなんですね。
このrpc_descを処理の前と後に挟んで、「GetMailクラスはどういうレスポンスとリクエストを扱うか」みたいなバリュエーションに今は利用しています。
(スライドを示して)これはベタで書いているんですが、共通Concernみたいなやつに切り出して、それぞれのクラスにincludeしているようなかたちです。こういう仕組みを入れています。
gRPCで通信しているわけじゃないんですが、これによって「protoのファイルに沿ったやり取りができていますか?」ぐらいの簡易チェックをするものとして利用しています。コードの例は以上です。
次が、永続化層への制限をどうやっているかですね。コードベースで分かれていたとしても、そのパッケージがアクセスするデータベースが有象無象だったらあまり意味がないので、データベースへのアクセスの制限も簡易的なものですが作っています。実現する手段としては、「Arproxy」という、クックパッドさんが作っているgemを利用しています。
これに関してすごく簡単に話すと、ArproxyはActive Recordとデータベースアダプターの間をフックして好きな処理を挟めるみたいなgemで、今回はそれを利用しています。
使い方の例です。(スライドを示して)「ざっくりとこんなことをしていますよ」という図になります。外部からのパッケージのアクセスが来たタイミングで、RailsのThread.currentにそのパッケージが許可するテーブル一覧を突っ込んでいます。
そのパッケージ内部で実際にクエリを呼ぶところです。「QueryObserver」というArproxyのプラグインを実行すると生SQLが流れてくるんですが、それに対して愚直に正規表現を書いています。ちょっと小声になっちゃいますけど。
100パーセントは弾けませんが、今の弊社のRailsの使い方だと、Railsなのであまりアソシエーションとかを貼っていないんですね。比較的シンプルなクエリが流れてくるので、今はそれでだいたい弾けているような状況です。
これはちょっと想像に難くないんですが、本番で動かすとたぶん重いので、今のところデベロップとステージングとQA環境で動かしています。「検知したい」というのは顧客にぜんぜん関係なく、開発者都合なので、「開発段階で気づけたらいいや」という背景でそのようにしています。
最後です。すごい細かい取り組みもしています。今僕が口頭でバーッと説明したことをエンジニアの人に「じゃあ、やって」と言うと、たぶんなかなか難しいと思うので、Rails generatorで「hacoway」というものを作っています。「hacoway」は「hacomono way」の略なんですけど。これでモジュール名を渡して実行すると、パッケージとprotoファイルを含めて全部自動生成できるみたいな仕組みを用意しています。
以上です。あっ、忘れていました。最後にちょっとリクルートになってしまうんですが、ここまでの話を聞いて、お客さまの中に「WOW!」を届けるような基盤作りに興味を持っている方がいたら、ぜひお声掛けいただけると幸いです。
また、選考に進まなかったとしても、単純に「ここらへんの技術、どうなっているの?」みたいな、気になっているところとかがありましたら、Twitter(現X)で@maco_tasuにメンションしてもらえたら答えるので、質問などをお待ちしています。
以上となります。ご清聴ありがとうございました。
関連タグ:
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.21
40代〜50代の管理職が「部下を承認する」のに苦戦するわけ 職場での「傷つき」をこじらせた世代に必要なこと
2024.11.20
成果が目立つ「攻めのタイプ」ばかり採用しがちな職場 「優秀な人材」を求める人がスルーしているもの
2024.11.20
「元エースの管理職」が若手営業を育てる時に陥りがちな罠 順調なチーム・苦戦するチームの違いから見る、育成のポイント
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.19
がんばっているのに伸び悩む営業・成果を出す営業の違い 『無敗営業』著者が教える、つい陥りがちな「思い込み」の罠
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.15
好きなことで起業、赤字を膨らませても引くに引けない理由 倒産リスクが一気に高まる、起業でありがちな失敗
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.21
40代〜50代の管理職が「部下を承認する」のに苦戦するわけ 職場での「傷つき」をこじらせた世代に必要なこと
2024.11.20
成果が目立つ「攻めのタイプ」ばかり採用しがちな職場 「優秀な人材」を求める人がスルーしているもの
2024.11.20
「元エースの管理職」が若手営業を育てる時に陥りがちな罠 順調なチーム・苦戦するチームの違いから見る、育成のポイント
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.19
がんばっているのに伸び悩む営業・成果を出す営業の違い 『無敗営業』著者が教える、つい陥りがちな「思い込み」の罠
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.15
好きなことで起業、赤字を膨らませても引くに引けない理由 倒産リスクが一気に高まる、起業でありがちな失敗