第8回 JBoss BRMS における宣言型プログラミング

コラム/第8回 JBoss BRMS における宣言型プログラミング

Red Hat

2015年10月13日

第8回 JBoss BRMS における宣言型プログラミング

Red Hat JBoss Middleware

「第6回 デモアプリケーションを使って JBoss BRMS を理解する ~ルールフロー~」ではルールを順番に評価する仕組みであるルールフローについてご紹介しました。今回は、JBoss BRMS でルールを定義する際の基本的な考え方である宣言型プログラミングについてご紹介します。

宣言型と手続き型

ルールを定義する際は、JavaやC++などで馴染んでいる手続き的な定義ではなく、宣言的に定義する必要があります。今回は、手続き型と宣言型の違いや、宣言的に定義する際のポイントをご紹介いたします。

宣言型
宣言型では「何をするか(問題の定義=CONDITIONとその際に満たすべき制約=ACTION)」を記述します。記述する条件評価が特定の評価順序や任意の時点に拘束されません。

手続き型
手続き型では、「どうやって処理するか」の手順を、 データ構造とアルゴリズムにより、コンピュータが実行するステップとして詳細に記述します。したがって、評価順序と評価対象の状態に依存します。

宣言型 手続き型
仕様を記述する 手続きを記述する
自己完結 実行の順序に依存する
オブジェクトの状態に依存しない オブジェクトの状態に依存する

表 1 宣言型と手続き型の比較

例えば、コーヒーを注文する時のオプションの選択を考えてみましょう。

図 1 コーヒー注文のやりとり

図 1 コーヒー注文のやりとり

選択条件 コーヒー 紅茶
サイズ 単一選択 S
M
L
砂糖 単一選択 グラニュー糖
ノンカロリー
ミルク 単一選択 ミルク
ローファット
豆乳
プレミアムオプション
(クリーム)
複数選択 生クリーム ◯ 豆乳NG ×
プレミアムオプション
(シロップ)
複数選択 チョコレート
キャラメル

表 2 コーヒーの注文

手続き型での定義は、処理の順序とオブジェクトの状態を意識して判断をします。 飲み物の注文のケースで考えると、種類、サイズ、オプションと順番に選択肢を絞っていき、それまでに選択された内容に従って、次の判断がなされます。

例えば、
コーヒーMサイズでミルクを追加しているならば、プレミアムオプションとして生クリームが選択可能
コーヒーMサイズで豆乳を追加しているならば、プレミアムオプションとして生クリームは選択不可
となります。

前段の選択によって、整合性が保たれるように次の選択肢が絞られているので、前に戻って選択を変更すると、戻った地点以降の選択がリセットされて、再び順番に選択肢を絞っていく必要があります。 このような状況を回避しようと、様々なパターンの条件分岐を作ると、分岐が複雑になってしまい、可読性が悪く、どのような条件に合致した場合にそのルートを通るのかもわからない、メンテナンス不可能なコードになってしまいます。

一方、宣言型の定義では、評価対象が条件に適合するかを判断します。 飲み物の注文のケースで考えると、オプションごとの整合性が保たれていれば、どのような順番で選択したかを気にする必要はありません。

コーヒー注文の例
コーヒーは、S,M,Lサイズが選択可能
コーヒーは、プレミアムオプションで生クリームを選択可能
豆乳と生クリームは、同時に選択不可

コーヒーの注文内容(ファクト)とオプションの組み合わせ(ルール)のマッチングを行い、選択可能な組み合わせを導出してオプションの選択肢を決定したり、チェックすることが可能になります。

図 2 コーヒー注文の仕組み

図 2 コーヒー注文の仕組み

考え方の移行

手続き型に慣れている方が、宣言型でルールを記述する場合には少し発想を変える必要があります。

手続き型の場合は、処理を文で分岐させ、解くべき課題を細分化し if-then の組み合わせを複数作成します。さらに条件を入れ子にして、オブジェクトの状態によって様々な出口(breakで処理を抜ける)を作ることが可能です。


if [条件] then [アクション]
else if [条件]
    if [条件] then [アクション]
    else if [条件] then [アクション]"

手続き型に慣れ親しんでいる場合には、BRMS でルールを記述する際も、このような考え方から離れられず、複合的な評価が必要となった場合に、要件をどのようにルールに落としこむかで迷ってしまうことがあります。

宣言型の場合は、処理を条件式で分岐し、条件によってもたらされる結果は一種類であるということを意識してください。複合的な評価を行う場合も、それぞれの条件を明確な式で表現できる単位で分離してルール同士が依存しないように定義します。

    rule [RULE NAME]
        when
            [CONDITION]
        then
            [ACTION]
    end

ルールの定義は上記のように、条件を表す式=CONDITION と、その式にマッチした場合の制約=ACTION を定義します。 ルールは条件式の単位で分岐(=ルールの単位に相当)しますので、CONDITIONの中で、さらに if 文を使ってさらに分岐をしないようにしましょう。そのようになってしまった場合は、条件式を見直して入れ子の分岐がないようにしていきます。

条件式の単位で分岐するとはどういうことでしょうか?Java の switch 文やSQL の WHERE 節が比較的近いかもしれません。 SQL でPeopleテーブルから性別が男性という条件に該当した行を返す処理を見てみると、SQL の場合は以下のようになります。

select * from People where Peple.gender == "male"

同様のことをルールエンジンで処理する場合は図-3のように「条件 {People.gender == "male"} とファクト{People}をマッチングして、条件に合うもの{性別が男性であるPeople}を結果として返す」となります。

図 3 ルールエンジンでの仕組み

図 3 ルールエンジンでの仕組み

rule "Get_Male
        when
            exists ($people : People(gender == "male"))

まとめ

BRMSを利用する際のポイントは、業務の定義から「データ」「プロセス」「ルール」切り出すことです。さらにルールを定義する上では、分岐を条件式で定義して、宣言的にルールを記述することです。 まずは、手続き的な考え方から少し思考を変えてみるというところからトライしてみてください。

著者紹介

レッドハット株式会社
JBossサービス事業部
ソリューションアーキテクト 大溝 桂 様

サン・マイクロシステムズにてC言語/Java言語を利用した基幹業務システムの開発などを経験後、2012年にレッドハット株式会社に入社。パートナを担当するプリセールスエンジニアとして、JBoss Middlewareの拡販とパートナ企業の技術者育成に従事。

Red Hat コンテンツ一覧

関連商品・キーワード