🏔️

設計の現場から:多重度アーキテクチャの考察と決断

2024/12/30に公開

この記事は FOLIO Advent Calendar 2024 - Adventar の17日目です。(2週間遅れ)

はじめに

今年は初めてアーキテクチャ Conference 2024 が開催されたりと、とても設計が盛り上がった年だったように感じています。
特に、これまでは設計の話というと、機密漏洩を気にして抽象的な議論または単純化したサンプルなどがほとんどでしたが、今年は構成といったより具体的なケースが公開されているケースが多いことが特徴な気がします。
せっかくなのでこの流れに乗っかって、本稿でも事業における設計の事例紹介を行ないたいなと思います。

設計って何?

そもそも設計とはなんでしょうか?
設計とは、システムの土台であるアーキテクチャを決める活動です。
そしてアーキテクチャは、システムが提供する能力(capability)を定義するものです。
引用 : アーキテクチャConference 2024 基調講演より

例えば、システムが持つべき柔軟性や性能、拡張性といった要件を設計段階で決めていくことで、システムが必要な役割を果たせるようにします。
しかし、設計の段階で想定が不足していると、業務上やりたいことができない、想定したパフォーマンスが出ない、UXが悪化する、といった形でシステムのcapabilityの不足が顕在化します。

capabilityの不足

とはいえ、capabilityは出来るだけ大きくすれば良いわけではありません。
例えば日本ローカルを前提としたビジネスのためのシステムであるにも関わらず、多言語対応というcapabilityは役に立たないでしょう。
また、1日にたかだか数回しか利用されないシステムでは、スケールアウトのためのcapabilityを用意しても出番は永遠に訪れません。

このように設計は、capabilityのトレードオフ(何が出来るようになるのか、どの程度のコストを必要とするのか)を見極めつつ、そのcapabilityをシステムに取り入れるべきかどうかを決断することがとても重要です。

本稿では、弊社の提供するプロダクトである4RAPにて約2年前にリリースされた機能について、どのような流れで設計を行ったのかを紹介します。
また、約2年の運用を受けての考察と、今後どのように設計を改善=capabilityの拡張を行うべきか、現時点の考えを述べようと思います。

事例紹介 : アカウントと所属部店

FOLIOが提供する4RAPというシステムは、ロボアドバイザーやファンドラップといった資産運用サービスをワンストップで始められる、金融機関向けB2B SaaSです。
4RAP|FOLIOのファンドラップ・ロボアドバイザー基盤

金融機関ではサービスの運営のために、4RAPの機能を使って様々な業務を行ないます。
そのため、4RAPでは金融機関の従業員のアカウント(以下、アカウント)を提供しています。

また金融機関は本社と支部、支店(以下、総称して部店)で構成されることが一般的です。
アカウントは何かしらの部店に所属して業務を行うことになります。
本稿の事例紹介は、このアカウントと部店の関係性=多重度における設計を紹介したいと思います。

アカウントは部店に所属する

なぜ多重度?

多重度を紹介する理由は、当初設定において多重度を見誤った場合(以下、多重度の誤り)に、後からcapabilityを拡張することが困難になりやすいことが挙げられます。

例えば、4RAPでは、先にB2C事業でロボアドバイザーを提供しており、そこで開発したシステムをB2BとB2B2Cに転用することでプロダクトを立ち上げました。
自社サービスで利用するシステムはシングルテナント前提のアーキテクチャでしたが、社外展開するとなるとマルチテナントに耐える必要があり、capabilityを拡張しなければなりませんでした。

このシングルテナントとマルチテナントの多重度の誤りに関するcapabilityの拡張のために、部分的ではありますがスクラッチから作り直す必要があり、大きなコストが発生しました。

このように、経験則から多重度の誤りは高コストにつながりがちですので、設計においては特に注意深く分析・決断が必要な箇所となることが多いです。

所属部店によるアクセス制御の設計(capabilityの決定)

所属部店はアカウントのアクセス制御としても利用され、アカウントがアクセス可能なデータは所属部店によって定まります。
例えば、部店Aに属するアカウントは、部店Aの顧客情報や申し込み情報などの機密情報にアクセス可能ですが、部店Bの機密情報にはアクセスできません。

所属部店によるアクセス制御

