設計者の発言

業務システム開発とデータモデリングに関する語り

WEBサービスのためのデータモデル

 WEBサービスのための汎用的なデータモデルを考えてみた。WEBサービスは事業にとっての特殊な商品カテゴリーに属するものではあるが、ソフトウエア分野として特殊ではない。専用の取引管理モジュールを伴うという特徴はあるものの、運用を支えるデータモデルとしてはあくまでも一般的な業務システムの応用形でしかない。

■データモデル

 その点を踏まえてデータモデルを眺めてほしい(図1)。複数のサービスを定義できるようになっていて、サービス毎に利用可能なフィーチャ・オプション(FO)を設定できる。顧客がサービス毎に選択したFO構成によって月額基本料金や取引あたりの従量単価が決まる。さらに月間の取引実績の集計結果にもとづいて課金・請求額が決まる。サービスの月間のパフォーマンスをモニターするためのサービス別月次サマリも用意されている。なお、カード情報がサブタイプとして切り出されているのは、セキュリティ上別格であるゆえだ。それは社内であれば厳格に管理されたサーバ上に、社外であれば決済サービスを提供する専門業者等に委託した形で保持される。

図1.WEBサービスのデータモデル

 少ないテーブル数ながら、前回記事での野球のデータモデルと同様に、複合主キーや動的参照関係を含んでいる。こういった構造を含むゆえに、設計手法としては一般的な業務システムと同様、DOA(データ指向アプローチ)が向いている。いっぽう、機能設計を先行させるPOA(プロセス指向アプローチ)ではこうはいかない。必要となりそうな機能を一覧し、それぞれ毎にデータストアを機械的に置こうとするため、似たような主キーのテーブルが並ぶ「おそ松くんモデル」が生み出される。まずは扱われるデータの論理構造を明らかにし、そのうえで運用に必要なUIや機能や業務を構想できるようになってほしい。

 これだけではわかりにくいと思うので、インスタンスを併記したモデルを図2で示した(簡単のために一部のテーブルが省略されている)。『タイムスタンプ取得サービス』が定義されていて、FOとして最大取引数と月次レポートの有無が選択可能になっている。顧客として『大日本帝国株式大会社』がこのサービスを契約しており、3件の利用実績が記録されている。それらを月次で集計すれば月次課金額が決まる。顧客は複数サービスを契約できるので、サービス毎の課金額は顧客別月次サマリにも集計される。これが顧客への請求額となり、決められた決済手段によって決済される。

図2.インスタンス併記のデータモデル

 ここでは有償サービスの例を挙げたが、無償化して広告収入で稼ぐ事業スタイルもある。その場合、顧客は一般ユーザではなく広告主である。無料契約では広告が示されるというハイブリッド型もよくある。難しくはないので、上掲のモデルを参考にして読者自身でモデルを考えてみてほしい。

■システム構成

 データモデルを明らかにすれば、これらを扱うための合理的なシステム構成も見えてくる(図3)。稼働中のサービスがA,B,Cの3つだとすると、それぞれのサービス専用の制御モジュール(a),(b),(c)が存在する。サービス利用セッション制御モジュール(S)は、(a),(b),(c)とともにバックエンド(狭義の業務システム)とも連携する。バックエンドは顧客自身が契約内容を確認・変更(*1)したり利用状況や課金額を眺める際に利用するモジュールでもある(セキュリティ確保のために物理的には独立していたほうがよい)。

