shiodaifuku.io

決済システムを設計するときに忘れてはならないたった1つの大切なこと

この記事はしおだいふく Advent Calendar 2020 23日目の記事です。

本日 設計 モデリング LT会【初心者の方・やっていきも大歓迎】 でお話させていただいた内容のRecapです。 LT会なのでおそらく大部分の説明を省くだろうという予想のもと、この記事を書いています。

さて、このブログでは以前に決済システムを作るまえにこれだけは知っておこう という内容の記事を公開しました。 結論としては「そんなモノ作らずに逃げろ」という話で締めたのですが、今日の記事は不幸にも逃げ損ねてしまったエンジニアの方にぜひ読んでいただければと思います。

資料

決済システムを設計するときに忘れてはならないたった1つの大切なこと

決済システムとは

この記事では、以下のような機能を備えるシステムを決済システムとして想定しています。

  • サービスの対価として金銭の支払いを行う機能を提供している
  • 月額課金などのサブスクリプション機能を提供している
  • なんらかの形で前払式支払手段1を提供する

どちらかというと金融サービス業そのものというよりも、決済代行などの決済サービスを利用して自分たちのサービスを有償で提供するようなシステムが対象になります。 もちろん自社で電子マネーをサービスとして展開されている方も対象ですが、その場合は今日ここでお伝えする内容がすでに実装されていると信じています。

決済システム設計のエッセンス

さっそく本題です。 決済システムを作るときは、 ユーザ(のモデル)とお財布(のモデル)を分ける という設計を取り入れていただきたいと思います。

僕はそれなりの数の決済システムを見てきました(し、自分で設計・開発もしてきました)が、だいたいこのルールを守れていないがゆえの苦しみを経験しています。 逆に、この設計思想を取り入れたために大変な目にあったという話はまだ聞いたことがないので、特段の事情がなければ深く考えずにこれでやっていただければよいかと思います。

「ユーザ」とは

一般的なユーザアカウントを表すモデルを指します。 現実世界において1人の個人に相当する、システムの各利用者に1つずつ与えられる人格にあたる概念です。

これは特に説明することもありませんが、おなじみの存在なので問題ないと思います。

「お財布」とは

現実の世界における、お財布や口座に相当するモデルです。 お金やクレジットカードなどの支払手段を保管しておくものです。

サブスクリプションモデルの場合は現実世界にちょうどよい概念が見当たらないのですが、 支払手段とサブスクリプション契約を紐付けるモデルになります。

「分ける」とは

「分ける」というのは以下の2つの要請を意味しています。

  • ユーザとお財布を別個の概念としてモデル化すること
  • ユーザとお財布のリレーションの多重度をN:1とすること

苦しむ例

まず、ユーザとお財布を分けることに失敗している例を紹介します。

苦しむ例

画像の1番上の例はそもそもテーブルのレベルで分離されていないパターンです。 ユーザのテーブルの中にポイント残高とかいうカラムが作られてしまっており、実質的にはユーザとお財布のリレーションの多重度が1:1になっています。 さすがに現代においてこのような設計にはしないとおもいますが、もしかしたら古いシステムをメンテナンスされている方はこういう形式を目にしているかもしれませんので、 ダメだというために例としてあげております。

2番目の例はテーブルこそ分離されていますが、これもユーザとお財布のリレーションの多重度が1:1になってしまっている例です。

3番目の例は2番めの逆パターンで、決済手段やサブスクリプション契約の側に所有者(ユーザ)の情報が書き込まれてしまっている例です。 これは「分ける」の要請のうち、ユーザとお財布のリレーションの多重度が1:Nになってしまっているパターンです。 特にサブスクリプションモデルで気づかずにやってしまいがちな失敗例です。

1:1だとどうして苦しむのか

端的に言うと、ユーザと決済手段の関連が本当に1:1で済むシステムがほぼありえないためです。 ここはサービスを拡大していくなかでかなり序盤に1:Nへの拡張が要求されるポイントになります。

例えば、クレジットカードに代表される支払手段であれば複数枚所持しておいて支払いの際に利用するカードを選ぶみたいな作りは当たり前になっています。 Apple PayのWalletにも複数のカードが登録できますよね。ここが1種類だったら非常に使いにくいシステムになってしまいます。

前払式支払手段であれば、ユーザからの見た目は確かに1つの『残高』になることがあるかもしれません。 しかし、裏側ではその残高には様々な色がついています。

