はじめに
LegalOn Technologiesが提供する「LegalOn: World Leading Legal AI」は、契約書ドラフト・レビューや案件の管理、法務相談まで、法務業務をワンストップで支援する革新的なサービスです。リリースから1年半、企画開始から約2年半が経った今、プロジェクト立ち上げの背景、開発の進め方、これまでの振り返りや今後の展望、さらには技術面での学びまでを、全9回にわたるブログシリーズとしてお届けしていきます。
第4回となる本記事では、「LegalOn」の全体アーキテクチャと技術選定に焦点を当て、当時の意思決定の背景や、これまでの成果・課題について、以下の3名に話を聞きました。
- 深川 真一郎:執行役員・CTO
- 杉田寿憲:Staff Platform Engineer
- 安部亨佑:Lead of Frontend Engineer
本記事が少しでも開発や技術選定のヒントになれば幸いです。
「LegalOn」採用技術スタック
深川 最初に「LegalOn」で採用した技術スタックをお見せしておきましょう。こちらです。この中からアーキテクチャ全体の基盤に関わるようなものを今日は触れていきたいと思います。僕は今日は基本的にはインタビュワーでたまにCTOとして話します(笑)。

設計思想と技術選定の成功点
gRPCとConnectの採用
深川 まずは「LegalOn」のアーキテクチャ全体を振り返って、開発初期に意識していたことや、「ここはうまくいったな」と感じているポイントをお二人に伺いたいです。最初にリリース前のフェーズで、特に注力していた部分から教えてください。
安部 最初に挙げるとしたら、やっぱり通信アーキテクチャにProtocol Buffers(protobuf)とgRPCを選択したことですね。Internet-facingな通信をBetter gRPCであるConnectを採用し、内部の通信はgRPCを採用して、両方protobufでスキーマ管理しました。通信スキーマをprotobufで統一することで、できるだけシステムを単純に、シンプルにしたかったんです。というのも、スキーマの寿命は製品そのものの寿命より長くなることもありえると考え、息の長い汎用的な技術を選びたかったという思いがありました。
深川 フロントエンドとバックエンドの通信部分に、RESTやGraphQLを利用するという選択肢もあったと思うんですが、そちらは採用しなかったんですね。
安部 はい。REST, GraphQLのいずれを採用するにせよ、gRPCで取得した値を詰め替えるレイヤーが必要となり、そことフロントエンドとの通信をprotobufとは別のスキーマで再定義する必要が生じます。その詰め替えるレイヤーの実装コストと開発者の心理的な消耗含めた運用コストがネックになると考えました。ツールによる機械的な変換も検討はしたんですが、運用中にエッジケースを踏み抜いて不具合が出る可能性が高いと考え、混乱を避けるために見送りました。 あとはすべての通信をREST APIで統一してOpenAPIでスキーマ管理するという案も考えましたが、protobufと比較するとスキーマの可読性がひっかかりました。REST×OpenAPI自体は当社では広く使われている技術でしたが、書き味や可読性の部分であまり満足している人はいませんでしたし、大規模な変更を行うにはちょうどよい機会かなと。
深川 なるほど。シンプルさを最優先した結果ということですね。protobufの採用については、今振り返るとどうでしょう?
安部 そこはポジティブに感じてます。やっぱり可読性の高さが大きなメリットですね。フロントエンドとバックエンドの間、あるいはバックエンド同士の通信でも、共通の書き方ができるのは助かりました。 一方で、Go以外の言語でのprotovalidate対応が遅れていたり、破壊的変更をどのように管理するかなど、運用面での課題はありました。ライブラリや自作静的解析ルールの活用など、もっと機械的なルール運用が必要だったなと感じています。
杉田 最低限のガイドラインや破壊的変更のチェックは用意していたんですが、コード化されていなかったため認識のズレが多かったのが実情です。やはりツール化は不可欠ですね。
深川 言語選定の部分はgRPCエコシステムについてもう少し調査できるともっとよかったんですけどね。時間の関係である程度で打ち切って、そこまでは気が回らなかった。あと、Connectは実際に使ってみてどう感じていますか?
安部 Connectを選んだのは正解だったと思いますね。フロントエンドでprotobufを使って通信スキーマ定義するなら、Connectがベストの選択肢かなと。ただ、v2への破壊的なバージョンアップは大変でしたね。インターフェースが大きく変わってしまって、対応にかなり苦労しました。メンバーのおかげで、先日ようやく対応が完了したんですが、そもそももうちょっと段階を踏んで(=いきなりの破壊的な変更を避けて)ほしかったのが正直なところです。
深川 gRPCのスタイルガイドでは破壊的変更を基本的に禁止してるのに(笑)。
開発プラットフォームの整備
深川 杉田さんはいかがですか?
杉田 開発ライフサイクルを通じて使える標準コンポーネントを、あらかじめ整備したことが大きかったと思います。たとえば、protobufの管理基盤や、アプリケーションとCIのテンプレート、CDツールなどを事前に準備しました。それらをほとんどのチームに使ってもらえたことで、サービス開発が一定の構成で行われ、知識共有もしやすくなったと感じてます。
深川 そのあたりは大事なポイントでしたね。開発環境まわりは今振り返って何か改善の余地は感じてますか?
杉田 ローカル開発環境については、アプリケーションテンプレートを用意して、そこに運用に必要なツールを組み込む形でサポートしました。例えば、サービス追加時に、DBスキーママイグレーションに必要なツールやPub/Subのエミュレータなどが利用できます。ただ、現状はデプロイ前の動作確認を十分にサポートできていなくて、サービス同士の繋ぎこみはdev環境に出して初めてわかる、という感じになっているのでここは改善ポイントですね。実際のサービスと近い環境で試せるような仕組みが必要だなと感じてます。
深川 なるほど。スキーマ管理についてはどうしたんでしょう?
杉田 protoから生成したコードをライブラリとしてホストできる、BSR(Buf Schema Registry)はとても便利でした。ただ、想像以上にAPIの増加数が早くて、費用も線形に膨らんでしまっていて‥、コスト面を考慮すると近いうちにBSRを手放す必要がありますね。
深川 BSR自体は良いサービスなんですけどね…。その他、開発環境周りで「この判断はよかった」と感じているものは、ほかにもありますか?
安部 モノレポの採用もうまくいった点の一つですね。AIエージェントとの相性や、CI設定の複雑さなど、課題はゼロではありませんが、コードの一括検索や依存関係の把握がしやすいというメリットがありました。
杉田 そうですね。モノレポを実現するための仕組みは極力、学習コストが高く運用が難しい仕組みも入れず、GitHubのcomposite actionやCIテンプレートといった薄めの仕組みで運用できているのも良かった点だと思います。

