Speee DEVELOPER BLOG

Speee開発陣による技術情報発信ブログです。 メディア開発・運用、スマートフォンアプリ開発、Webマーケティング、アドテクなどで培った技術ノウハウを発信していきます!

マルチプロダクトSaaSにおけるシンプルな共通基盤を作るための3原則

※この記事は、2025 Speee Advent Calendar 16日目の記事です。 昨日の記事はRailsアップデートから学ぶ意思決定に根拠を持ち、残すことの重要性 - Speee DEVELOPER BLOGでした。


こんにちは、デジタルトランスフォーメーション事業本部の中嶋 学です。「ツナガル」という不動産会社様向けの業務支援プロダクトを開発しています。査定書作成SaaSや架電代行BPOサービスなど、複数のプロダクトを提供しています。

これらのプロダクトを開発する上で欠かせないのが、請求システムや社内管理画面といった共通基盤の設計です。共通基盤は、ツナガルの提供プロダクト数が増えても、メンテナンスし続けられるようシンプルな状態を保たなければなりません。シンプルに保つためにも、場合によっては再設計も必要になります。認知負荷の高い設計のままでは、変更や調査のたびに大きなコストがかかってくるからです。

本記事では、共通基盤においてシンプルさを追求する上で大事な3つの原則を、実際の事例を通して紹介します。

原則1: 設計を必要になるまで遅らせる

「企業」の階層を捨ててリリースした

ツナガルのような実店舗を扱うBtoB SaaSには、「企業」と「店舗」のような階層構造を持つことが多いです。既存プロダクトであるイエウールとすまいステップにも同様の階層構造があります。

ツナガルの立ち上げ時においても、はじめは既存プロダクトを踏襲し、企業と店舗の階層構造を導入することを考えていました。しかし最終的に、社内管理画面を含めた実装工数を少しでも減らしリリースを早めるため、企業モデルの設計は省き、最小の組織単位である店舗モデルのみを実装することにしました。請求の実施や顧客データの扱いの観点から、店舗モデルがあれば十分と考えたからです。

結果、立ち上げ後2年弱のあいだ企業の概念がない状態でしたが、問題は起こらず、必要性に迫られたこともありませんでした。

設計を遅らせることで得られたシンプルさ

企業モデルの設計を遅らせたことで、思いがけず得られたメリットがありました。それは、ツナガルの社内管理画面が既存プロダクトに比べて非常に分かりやすくなったことです。

企業の階層が存在しない分、すべての情報・アクションボタンが店舗階層の画面に集まり、階層間の行き来が不要になりました。一画面に全店舗の情報やアクションボタンが乱立することもなくなりました。実際に、既存プロダクトに比べてまだ歴史が浅いこともありますが、ツナガルの社内管理画面が一番わかりやすいという声をいただいています。

ここでの学びは、必要になるまで設計を遅らせることで、前提条件から無駄が削ぎ落とされ、結果システムがシンプルになるということです。このケースでは、前提条件を「企業と店舗の階層構造」から「店舗のみのフラット構造」に変更しました。これにより、管理画面は店舗階層のみを扱えばよくなり、企業詳細画面に複数の店舗の情報やアクションボタンが乱立する状況を避けることに成功しました。

前提を疑う

当初は、既存プロダクトに企業と店舗の階層構造があるのであれば、ツナガルもすぐ必要になるだろうと考えていました。しかし、上記のとおり予想は外れました。

既存プロダクトの設計を先入観として持っていたこともあり、はじめは気づきませんでした。しかし結局、企業モデルは、プロダクトの設定やリソースを企業単位で持たせたいユースケースがない限り、ただ店舗を束ねるだけの単位にすぎないことに気づきました。

店舗を企業に束ねて何がしたいのか。なぜ企業の単位が必要なのか。目的ありきでデータモデリングを決めないと、過剰に複雑な設計になることも併せて学びました。

原則2: DRY原則で認知負荷を削減する

現行の請求システムの複雑さの正体

ツナガルの提供プロダクトを今後増やしていくうえで請求システムは重要です。どのようなプロダクトを提供するにしても請求とは切っても切り離せないからです。新規プロダクトを始める際には、必ずどのような料金体系にするか、どのようなオペレーションにするかといった、請求にまつわる議論が出てきます。

現行の請求システムは認知負荷が高く、このまま使い続けるうえで限界を迎えているため、現在、請求システムの再設計プロジェクトに取り組んでいます。

現行の設計は、ツナガルで提供しているプロダクトごとにモジュール、テーブルが分かれています。分かれている分、各モジュールは比較的小さく簡単に読めます。しかし、全体構造を読み解こうと思うと途端に認知負荷が高く感じます。この認知負荷の高さは何なのか。言語化すると、次のようになります。

  • プロダクトごとに個別に料金計算ロジックが書かれているため、プロダクトの数だけロジックを読みにいく必要がある
  • プロダクト間で「月額課金のための料金計算」といった共通しているロジックもたくさんあるが、個別にロジックが書かれているため、全部のロジックを見ないと理解しきれない
  • ただ、頭の中にすべてのロジックを記憶できるわけではない
  • ゆえに、全体構造を読み解き頭の中にインプットするには、個別に書かれたロジックを抽象化し、脳の記憶容量を圧縮しなければならない
  • ところが、抽象化によって脳の記憶容量を圧縮しても、実際のコードは個別にロジックが書かれているため、時間が経つと頭の中の抽象化に自信がなくなり、結果、何度も具体のコードを読みにいく羽目になる