アカウントと所属部店の多重度として、以下の2つが考えられました:

  1. N:1
    • 「アカウントは必ず1つの部店に所属し、部店には0個以上のアカウントが所属する」
  2. N:N
    • 「アカウントは1つ以上の部店に所属して、部店には0個以上のアカウントが所属する」

N:1とN:N

もちろんcapabilityとしては「N:N」が「N:1」を包含するのですが、「N:N」は実装コストが高くなりがちです。
例えば、「N:N」の場合、アカウントがどの部店で行なったアクションかを特定しなければいけない可能性があります。
AWSのダッシュボードのように、ログイン時に選択をさせるUIが良い例ですね。
実装出来なくはないものの、部店の選択や部店の引き回しの機構、バリデーションが追加で必要になってきそうなため、出来れば採用したくはないと考えていました。
そこで設計の当初方針としては、コストが低く抑えられる「N:1」をベースとし、capabilityに不足がないかどうかを検証することにしました。

では、どういったケースで「N:1」でcapabilityが不足するのでしょうか?

一つは、販売の手続きにおける審査プロセスがあります。
金融機関はファンドラップという金融商品を販売するために4RAPを導入するわけですが、ファンドラップは営業店の営業員が販売します。
その際、営業員が営業店が不適切な販売を行なわないよう、会社として抑止力を働かせることが必要です。
そこで4RAPでは、営業員の販売の手続きの中に、必ず管理者ロールのアカウントが審査のプロセスを組み込んでいます。

販売の審査

この審査プロセスに抑止力を持たせるには、営業員とインセンティブが一致しない従業員が行なう必要があります。

例えば営業店の支店長が審査を行なうこととした場合、営業員と支店長は同じインセンティブ(営業員の売り上げが上がれば、支店の売り上げが上がる = 支店長の評価が上がる)を持っていますので、審査が形骸化し不適切な営業を行なう可能性が上がってしまいます。
そのため、審査プロセスは営業店から離れた組織、例えば本部の営業活動に従事しない組織(以下、単に本部と書きます)の従業員で行なうことが求められるのです。

本部の従業員が全ての販売について漏れなく審査に関わるためには、当然ながら審査対象となる営業店 = 他部店の販売情報にアクセスしなければなりません。
この問題に対して思いつく対策の一つは、本部の審査を担当する従業員を、審査を担当する営業店全てに所属させることです。
ただ、かなり多くの営業店を兼務する必要があり、所属の管理が極めて煩雑になってしまいます。

そこで4RAPでは、部店間にツリー構造を導入し、上位(根に近い)部店が下位(葉に近い)の部店のアクセス権限を持てるようにしました。
例えば根=本部に所属するアカウントは全ての部店のアクセス権限を持つ一方で、葉=営業店は自身のアクセス権限しか持ちません。
また、途中の節である支部Aは自身の配下の部店のアクセス権限を持つ一方で、隣の節=支部Bの配下の部店のアクセス権限は持ちません。

アクセス権限のツリー構造

このツリー構造の導入により、審査を含む4RAP上で行なわれる業務の多くについて、「N:1」でもアクセス権限に対応できる見込みがたちました。
このような検討を経て、アカウントと所属部店の関係性は「N:1」のcapability を採用、約2年前の新機能リリースに至りました。

今後の課題(capabilityの拡張)

当初に行なった設計のおかげで、約2年間の運用の間にアクセス権限に関するクリティカルな問題は発生せず、大きな改修や追加実装を行なわずに済みました。
ただし、若干のcapability不足が少しずつ顕在化してきました。
その課題は「異動」と「兼務」に関するものです。

異動では、従業員が現在所属している部店Aから、次に所属する部店Bに所属が変更されますが、ある日突然所属が変更されるわけではありません。
引き継ぎなどの業務上の理由から、従業員が一時的に部店Aと部店Bの両方に所属する必要があり、N:Nの関係が生じます。

異動の関係性をツリー構造で吸収できるかというと、極めて困難です。
理由の一つは、異動は任意の部店A, Bで起こることです。
任意のA, Bで発生するということは、ツリー構造ではなくグラフ構造なので capabilityが不足しています。

もう一つの理由は、異動は従業員=アカウントに対して発生するものということです。
権限のツリー構造は部店間の関係性を表現するものであって、従業員が対象ではありません。
もし無理に当てはめようとすると、

  • 権限構造をツリーではなくグラフに拡張する
  • 異動対象の従業員ごとに、部店A, 部店Bを配下に持つテンポラリーの節を用意する