マイクロサービス採用の判断と粒度
深川 全体といえば、マイクロサービスも、「LegalOn」開発の大きな特徴でしたよね。マイクロサービスアーキテクチャについて、どんなふうに捉えていますか?
杉田 APIを定義したあとに、チームごとに独立して開発やデプロイができるようになったのはすごく良かったです。サービスの粒度に関しては議論もありましたが、ドメイン単位に分けることで、それぞれが自律的に開発を進められて、リリースまでのスピードを上げることができました。
深川 マイクロサービス採用の是非は各所で語られていますよね。全てにおいてマイクロサービスがいいということはもちろんないのですが、100名を超えるチームですし、モノリスやモジュラーモノリスだったら別の問題が出ていた気はしますね。そういった意味ではベターな選択肢だったとは思います。あと、マイクロサービスの “粒度” はよく議論に上がるところだと思うんですが、マイクロサービスの粒度はどうやって決めていったんですか?
安部 大きく分けて2つのパターンがありました。一つは、予約やレビューといったユーザー視点で機能のまとまりがいいもの。DDDの言葉を借りるとコアドメインですね。もう一つは、認証や通知、ファイルデータのようなそれぞれのサービスで共通して利用する、抽出可能な支援サブドメインや汎用サブドメインです。
深川 CTOの立場から振り返ると、このサービスの区切り方は間違いではなかったと感じてます。ただ、単一の責務を追求して若干細かく分けすぎた気はしているので、もう少しドメインの抽象度を高めて分割単位としてもよかったですね。あとこれは深く反省しているのですが、ビジネスドメインを優先してサービス分割した結果、データ整合性を守るためのデータ制約を実現する層が分散してしまったという点があります。業務知識的なビジネスルールとシステム的なデータ制約の両方の観点からどこで分割するかをもっと検討すべきでした。これはプロダクトリリース後、1年くらいしてからリファクタリング・リアーキテクチャが検討されています。
マネージドサービスを組み合わせた共通基盤
深川 その他の基盤についても聞いていきましょう。まずは認証からいきましょうか。認証基盤には今回 Okta Customer Indentify Cloud by Auth0 (以下、「Auth0」と呼ぶ)を採用しましたが、Auth0を使ったことのメリットや、もう少しこうできたという点はありますか?
杉田 当社は前身となるプロダクトの「LegalForce」でもAuth0を採用していたので、これまでの知見を活かしながら、開発工数を抑えられたという意味ではAuth0はありがたかったですね。もう少しこうできたらよかった、という話であれば将来的な全社共通の認証基盤としての拡張性を考慮して、「LegalOn」以外の複数プロダクトも踏まえて、アカウント管理や認証を設計できていたらさらによかったかもしれません。
深川 Auth0は高機能で認証の基本的な部分はAuth0で賄えますしね。あと今回はマイクロサービス構成を採用していますが、マイクロサービス間の認証や認可についてはどうでした?
杉田 そこはService Meshで対応しましたね。なんだかんだ考えることの多いサービス間の認証認可をアプリケーション内でハンドリングしなくて良いためです。結果として、開発者があまり意識しなくても運用できているので、十分機能していると思います。
深川 その他でいうと、非同期処理基盤にはPub/Subを選びましたが、使ってみての印象はどうでしたか?
杉田 Kubernetesとの親和性も考えて、Google Cloudの標準機能から選んだんですが、選択肢としては当時の状況に合っていたと思っています。ただ、もう少し深く仕様を理解した上で使えたら、より運用しやすかったのではとも感じています。
深川 結果論ではありますが、今思えば、Pub/Subを扱いやすくするためのラッパーをあらかじめ用意しておく、という選択肢もあったかもしれないですね。非同期処理の複雑さは最初から認識していたものの、大規模な開発体制ではもう一歩踏み込んでEasyに使えるように準備しておくべきだったな、と感じてます。