言い換えるなら、全体構造を読み解くために、読み手が抽象化を行うコストを都度払う必要があり、認知負荷が高くなっているのです。

DRY原則の導入

認知負荷を下げるには、読み手に抽象化のコストを払わせるのではなく、コードやテーブル設計自体を抽象化し、対象システム全体の情報量を圧縮する必要があります。これには「DRY(Don't Repeat Yourself)原則」が有効です。

DRY原則を理解する上で、『プログラマが知るべき97のこと』の次の文言が重要です。

DRY原則を守るとは、言い換えれば「すべての知識はシステム内において、単一、かつ明確な、そして信頼できる表現になっていなければならない」という条件を満たすことです。

現在の請求システムは、このDRY原則が守られているとは言えません。「月額課金」「従量課金」「初期費用」といった料金計算ロジック(=知識)が、プロダクトごとに分かれたモジュールにバラバラに実装されているからです。

共通のデータモデルを定義する

そこで、ツナガル開発チームでは現行の請求システムから共通するドメイン知識を抽出し、次のような全プロダクト共通のデータモデルを定義しました。

  • 契約: どのプロダクトの、どの料金プランを契約しているかを表す
  • 契約単価: 契約時に締結した請求金額を表す。月額10,000円、従量単価100円/件など
  • 契約単価条件: 単価を適用する条件を表す。例えば「使用量100件まで」「使用量101件以上」など
  • 使用量: サービスにおけるトランザクション件数を表す。従量課金に使用
  • 請求予定: 契約と使用量から算出された、実際の請求金額を表す

プロダクトごとに異なる料金体系や使用量の集計方法は、このデータモデルに従いあらかじめ定義することで、全プロダクトの請求を最小のデータモデルで実現できます。

DRY原則によって得られたシンプルさ

このような設計によって、現行請求システムはプロダクトごとに平均4.3個のテーブルがありましたが、新システムではプロダクトごとのテーブルが不要になり、認知負荷を大幅に削減できました。提供プロダクト数が増加したとしても、共通の金額計算ロジックを流用できるため、テーブルとコードの追加を最小限に抑えられ、理解すべきコードやテーブルを最小限にとどめられます。

原則3: 成果・ビジョンから逆算する

これまでの2つの原則も、実は成果やビジョンから逆算した結果として導かれたものです。

なぜこの原則が必要なのか

技術的な原則を適用する際、「どこまでやるか」の判断基準が必要です。成果やビジョンから逆算せずに原則を適用すると、以下の問題が起こります。

  • やりすぎ: 必要以上に抽象化・最適化してリリースが遅れる
  • やらなさすぎ: 将来を見据えた設計ができず、すぐに限界を迎える

成果定義やビジョンがあってはじめて、「設計を必要になるまで遅らせる」「認知負荷を削減する」といった原則を、どこまで適用すれば十分かを判断できます。

ビジネスとエンジニアリングの協働

ツナガルの開発チームでは、ビジネスとエンジニアが一体となってチーム単位・プロジェクト単位で成果定義について目線を合わせながら、共通基盤の改善施策を実施しています。成果定義やビジョンの目線を合わせ互いに議論することで、どこまで改善に踏み込むかを決め、改善施策を進められています。

この点については、同僚の林崎さんの記事でも詳しく語られているので、ぜひご覧ください。

tech.speee.jp

先に紹介した企業階層の削減は、「早期リリース」という成果から逆算した判断でした。もし成果定義がなければ、「既存プロダクトにあるから」という理由だけで企業モデルを実装し、リリースが遅れていたかもしれません。同様に、現在進行中の請求システムの再設計も、「プロダクト数を増やしていく」というビジョンから逆算した施策です。ビジョンがあるからこそ、プロダクト数が増えたとしても耐えられる設計という明確な目標が定まり、DRY原則に基づいた抽象化の程度を判断できました。

まとめ

本記事では、ツナガルの共通基盤開発において大事な3つの原則を紹介しました。

原則1: 設計を必要になるまで遅らせる

先入観にとらわれず、本当に必要な機能だけを実装することで、システムは自然とシンプルになります。「何のためにその構造が必要なのか」を問い続けることで、過剰な複雑さを避けられます。

原則2: 認知負荷を削減する

個々のモジュールの美しさだけでなく、システム全体の情報量を圧縮することが認知負荷の削減につながります。特に共通基盤では、DRY原則を守り知識を単一の場所で表現することで、変更に強く理解しやすいシステムになります。

原則3: 成果・ビジョンから逆算する

技術的な原則を適用する際、成果やビジョンから逆算することで「どこまでやるか」を適切に判断できます。ビジネスとエンジニアリングが協働して目線を合わせることが、バランスの取れた改善施策につながります。

これらの原則を意識することで、長期的にメンテナンスしやすいシステムを作ることができると考えています。


Speeeでは一緒にサービス開発を推進してくれる熱い仲間を募集しています!

新卒の方はこちらより本選考に申し込みが可能です! キャリア採用の方はこちらのFormよりカジュアル面談も気軽にお申し込みいただけます!

Speeeではさまざまなポジションで募集中なので「どんなポジションがあるの?」と気になってくれた方は、こちらをチェックしてみてください!