ソーシャルゲームをプレイされる方であれば有償石と無償石が区別されているのを見たことがあるでしょう。 最近の事例で言えば某スマホ決済サービスにおいて送金可能な残高とか送金不可能な残高とか言ってるのを見たことがある方もいるかもしれません。 ポイントの場合であれば、その原資2や有効期限によって複雑な処理の分岐が発生します。 同じポイントでありながら一律の扱いができないところがポイントサービスのムズカシイところです。

もちろん画面に表示したために集計した値をデータとしてもっておくことは構いませんが、それはあくまで算出値にすぎず、 算出するための元となるデータはここで紹介した方式で扱うほうが良いと思います。

1:Nだとどうして苦しむのか

1:Nの良くないところは非常に明確で、ある1つの決済手段を複数人で共有できない点がネックになります。

もっともよくある例はtoBのサービスで、相手側に経理部が存在するパターンです。 経理部にお勤めの方々にそれぞれ異なるログインアカウントを発行しながら、扱う決済手段は会社のコーポレートカードと銀行口座で共有している、 というユースケースに対応するにはユーザとお財布の対応がN:1になっていることが必要です。

「toCのサービスなら大丈夫では...?」と思った方もいるかもしれませんが、僕の経験上あまり大丈夫ではないことが多いです。

ゲームなどでよくあるのは一人のユーザが複数のアカウントを持つケースです。 どんなに対策しても複数アカウントを作成されることは避けられません。 規約で縛ることはできなくもないですが、複数アカウントを利用してもらうほうが運営会社にとってメリットになる場合も多いため、 真剣に複数アカウントを規制しているという話はあまり耳にしません。 また他の例としては、家族でそれぞれログイン用のアカウントは持つけど、支払いは共通のクレジットカードを使いたい、といったようなケースが考えられます。

このときに問題になりがちなのが、利用している決済サービス側の都合です。 特にクレジットカードで顕著ですが、同一のクレジットカードを2回以上登録できないように制限しているところがあります。 この場合は、結局こちらのシステム内で1つのカード情報を複数のユーザに紐付ける処理が必要になります。

複数アカウントを防ぐことがそもそも困難かつ非合理なのであれば、最初からそれに対応しておくほうが選択としては賢いはずです。 僕が考えるよいモデル化とは、なるべく現実の概念を忠実に再現することです。 1枚しか存在しないはずの同一のクレジットカード情報が2件以上データベースに登録されているというのは非常に気持ち悪い状態です。 これを解消するための概念が、本日ご紹介させていただきましたお財布モデルなのです。 便宜上お財布と呼んでいますが、適宜良い名前をつけてあげてください。

その他の特殊な事例への対応もある

その他特殊な事例ではありますが、以下のようなユースケースに対応する際も今日紹介したお財布の概念が活躍するでしょう。

  • ECサイトを家族で利用する際に、(決済手段だけでなく)ポイント還元される先を一本化したい
  • サブスクリプションサービスに於いて、サービスを利用するユーザと支払いを行うユーザが異なる

比較的少ない苦しみで済む例

以上を踏まえて、比較的少ない苦しみで済むモデリングの例を紹介しておきます。

比較的少ない苦しみで済む例

上の図は素直なパターンで、ユーザは現在所有しているお財布の情報を持ちます。 この形にすることで、ユーザとお財布のリレーションがN:1になります。 もし、1人のユーザが複数の財布を使い分けるような必要があれば、ここの多重度はN:Nになります。

下の図はサブスクリプションモデルにおいて、ひとつの支払手段で複数のサブスクリプション契約を管理する例です。 左のユーザとは支払いを管理するユーザを表します。必ずしもこのユーザがサブスクリプションサービスを受けるわけではないところに注意してください。

まとめ

今日は僕が馴染み深いという理由で決済システムを題材に取り上げましたが、 少し抽象度の高い言い方をすれば(途中でもちょっと書いたように)モデリングは現実世界を忠実に再現することが大事だということが本稿で主張したいところになります。

ここで悪い例として取り上げた形式も、RDBの世界に閉じた見方をしてしまえば適切に正規化がなされているといえます。 しかし、拡張性の高いシステムを作るためには、単に正規化して満足するのではなく、システム化の対象となっている業務をよくモデル化できているかという観点が必要です。

...ということがなんとなく伝わっていたら嬉しいです。


  1. 電子マネー・ポイント・ゲームの石など。
  2. 基本的にはプロモーション費用なので、ポイントのために誰かがお金を積み立てており、ポイントが利用されると費用を請求されるようなことが多い。

最新記事

  1. クソお世話になりました
  2. Cloud RunでgRPC streamingができるようになったので動かしてみたりした
  3. 2020年の執筆業まとめ
  4. アーキテクチャを設計する仕事とは
  5. 決済システムを設計するときに忘れてはならないたった1つの大切なこと