SIer/クライアント視点から読み解くBRMS導入の効果とは
こんにちは。SCSKの植木とレッドハットの梅野によるBRMSコラムの第2回です。前回はBRMSの概要について説明しましたが、いよいよ今回からはBRMSの実装例をご紹介します。
BRMSの実装例
BRMSの根底にあるのはオブジェクトとオブジェクトを比較するという考え方です。
オブジェクトとオブジェクトを比較するという考え方
オブジェクトとは、データであったりルールであったり、なんでも良いのです。Java上のオブジェクトであれば、なんでも比較できます。
例えば、
- 「申込書」と「規約」
- 「顧客情報」と「キャンペーン情報」
- 「複数の明細」と「注文情報」
は、すべてオブジェクトであり、その2つ以上のデータの関連性がルールになります。
申込書と規約であれば、
「申込人の年齢が18歳未満の場合、保護者の欄に記名が必要」
という関係性がルールになります。
これは、申込書というオブジェクトの中にある、“年齢”というオブジェクトと、18という数値(固定的なオブジェクト)を比較しています。
続いて顧客情報とキャンペーン情報の場合は、
「顧客の入会日がキャンペーン適用期間に含まれる場合、当該施策の他に壺をプレゼント」
といったルールを設定できます。
これは、顧客情報というオブジェクトにある顧客の“入会日”というオブジェクト(日付データ)とキャンペーン情報というオブジェクトの中にある“キャンペーン期間”というオブジェクト(日付のレンジや入会日から何日以内などという数値)を比較しています。
また、複数の明細の場合では、
「各明細の数量の合計と、最小値と最大値を注文情報のサマリに記述」
としてみましょう。
例えば、最小値を出すルールは
when Order() Meisai($最小値: 数量, $SKU: SKU) not Meisai(数量 < $最小値, SKU != $SKU) then …
もしくは
when Order() $最小値 : Number() from accumulate (Meisai($数量:数量), min($数量)) then …
というように記述できます。
これは、ワーキングメモリに複数のオブジェクトがある事を想定しています。その中で、ルールにマッチする全ての組合せを列挙し、そのうちの1つを実行します。1つ実行することにより他の組合せがキャンセルされることもあります。
ルールエンジンが一番得意とするのは、このように複数のオブジェクト間の関係性を判断するところです。システム的な観点だと、そのロジックを何回ループさせるかを考えますが、業務ユーザーは、「そのロジックが何回ループするか」という視点はもっていません。何回ループするかは組合せを幾つ作るかに等しく、ルールエンジンの場合はその組合せを自動的に作って実行してくれるのです。ルールエンジンが業務ユーザーに親和性があるという理由の1つがここにあります。
従来の手続き型と宣言型
皆さんがお馴染みのプログラミングの方法は、「手続き型」プログラミングと言います。フロー図を起こしてその順番通りに実装していくというものです。最初はかなりスッキリ作られるのですが、変更が入ると段々複雑化していきます。途中でデータベースの読込・書込などをしていると、改修の難易度が一気に高くなります。
皆さんが「工数が掛かっている」と認識するのはここの部分になります。1つ1つの改修の難易度は高くないですが、処理系全体で考えると、影響分析、テストパターンの洗い出しに非常に多くの工数を掛けているのが現実です。
例として、Webで受付をしたデータで契約確認をするロジックを考えてみます。業務側がやりたいことは、「本人確認には、登録された生年月日と電話番号を確認すること」です。
これをシステム側ではロジックの中で、「氏名がある場合はデータベースの検索を行い、ない場合はエラーコード404を返す。次にデータベースを検索し氏名が一致するレコードを取り出す。入力された生年月日と検索結果の生年月日を比較し、一致していなかったらエラーコード505を返す、入力された生年月日がない場合はエラーコード404を返す」というようなことをしていたかと思います。これを一連で書くと、まさに手続き型のフロー図になります。
では、このフローを次のようにしたらどうでしょうか。まず、セクションを「手入力データチェック」「DB検索」「契約確認」の3つに分けます。
手入力データチェックは、
「氏名が空白の場合、氏名の入力が必要です(エラー404)と返す」
「生年月日が空白の場合、生年月日の入力が必要です(エラー404)と返す」
というようなルールになります。氏名と生年月日というデータ間は、直接的な関係性はありません。つまり、宣言型になります。
次に、手入力データチェックでエラーがなければ、データベースを検索し、手入力したデータとデータベースのデータをマッチングさせます。
「手入力データの生年月日と顧客名簿の生年月日が同一でない場合、登録情報が異なります(エラー505)を返す」
「手入力データの電話番号と顧客名簿の電話番号が同一でない場合、登録情報が異なります(エラー505)を返す」
…
というようなルールになると思います。
業務ユーザーは、何をもって本人とするかの契約確認ルールだけをメンテナンスします。入力データチェックルールは、ロジック上システムとして必要なルールですので、IT部門でメンテナンスします。
セキュリティチェックが厳しくなり、マイナンバーを入力しなければならなくなった場合を考えてみてください。ちゃんと構造化されたアーキテクチャで書かれるなら大した手間もないですが、「10数行でおさまるから」と、ロジックの中に処理を記述してしまったら、データベース呼出やらnullチェックやらで、あっという間にロジックの迷路(スパゲッティ)ができあがることは想像に難くないでしょう。
これが手続き型と宣言型の違いです。筆者が経験している実案件ではこの判断すべきパラメータは100〜500にもなりえます。手続き型で書かれている場合、if-then-elseを追うだけでも大変な作業になり、ロジックを追いきれずに、同じデータベースへの呼出を複数回書いていたのを発見したこともあります。
ただ、宣言型といえども、ルールやデータ間に順序性相関がある場合は、ルールで順番を制御する必要があります。ルールフローやルールの優先順位付けをすることでその制約を満たすことができます。
手続き型と宣言型。どちらがメンテナンスしやすいでしょうか?
BRMSを導入して得するのは誰?(推進する理由)
では、BRMSを導入した際の効果はどこに表れるのでしょうか? ここでは、クライアントとSIerという2面で効果について見ていきたいと思います。
クライアント視点
クライアントの視点では、まず仕様が見える化することが挙げられます。
BRMSを用いないプログラム言語による実装の場合、技術者が辛抱強く読み解けば仕様を把握することは可能です。しかし、クライアントが技術者でないことが往々にしてあるため、実装から仕様を知ることができません。
そのため、仕様書や設計書を用いてクライアントと確認を取ることが一般的ですが、長く保守をする中で仕様書や設計書が実装と乖離していくことが少なくありません。これでは、クライアントが仕様書で確認を取ったとしても、正確に実装されたかを確認できないということになります。
これに対し、BRMSではビジネスロジックの実装手段に、前回取り上げたExcelシートを用いた意思決定表を用います。意思決定表は、仕様レベルで頻繁に登場する表形式に似ており、技術者でないクライアントでも仕様を理解しやすくなっています。
実際、筆者はクライアントに対して意思決定表で仕様確認を実施しようとした際、元になった表から変わっていないと言われたことがあります。全ての仕様がキレイな表のような意思決定表にできるわけではありませんが、仕様にかなり近い記述を動作させることができる点は、クライアントにとっても大きなメリットだと言えます。表現を工夫していることもありますが、「元の表から変わっていない」というのは、SIerにとって最高の褒め言葉です。
次に、変化に対する強さがあります。BRMSを導入するような事例は、仕様の変更や追加が頻繁にある場合が多く見られます。と同時に、その変化に対して素早く対応することも求められます。
BRMSを用いた場合、意思決定表によって、変化を適用する点が発見しやすくなる効果があります。また、その変化の適用前後を表として見ることができるため、変更点をクライアントが理解しやすくなります。さらに、変化が思わぬ影響を他の仕様に及ぼす場合もありますが、素早く意思決定表に変化を適用し、それを回帰テストすることで、影響範囲の特定も容易にします。これにより、クライアントは変化へのトライを比較的安価に実施することも可能になるのです。
SIer視点
クライアント視点での効果を見たところで、続いてSIerの視点でBRMSの効果について見ていきます。
まずは、クライアント視点と同様に仕様が見える化することです。前述した通り、業務ルールが、クライアントでも分かるように表現できるため、仕様確認が円滑になりますし、メンテナンス時の仕様把握や確認も容易になります。さらに、自身が実装したルールを他者に伝えやすいため引き継ぎが容易になり、他者が実装したルールのメンテナンス時にも何が実現されているのが理解しやすくなります。
続いて、品質を高くできる点があります。近年の業務ルールは複雑化しているため、品質を保つのが難しかったり、コーディングミスをしてしまったりします。BRMSでは、見える化された実装によって複雑な仕様を見通しよく実装できます。また、プログラミング言語に対するテストと同様に、テストフレームワークを用いたテストも可能です。実際に筆者が携わったプロジェクトでは、かなりの数のテストケースをJUnitやSpockを用いて実現しました。テストコードにしておくことで、Jenkinsのようなツールを用いてCIをしたり、容易に回帰テストをしたりできるようになりますので、仕様の変更や追加時にも品質を保ったまま実現できるようになります。
最後に、生産性の向上が挙げられます。BRMSにおける意思決定表は、実装としてそのまま動作します。筆者の体験としては、設計と実装の工程が1つになったような構築をしていきますので、設計と実装の工数削減が見込まれます。また、明らかになった仕様からインクリメンタルに設計・実装をしていけますので、ウォーターフォール型のように全ての仕様が決定していなくても実装を進めていくことができます。さらに、要件定義においてプロトタイプとしてルールを作成することが多いです。これにより、要件の整理がしやすくなり、フロントローディングが進み、トータルの工数が結果的に削減されていきます。