図3.WEBサービスの論理システム構成

 各モジュールはどのように実装されるのだろう。(a),(b),(c),(S)においてデータはイミュータブルに扱われる(追加と削除のみ)ゆえに、OOPオブジェクト指向プログラミング)やその応用であるDDD(ドメイン駆動設計)で実装できる(参考記事「自社サービスはOOP、業務システムはDOAで作ろう」)。データストアについてはNoSQLやテキストファイルで賄える。いっぽう、複雑な更新操作を伴うバックエンドについては、RDBを基礎に据えたローコード基盤で手早く、手堅く実装すればよい。

 つづいてシステムの動きを時系列で見よう。最初に顧客はバックエンドを用いて自らの顧客情報と契約内容を登録する。そのうえで顧客は(S)にユーザIDとパスワードを含んだリクエストを渡し、サービス利用を開始する。(S)はバックエンドが提供するAPIを利用してリクエストを認証し、セッションを確立する。

 それぞれのセッションは、いずれかのサービス制御モジュールにリクエストを渡し、処理結果を受け取る。その時点で利用実績が生成され、処理結果はただちに顧客に返される。利用実績は非同期でバックエンドに送信・蓄積される。

 月次の締め日が近づいてきた時点で、当月および翌月向けの月次データが展開・補完される(必要な機能はバックエンド上にある。以下も同様)。締め日を過ぎたなら請求処理が起動され、月次サマリ上の課金額と請求額が確定される。その結果を事前に顧客にメール送信・確認したうえで、申請済の決済手段を用いて決済される。決済に失敗した場合には顧客にその旨がメール送信され、規定日までのリトライで決済できなければ利用が停止されることになる。

 このようにシステム構成や処理過程を細かく構想できるのは、扱われるデータの構造を事前に理解できているからだ。そうでなければシステムの構成や動きを想像しても、観念的なもの(いわゆるポエム)にならざるを得ない。それを前提にしたDB設計の品質もタカが知れている。DOAの威力がおわかりだろうか。

アンチパターン

 アンチパターンについても触れておこう。図3の(a),(b),(c),(S)はOOPで実装可能と説明したが、バックエンドまでを含めてOOPで実装してしまうケースがある。とくに単一サービスで始めるスタートアップ企業で起こりやすい。これは危険だ。

 上述したように、イミュータブルなデータしか扱わないモジュールであれば、OOPは比較的有効である。ところが上掲のモデルでは、セッションや利用実績以外は更新されるものばかり。それなのになぜ、それらを扱うモジュールまでOOPで実装されてしまうのだろう。

 おそらく、データ間の論理構造に関する検討や洞察のないまま、ごく単純な業務要件を想定して開発を始めてしまうためではないか。商品定義や契約や課金や請求のデータ構造や管理プロセスが単純でないことは、業務システム開発者にとっては常識である。それを知らない技術者ならば、(a),(b),(c),(S)と同様にアジャイル開発できると侮ってしまうかもしれない。

 そうなるとバックエンドは、必要以上にシンプルな設計から始まるため、運用段階、あるいはサービス・フィーチャの高度化や新規サービスを追加する時点で大掛かりな改修が必要になる。しかしこれは「成長中の動物の背骨をすげ替える」ような大手術だ。バックエンド、つまり狭義の業務システムについては「段階的にアジャイルに高度化してゆく」という開発方針が通用しないことは知っておいたほうがいい。小振りな電化製品や単機能のAPIの開発であれば可能だろうが、橋梁や高層ビルや航空機や業務システムを相手にすればそうはいかない。なんと単純明快な話だろう。

 今風で華やかに見えるWEBサービスといっても、けっきょくは(広義の)業務システムの構成物でしかない。この意味で「WEBサービス開発に特化した技術者」といった狭小な専門性は成立しない。WEBサービスの安定運用および発展のためには、適度に複雑かつ端正なDB構造を基礎とするバックエンドが必要だ。そのためのスキルが、WEBサービスでのスタートアップを支援する技術者にも求められる。あくまでも「業務システム開発に特化した技術者」にとっての付加的な開発テーマとして、WEBサービスを位置づけてほしい。


*1.契約済サービスのFO構成を月中で変更するような場合、「契約サービス」にサービス行番違いでレコードが追加され、顧客が指定した期日で切り替わることになる。FO構成によって月間基本料金が決まるケースなど、月単位でしか契約内容を切り替えられないこともあるだろう。その場合には、同一サービスに対して並立している旧契約と新契約の切替日が強制的に翌月初日に設定される、といった措置が必要になる。