運用フェーズで感じた手応え
深川 運用フェーズに入ってからも、「これはやってよかった」と思える部分ってありますか?
安部 これも「LegalForce」時代から引き続きにはなりますが、Datadog Real User Monitoring (以下、「Datadog RUM」)の活用は大きかったですね。ログやモニタリングの観点でとても使いやすくて、フロントエンドから見ても頼れる存在でした。「LegalOn」のユーザーサポートのメンバーもDatadog RUMも直接見てユーザーの問い合わせの調査をしたりして重宝しています。
杉田 「LegalOn」だと今はフロントエンドでしかDatadogを使ってないのでもっとバックエンドでも活用の幅を広げていこうと思っています。
深川 RUMは便利ですよねー。toCだとアクセス量が大変なことになりますが、toBだとSample Rateを100%にしてもそこまで爆発的な量にはなりませんしね。
あとは、運用といえば「LegalOn」の開発はドキュメントにかなり力を入れたプロジェクトでしたよね。
杉田 そうですね。Design Doc や Decision Record など、意思決定や設計の記録をレビューし、残せたのはすごく価値があったと思っています。あとから入ってきたメンバーが、「なぜこうなっているのか」技術的な背景や判断の理由を理解しやすくなるので、やっぱりドキュメントって大事だなと改めて感じます。
安部 本当にそう思います。ドキュメントって、その時点の判断をあとから辿るためにも重要なんですよね。なければ「今どうなっているか」しか見えなくなってしまう。毎回ゼロから読み解くんじゃなくて、記録をベースに考えられるのは大きなメリットです。
深川 これは運用フェーズに入る前のリリース前の開発段階でもどんどん人が増えていく中で書いた価値を感じましたね。大規模なプロジェクトだと大まかな全体像を把握するだけでもバカにならないコストがかかるので、「まず結論はこれを読もう!決定の経緯や理由を詳しく知りたかったらDesign DocとDecision Recordを読んで!」って言えるのはよかった。手前味噌ですが、僕が書いたアーキテクチャ基盤設計書(※1)や非機能要件定義書 のドキュメントも、リリースから1年以上経った今でも「LegalOn」以外の多くのプロジェクトで参照されていて、作っておいて本当に良かったなと感じています。
※1 … アーキテクチャの全体像と選定技術、選定技術へのDesign Doc / Decision Record へのリンクを貼ったドキュメント。