というような、必要以上に複雑で不自然な設計となってしまいます。

異動のグラフ構造

兼務も異動と同様に複数の部店に所属する状態です。
ただ、兼務は全く無関係な部店間で発生することが少ないため、ツリー構造で一定は対応が可能です。
例えば、とある都市の営業店Xとその周辺に展開する出張所Y, Zがあった時に、営業店XにYとZの営業管理機能も集約したいというようなケースですね。
この時、XをY, Zの上位の節として、3店舗の営業管理に従事するアカウントがXに属することで、当該アカウントはX, Y, Zの3店舗のアクセス権限を保持することになります。
このように兼務に対しては、既存のアーキテクチャであっても一定のcapabilityを充足しています。
とはいえ、異動と同様に兼務はアカウントに対して発生するものですので、部店の関係性であるツリー構造で常に対応可能であるとは言い切れず、capabilityの拡張が必要になりそうなユースケースです。

兼務のツリー構造

実のところ、どちらのケースについても当初の設計段階でも全く考えていなかった訳ではありません。
ただ、異動は短期間に限定されるもの、兼務も一定対応可能なことから、あえてcapabilityの不足に目を瞑るという判断を行なったという経緯があります。
ただ、約2年が経過したことで当初想定していない利用が増え始める頃であること、4RAPを導入していただいた金融機関が増えバリエーションが出始めていることから、capabilityの拡張をそろそろ考えるフェーズに近づいていると感じています。(実際に「複数の部店に所属できないのか」との問い合わせもあったり)

capabilityの拡張のアイデア

では、既存の「N:1」とツリー構造に対して、どのようにしてcapabilityを拡張するのが良いでしょうか?

異動や兼務の性質を考えると、以下の2点を満たさなければならないことがわかります。

  • アカウントに対して権限が付与されること
  • 権限は複数かつ任意の部店の組み合わせであること

素直に考えると「N:N」を採用することが考えられますが、今から多重度を変更することはかなりのコストを払うことになる一方で、異動と兼務というクリティカルではないユースケースに対する対応であり、トレードオフが見合いません。
現時点では、既存の設計の範囲での自然な拡張で対応することが理想的と言えます。

具体的には、「限定的な所属部店の変更権限の委譲」というアイデアを検討しています。
本来、アクセス権限は中央集権で管理されるものですが、異動や兼務の対象となったアカウントに対しては、対象となる部店や期間、自身のアカウントに限定して自身で変更が行なえるようにするものです。

変更権限の委譲

例えば従業員Aが部店Xから部店Yに対して2025年1月1日から異動となった場合、2024年12月31日までは従業員Aが必要に応じて所属を部店Xから部店Y、部店Yから部店Xに切り替え可能とします。
これにより、引き継ぎ業務の必要に応じて、異動元、異動先それぞれの権限に切り替えて作業することが出来ます。

自身で所属部店を切り替え

この設計であれば、異動や兼務に必要なcapabilityを拡張しつつも、既存の「N:1」のアークテクチャを大きく変更しなくてすみます。
一方でこの方式の問題点は、アカウントが同時に複数の部店に所属していることを表現できていないことです。

あくまで所属変更の権限が委譲されているだけなので、アカウントが所属する部店は常に一つです。
そのため、複数部店の所属状態を前提とするユースケースに対しては、capabilityが不足してしまいます。
ただ、今後も詳しく検討して行く必要がありますが、ここまでの検討ではクリティカルなユースケースは思いついていませんので、おおむねは大丈夫そうな肌感です。
まだ実装時期は未定なので何年後になるかは分かりませんが、設計、実装が終わって一定運用の結果が出たら、改めて答え合わせのご報告が出来ればなと思います。

終わりに

本稿では、設計において特に重要=誤りのコストが高い「多重度」の設計を取り上げました。
私が実際に携わった機能開発において、当初の設計(capabilityの決定)において考えたこと、そして今後の設計(capabilityの拡張)で考えていることをつらつらと書き下してみましたが、いかがでしたでしょうか?
もし読者の皆様の設計において、少しでも参考になるようでしたら幸いです。

Discussion