課題と反省点
組織・地域・プロダクトのスケールに対応する基盤の整備
深川 ここまでうまくいったことを中心に振り返ってきましたが….といいつつ反省点もナチュラルにでてきましたがまぁそれは一旦おいといて、逆に「ここはもっとこうしておけばよかった」と感じていることはありますか?
安部 当時は「LegalOn」だけが対象だったのでモノレポで問題はなかったんですが、今では全社共通の概念が増えてきたことで、前提が崩れつつありますね。その影響で「LegalOn」ありきで構築した基盤が、やや中途半端になってしまう恐れもあります。
杉田 ある程度全社共通で利用できるようテンプレートを作り始めたんですが、開発の過程で「LegalOn」固有の要素も入り込んでしまっていて。他のプロダクトで利用する場合は「LegalOn」用のモノレポでホストするのも適切ではないので、管理・提供方法も見直さなければと感じています。
深川 当時は想定していなかった要件、たとえばグローバル展開のような部分については、どんな課題が見えてきましたか?
安部 最低限、文言の抽象化はしていたんですが、どうしてもアドホックな対応が混ざってしまいました。もともと「将来的に多言語対応が必要になるのは間違いないので、困らないようにしておく」という前提で設計していたのですが、それが本当の意味で全員で徹底できなかったのが原因かもしれません。例えば各フェーズのレビューでそういった観点が漏れないような仕組みがなかったりとか。やはり、組織間の意思疎通は改めて重要だと感じました。
杉田 それで言うと、インフラ周りでも「今はこうしてるけど、将来的にはこうしたい」といったビジョンをもっと共有できていればよかったと思ってます。ドキュメント自体は作っていたとしても、それを丁寧に伝えることにもっと力を入れるべきだったと今では思っています。
深川 グローバル展開やマルチプロダクト化は当時の想定よりもずっと早く到来してきたのでそこは誤算でしたね。でも当時は本当に余裕がなかったのでグローバル展開やマルチプロダクト化の前提はもう一回やり直せたとしても、多少の手戻りは許容してクリティカルじゃない部分は前提からスコープアウトさせてたかも(笑)。
今後の展望と自己評価
深川 色々振り返ってきましたが、「LegalOn」のアーキテクチャ全体を振り返って、今あえて点数をつけるとしたら、どれくらいだと思いますか?
安部 開発を開始してからもう2年が経ちましたし、この先1〜2年は安定して運用できそうだという見通しも立っているので、自分としては「及第点」と言って良いかなと思っています。ここまでたどり着けたのは、間違いなくチーム全員の努力の成果ですね。
杉田 私もまったく同感です!自分が「ここはもう少し工夫できたかも」と感じていたところも、他のメンバーがカバーしてくれて、なんとか全体として機能させることができました。 それに、「LegalOn」だけじゃなく、他のプロダクトにもつながっていくような土台が築けたのも大きいですね。
深川 具体的な点数ではなく及第点と表現するのは上手いですね(笑)。もちろん、計画通りに進んだところばかりではなかったですが、それでも「LegalOn」が今安定して動いていて、ビジネス的にも目標達成にしっかり貢献できていると思っています。開発者体験にはまだまだ改善の余地はあると思いますが、最先端の技術を取り入れつつ、実用性とのバランスも結果的にうまく取れていたんじゃないかと感じています。
今回の振り返りで出てきた学びや課題を、今後のプロダクト開発に活かして、LegalOn Technologies全体のさらなる成長にもつなげていきたいですね!
仲間募集!
LegalOn Technologies では、「Product Centric(全員がプロダクトの価値向上のために活動する)」 を大切にし、学ぶことに前向きで、挑戦を楽しめるエンジニアを募集しています。今回の記事で触れたような技術的な挑戦や、チームで課題を解決していくプロセスに興味を持たれた方は、ぜひ以下の採用サイトをご覧ください。皆さんのご応募をお待ちしております!
次回は、「第5回「LegalOn」誕生の裏側:インフラ編」をお届けいたします。