2021年7月31日土曜日

Kaleidox/状態機械:ヒストリー

前回は状態機械のサブステートを用いてキャンセル機能を実現しました。

サブステートに並ぶ状態機械の重要な機能にヒストリーがあります。

ヒストリーは状態間の遷移時に、遷移元状態の履歴を保持しておく機能で、状態遷移後に元の状態に戻る遷移を行うことができます。

ヒストリーを用いることで、保留/再開機能を記述することができます。今回はこのヒストリーを使ってKaleidoxの状態機械で保留/再開機能を実現します。

モデル

前回のモデルに対して以下の拡張を行っています。

  • suspendイベント、resumeイベントを追加
  • 保留状態を示すsuspendedステートを追加
  • サブステートrunningの任意のステートでsuspendイベントにより保留可能にした

この拡張設定を行った状態機械の定義は以下になります。

* event
event=[{
    name="confirm"
  },{
    name="reject"
  },{
    name="delivered"
  },{
    name="cancel"
  },{
    name="suspend"
  },{
    name="resume"
}]
* statemachine
statemachine={
  name="purchase"
  state=[{
    name=INIT
    transition=[{
      to=running
    }]
  },{
    name=canceled
    transition=[{
      to=FINAL
    }]
  },{
    name=suspended
    transition=[{
      guard=resume
      to=HISTORY
    }]
  }]
  statemachine=[{
    name="running"
    state=[{
      name=applying
      transition=[{
        to=confirming
      }]
    },{
      name=confirming
      transition=[{
        guard=confirm
        to=confirmed
      },{
        guard=reject
        to=rejected
      }]
    },{
      name=confirmed
      transition=[{
        to=delivering
      }]
    },{
      name=rejected
      transition=[{
        to=FINAL
      }]
    },{
     name=delivering
      transition=[{
        guard=delivered
        to=delivered
      }]
    },{
      name=delivered
      transition=[{
        to=FINAL
      }]
    }]
    transition=[{
      guard=cancel
      to=canceled
    },{
      guard=suspend
      to=suspended
    }]
  }]
}

イベント

以下の6つのイベントを定義しています。

confirm
確認OK
reject
確認却下
delivered
配送済み
cancel
キャンセル
suspend
保留
resume
再開

前回のものからはsuspendイベントとresumeイベントを追加しています。

状態機械

定義したモデルを状態機械図で記述すると以下になります。

前回、サブステートrunningを作成し、applying, confirming, confirmed, rejected, delivering, deliveredの各ステートを定義しています。

以下の定義により新たに保留状態を示すステートsuspendedを作成し、サブステートrunningの任意のステートからの状態遷移ができるようにしました。ステートsuspendedからの遷移先はHISTORYになっているので、履歴情報にある直近のステートに復帰します。

  state=[{
...
  },{
    name=suspended
    transition=[{
      guard=resume
      to=HISTORY
    }]
  }]

サブステートrunningからは以下の遷移設定によって、任意のステートでsuspendイベントが発生するとステートsuspendedに遷移します。

    transition=[{
...
    },{
      guard=suspend
      to=suspended
    }]

実行

それでは実行してみます。

まず正常系とrejectイベントの2つのルートを確認します。これは前回と同じ動きになります。

この後に、今回のテーマであるサブステートを利用したsuspendイベント、resumeイベントの振る舞いを確認します。

正常系

最初に正常系の動きです。前回の正常系と同じ動きになります。

まずstatemachine-new関数で状態機械を生成します。生成する状態機械のモデル名はpurchaseです。

生成した状態機械をsetq関数で変数smに束縛します。

状態機械の名前はpurchaseです。状態機械の状態はconfirmingになっています。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]

状態機械purchaseを作成すると、すぐにサブステートrunning内のステートconfirmingに遷移します。

次にevent-issue関数でconfirmイベントを発行します。

confirmイベント発行の結果、状態機械purchaseの状態はdeliveringになりました。引き続きサブステートrunning内です。

kaleidox> event-issue 'confirm
Event[confirm]
kaleidox> sm
StateMachine[purchase:delivering]

次にevent-issue関数でconfirmイベントを発行します。

confirmイベント発行の結果、状態機械purchaseの状態はdeliveringになりました。引き続きサブステートrunning内です。

kaleidox> event-issue 'delivered
Event[delivered]
kaleidox> sm
StateMachine[purchase:FINAL]

これで状態機械の状態遷移は終了です。

reject

続けてrejectイベントのルートも確認しておきます。

statemachine-new関数で状態機械purchaseを生成した直後はconfirming状態になっています。

ここでrejectイベントを発行するとモデルの定義どおり最終状態FINALに遷移しました。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]
kaleidox> event-issue 'reject
Event[reject]
kaleidox> sm
StateMachine[purchase:FINAL]

状態機械purchaseはrejectイベントを受信することで状態rejectedに遷移しますが、状態rejectedから最終状態FINALの間にガードがないので最終状態FINALに自動遷移しています。

suspendとresume

次はsuspendイベントです。サブステートrunning内の任意のステートでsuspendが可能になります。

状態機械purchaseを作った直後、状態機械はステートconfirmingになっています。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]

ステートconfirmingでsuspendイベントを出してみます。以下に示すとおりsuspended状態になりました。

kaleidox> event-issue 'suspend
Event[cancel]
kaleidox> sm
StateMachine[purchase.suspended]

ここでresumeイベントを出すと、suspended前の状態であるステートconfirmingに戻りました。

kaleidox> event-issue 'resume
Event[resume]
kaleidox> sm
StateMachine[purchase.running.confirming]

次には、ステートdeliveringでresume/suspendの動きを確かめます。

状態機械purchaseを作った後にconfirmイベントを出し、delivering状態にします。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]
kaleidox> event-issue 'confirm
Event[confirm]
kaleidox> sm
StateMachine[purchase.running.delivering]

ステートdeliveringでsuspendイベントを出してみます。以下に示すとおりsuspended状態になりました。

kaleidox> event-issue 'suspend
Event[suspend]
kaleidox> sm
StateMachine[purchase.suspended]

ここでresumeイベントを出すと、suspended前の状態であるステートdeliveringに戻りました。ステートsuspendに遷移する前のステートを覚えていて、そのステートに復帰することが確認できました。

kaleidox> event-issue 'resume
Event[resume]
kaleidox> sm
StateMachine[purchase.running.delivering]

まとめ

今回はスブステートをもった状態機械モデルで保留機能をモデル定義し、Kaleidox上で動作させてみました。

前回実現したキャンセル機能と今回の保留機能は実用アプリケーションでは頻出の機能ですが、スクラッチで実装するのはなかなか大変だと思います。これらの機能がモデル定義のみで使用できることは、モデル駆動開発の大きなメリットといえます。

諸元

Kaleidox
0.3.1

2021年6月30日水曜日

Kaleidox/状態機械 : サブステート

前回は状態機械のモデル定義を行い、そのままKaleidoxで動作させることができることを紹介しました。

前回の状態機械はステートがフラットに並んでいる単純なものでしたが、実際のアプリケーションを作成するにはやや不便なところがあります。

というのは、実際のアプリケーションではキャンセルや保留といった状態遷移が必須となってきますが、フラットなステートの遷移では表現が煩雑になったり、実現が困難になったりという問題があるからです。

この問題を解決する仕組みの一つがサブステートです。

今回はこのサブステートをつかってキャンセル機能を実現します。

モデル

前回のモデルに対して以下の拡張を行っています。

  • Cancelイベントを追加
  • 基幹部をサブステートとして、サブステート内の任意のステートでキャンセル可能にした

この拡張設定を行った状態機械の定義は以下になります。

* event
event=[{
    name="confirm"
  },{
    name="reject"
  },{
    name="delivered"
  },{
    name="cancel"
}]
* statemachine
statemachine={
  name="purchase"
  state=[{
    name=init
    transition=[{
      to=running
    }]
  },{
    name=canceled
    transition=[{
      to=FINAL
    }]
  }]
  statemachine=[{
    name="running"
    state=[{
      name=applying
      transition=[{
        to=confirming
      }]
    },{
      name=confirming
      transition=[{
        guard=confirm
        to=confirmed
      },{
        guard=reject
        to=rejected
      }]
    },{
      name=confirmed
      transition=[{
        to=delivering
      }]
    },{
      name=rejected
      transition=[{
        to=FINAL
      }]
    },{
     name=delivering
      transition=[{
        guard=delivered
        to=delivered
      }]
    },{
      name=delivered
      transition=[{
        to=FINAL
      }]
    }]
    transition=[{
      guard=cancel
      to=canceled
    }]
  }]
}

イベント

以下の3つのイベントを定義しています。

confirm
確認OK
reject
確認却下
delivered
配送済み
cancel
キャンセル

前回のものからはcancelイベントを追加しています。

状態機械

定義したモデルを状態機械図で記述すると以下になります。

サブステートrunningを作成し、applying, confirming, confirmed, rejected, delivering, deliveredの各ステートをサブステートrunningに移しました。

また、新たにキャンセル状態を示すステートcanceledを作成し、サブステートrunningの任意のステートからの状態遷移ができるようにしました。

実行

それでは実行してみます。

まず正常系とrejectイベントの2つのルートを確認します。これは前回と同じ動きになります。

この後に、今回のテーマであるサブステートを利用したcancelイベントの振る舞いを確認します。

正常系

最初に正常系の動きです。前回の正常系と同じ動きになります。

まずstatemachine-new関数で状態機械を生成します。生成する状態機械のモデル名はpurchaseです。

生成した状態機械をsetq関数で変数smに束縛します。

状態機械の名前はpurchaseです。状態機械の状態はconfirmingになっています。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]

状態機械purchaseを作成すると、すぐにサブステートrunning内のステートconfirmingに遷移します。

次にevent-issue関数でconfirmイベントを発行します。

confirmイベント発行の結果、状態機械purchaseの状態はdeliveringになりました。引き続きサブステートrunning内です。

kaleidox> event-issue 'confirm
Event[confirm]
kaleidox> sm
StateMachine[purchase:delivering]

次にevent-issue関数でconfirmイベントを発行します。

confirmイベント発行の結果、状態機械purchaseの状態はdeliveringになりました。引き続きサブステートrunning内です。

kaleidox> event-issue 'delivered
Event[delivered]
kaleidox> sm
StateMachine[purchase:FINAL]

これで状態機械の状態遷移は終了です。

reject

続けてrejectイベントのルートも確認しておきます。

statemachine-new関数で状態機械purchaseを生成した直後はconfirming状態になっています。

ここでrejectイベントを発行するとモデルの定義どおり最終状態FINALに遷移しました。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]
kaleidox> event-issue 'reject
Event[reject]
kaleidox> sm
StateMachine[purchase:FINAL]

状態機械purchaseはrejectイベントを受信することで状態rejectedに遷移しますが、状態rejectedから最終状態FINALの間にガードがないので最終状態FINALに自動遷移しています。

cancel

次はcancelイベントです。サブステートrunning内の任意のステートでcancelが可能になります。

まずステートconfirmingでcancelイベントを出してみます。以下に示すとおりFINAL状態になりました。状態機械がcancelイベントを受信した結果、ステートcanceledに遷移し、ステートcanceledにはガードを設定していないのでFINAL状態に遷移しています。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]
kaleidox> event-issue 'cancel
Event[cancel]
kaleidox> sm
StateMachine[purchase:FINAL]

次にステートdeliveringでcancelイベントを出してみます。以下に示すとおりこちらもFINAL状態になりました。

kaleidox> statemachine-new 'purchase
StateMachine[purchase.running.confirming]
kaleidox> setq sm
StateMachine[purchase.running.confirming]
kaleidox> event-issue 'confirm
Event[confirm]
kaleidox> sm
StateMachine[purchase.running.delivering]
kaleidox> event-issue 'cancel
Event[cancel]
kaleidox> sm
StateMachine[purchase:FINAL]

いずれの場合もサブステートrunninigに設定した以下の遷移によって、サブステート内の状態からcanceled状態に遷移することができました。

    transition=[{
      guard=cancel
      to=canceled
    }]

まとめ

サブステートをもった状態機械モデルでキャンセル機能をモデル定義し、Kaleidox上で動作させてみました。

キャンセル機能は実際のアプリケーションでも頻出の機能ですが、実装するのは案外煩雑なので、サブステートを用いたシンプルなモデル定義のみでそのまま動作するのは大きなメリットだと思います。

サブステートを使った別の頻出機能として保留機能があります。次回は状態機械モデルとKaleidoxで保留機能を実現する予定です。

諸元

Kaleidox
0.3.0

2021年5月31日月曜日

Kaleidox/状態機械

オブジェクト指向分析設計(OOAD)によるソフトウェア開発を進めるための鍵となるのが状態機械です。

Javaなどのオブジェクト指向言語では状態機械は直接サポートはされておらず、状態機械を実現するためのクラスライブラリもよいものがありません。ワークフローエンジンといったものはありますが、仕掛けが大きすぎるので状態機械を実装するために手軽に使用できる感じではないでしょう。

このため、モデリング段階で状態機械を定義しても、プログラミング段階では手組みになってしまうので、モデリングすることの価値がそれほど高くないという状況になっています。また、状態機械をプログラミングで実装するのは案外大変です。

このこともあってか、開発現場では状態機械はほとんど使われていない状況だと思います。

OOADは静的構造モデル(クラス図)と動的モデル(状態機械)が両輪で、その2つのモデルと要求仕様をシナリオ分析であるユースケースモデルで連携させるという仕掛けになっています。

両輪の一つである動的モデルが使用されていないので、当然静的構造モデルと動的モデル、要求仕様を連携させるユースケースモデルも実力を発揮できない状況にあるといえます。

結果として、OOADではなくクラス図を用いたデータ中心設計になってしまっているのが現状ではないでしょうか。

クラウドアプリケーションでは、今後ますますイベント駆動型の応用が重要になってくると予想されますが、この核となるモデルが状態機械であり、状態機械がうまく活用されていない現状はかなり危機的な状況ではないかと思います。

SimpleModelingではこの問題に対処するため、モデルコンパイラSimpleModelerとアクション言語Kaleidoxで状態機械をサポートします。モデリング段階で状態機械モデルを定義することで、状態機械のプログラミングをせずに、アプリケーションでそのまま状態機械を利用できることになります。

今回はKaleidoxで状態機械を使用してみます。

モデル

Kaleidoxで状態機械を動かしてみましょう。

まず状態機械に使用するイベントを定義した後、状態機械のモデルを定義します。

商品販売を単純化したモデルにしてみました。本来は、注文毎に状態機械を持つことになりますが、ここでは簡単化のためグローバルな状態機械をグローバルなイベントで駆動することにします。

* event
event=[{
    name="confirm"
  },{
    name="reject"
  },{
    name="delivered"
}]
* statemachine
statemachine={
  name="purchase"
  state=[{
    name=applying
    transition=[{
      to=confirming
    }]
  },{
    name=confirming
    transition=[{
      guard=confirm
      to=confirmed
    },{
      guard=reject
      to=rejected
    }]
  },{
    name=confirmed
    transition=[{
      to=delivering
    }]
  },{
    name=rejected
    transition=[{
      to=final
    }]
  },{
    name=delivering
    transition=[{
      guard=delivered
      to=delivered
    }]
  },{
    name=delivered
    transition=[{
      to=final
    }]
  }]
}

イベント

以下の3つのイベントを定義しています。

confirm
確認OK
reject
確認却下
delivered
配送済み

状態機械

定義したモデルを状態機械図で記述すると以下になります。

実行

それでは実行してみます。

まずstatemachine-new関数で状態機械を生成します。生成する状態機械のモデル名はpurchaseです。

生成した状態機械をsetq関数で変数smに束縛します。

状態機械の名前はpurchaseです。状態機械の状態はconfirmingになっています。

kaleidox> statemachine-new 'purchase
StateMachine[purchase:confirming]
kaleidox> setq sm
StateMachine[purchase:confirming]

次にevent-issue関数でconfirmイベントを発行します。

confirmイベント発行の結果、状態機械purchaseの状態はdeliveringになりました。

kaleidox> event-issue 'confirm
Event[confirm]
kaleidox> sm
StateMachine[purchase:delivering]

次にevent-issue関数でconfirmイベントを発行します。

confirmイベント発行の結果、状態機械purchaseの状態はdeliveringになりました。

kaleidox> event-issue 'delivered
Event[delivered]
kaleidox> sm
StateMachine[purchase:final]

これで状態機械の状態遷移は終了です。

状態機械の遷移の履歴をhistoryメソッドで取得することができます。

kaleidox> sm.history
((Event[system.control.init] . State[applying]) (Event[system.control.go-ahead] . State[confirming]) (Event[confirm] . State[confirmed]) (Event[system.control.go-ahead] . State[delivering]) (Event[delivered] . State[delivered]) (Event[system.control.go-ahead] . State[final]))

historyメソッドで取得した結果を元に状態遷移の経緯をまとめると以下になります。

イベント遷移先
system.control.initapplying
system.control.go-aheadconfirming
confirmconfirmed
system.control.go-aheaddelivering
delivereddelivered
system.control.go-aheadfinal

まず、初期状態から自動的に先頭の状態であるapplyingに遷移します。イベントは初期化を示す疑似イベントであるsystem.control.initです。

状態applyingと状態confirming間にはガードがないので状態間を自動的に遷移します。イベントは自動遷移を示す疑似イベントであるsystem.control.go-aheadです。状態機械モデルですが、アクティビティモデル的な振舞いになります。

ここでconfirming状態となります。

次にevent-issue関数でconfirmイベントを発行すると、confirming状態からconfirmed状態に遷移します。

状態confirmedと状態delivering間にはガードがないので状態間を自動的に遷移します。

ここでdelivering状態となります。

次にevent-issue関数でdeliveredイベントを発行すると、delivering状態からdelivered状態に遷移します。

状態deliveredと最終状態final間にはガードがないので状態間を自動的に遷移し、状態機械purchaseは終了します。

reject

続けてrejectイベントのルートも確認しておきます。

statemachine-new関数で状態機械purchaseを生成した直後はconfirming状態になっています。

ここでrejectイベントを発行するとモデルの定義どおり最終状態finalに遷移しました。

kaleidox> statemachine-new 'purchase
StateMachine[purchase:confirming]
kaleidox> setq sm
StateMachine[purchase:confirming]
kaleidox> event-issue 'reject
Event[reject]
kaleidox> sm
StateMachine[purchase:final]

状態機械purchaseはrejectイベントを受信することで状態rejectedに遷移しますが、状態rejectedから最終状態finalの間にガードがないので最終状態finalに自動遷移しています。

まとめ

Kaleidoxで状態機械モデルの実行を行うことができるようになりました。

今回は最もシンプルなモデルですが、このレベルのモデルでもプログラミングレスで使用できるとかなり便利だと思います。

状態機械モデルはもっと複雑な記述が可能で、より広範囲な応用に適用することができます。次回以降、状態機械モデルの色々な使い方について見ていく予定です。

諸元

Kaleidox
0.2.1

2021年4月30日金曜日

Kaleidox/Service

前回はソフトウェア開発の中軸モデル要素であるコンポーネントのメタモデルについて検討しました。

今回はコンポーネントの派生モデル要素であるサービスについて取り上げます。

サービスは外部に対して公開されたコンポーネントという位置付けなので、外部から直接実行できるコンポーネントということができます。

Kaleidoxでサービスモデルを直接実行することができるので、サービスモデルを使ってコンポーネントの特性を見ていきたい思います。

今回はサービスのAPIを定義して、Kaleidox上で実行してみます。

サービスモデル

足し算と引き算を行うサービスcalcを以下のように定義しました。この定義に沿って、サービスモデル(コンポーネントモデル)の定義について説明します。

* Service
** calc
*** Operation
**** plus
***** In
| 名前 | 型  | 多重度 |
|------+-----+--------|
| arg1 | int |      1 |
| arg2 | int |      1 |
***** Out
| 型  | 多重度 |
|-----+--------|
| int |      1 |
***** Method
+ arg1 arg2
**** minus
***** In
| 名前 | 型  | 多重度 |
|------+-----+--------|
| arg1 | int |      1 |
| arg2 | int |      1 |
***** Out
| 型  | 多重度 |
|-----+--------|
| int |      1 |
***** Method
****** js
arg1 - arg2

全体構造

サービスモデルの全体構造は以下のようになっています。

* Service
** サービス名
*** Operation
**** オペレーション名
***** In
***** Out
***** Method

Service節でサービスモデルの定義を行います。

Service節の直下にはサービス名を節名としたサービスの定義が並びます。

サービス名節の直下にはOperation節があります。

Operation節の直下にはオペレーション名を節名としたオペレーションの定義が並びます。

オペレーションの定義は次節で説明します。

拡張予定

前回、コンポーネントの部品として検討した部品の中でAPIに該当する部品をサポートしています。

以下の部品は現在は未実装です。

  • SPI
  • Bus
  • StateMachine
  • Entity
  • Configuration
  • Rule
  • Log
  • Metrics
  • Audit trails

これらのモデル要素はkaleidox上で順次実現していく予定です。

オペレーション

plusオペレーションの定義は以下になります。

*** Operation
**** plus
***** In
| 名前 | 型  | 多重度 |
|------+-----+--------|
| arg1 | int |      1 |
| arg2 | int |      1 |
***** Out
| 型  | 多重度 |
|-----+--------|
| int |      1 |
***** Method
+ arg1 arg2

オペレーションの定義は以下の3つです。

In
入力定義
Out
出力定義
Method
Method定義

In節には入力情報を表形式で記述します。表では入力パラメタの名前、型、多重度を定義します。

Out節には出力情報を表敬式で記述します。表では出力パラメタの型、多重度を記述します。

Method節にはオペレーションの実装であるメソッドの定義を行います。

メソッド

Method節では、オペレーションの実装であるメソッドの定義を行います。

モデルが仕様のみで実装まで定義しない場合はMethod節を省略することができます。

ただし、Method節を省略した場合はKaleidoxでの直接実行はできません。手動で作成したプログラムを、SimpleModelerのプログラム自動生成と組み合わせて使用する形になります。

Kaleidox

オペレーションの実装をKaleidoxスクリプトで定義する場合は、Method節に直接Kaleidoxスクリプトを記述します。

サービスモデルのplusオペレーションの下には、以下のMethod節を定義しています。

***** Method
+ arg1 arg2

calcサービスのplusオペレーションが呼び出されると、Kalidoxスクリプト「+ arg1 arg2」が実行され、その結果が返却されます。

JavaScript

Method節の下にjs節が配置されている場合は、js節内をMethod実現のためのJavaScriptスクリプトとして使用します。

***** Method
****** js
arg1 - arg2

calcサービスのminusオペレーションが呼び出されると、JavaScriptスクリプト「arg1 - arg2」が実行され、その結果が返却されます。

Java ScriptEngine

Method節の下には、JavaScript以外にもJava ScriptEngineでサポートしているスクリプト言語を使用することができます。この場合は、Java ScriptEngineの認識する言語名を節名で指定します。

拡張予定

メソッドの実現方法として、外部のJava/Scalaプログラムを利用可能にする予定です。以下の形式が候補となっています。

  • JavaBeans (JAR)
  • Servlet (WAR)
  • OSGi

実行

それでは、Kaleidoxでサービスモデルを直接実行してみます。

前述のサービスモデルをinit.kldに格納してkaleidoxが認識できるようにします。

コマンド

まず、コマンドラインで実行してみます。

$ klaidox calc.plus 1 2
3

サービス名とオペレーション名を「.」で繋いだ文字列でオペレーション名を指定します。calcサービスのplusオペレーションなので「calc.plus」となります。

引数には「1」と「2」を指定した結果、計算結果の3が返されました。

REPL

次はKaleidoxのREPLで実行してみます。

REPLのプロンプトから「calc.plus 1 2」と実行すると、計算結果の3が返されました。

kaleidox> calc.plus 1 2
3

トレース

calc.plusの実行時のコールツリーは、REPLコマンド「:trace」で表示することができます。先程の「calc.plus 1 2」の場合は以下になります。

kaleidox> :trace
INVOKE(302)[Script] (calc.plus 1 2) => 3
  INVOKE(104)[Function(Operation):service-script-kaleidox(calc.plus)] (calc.plus 1 2) => 3
    INVOKE(60)[Lambda:calc.plus] (1 2) => 3
      INVOKE(53)[Script] (+ arg1 arg2) => 3
        INVOKE(23)[Function(Eval):+] (+ arg1 arg2) => 3
          INVOKE(15)[Variable:arg1] arg1 => 1
          INVOKE(1)[Variable:arg2] arg2 => 2

Web REST

KaleidoxをWebで実行するためのコンテナとしてpbjを開発しました。

  • https://github.com/asami/pbj

pbjを実行するとWebサーバーが立ち上がります。ポート番号は8080です。

$ pbj

curlコマンドでpbjサーバーを呼び出します。

パス名はサービス名「calc」、オペレーション名「plus」をつなげた「/calc/plus」です。引数にはarg1、arg2にそれぞれ「1」、「2」を指定します。

$ curl "http://localhost:8080/calc/plus?arg1=1&arg2=2"
{"status":200,"data":3}

実行の結果、JSONの形式で実行結果が返されました。プロパティdataに計算結果の「3」が入っています。

jqコマンドを併用してJSONを整形すると、以下のようになります。

$ curl "http://localhost:8080/calc/plus?arg1=1&arg2=2" | jq .
{
  "status": 200,
  "data": 3
}

トレース

Webサーバ上で実行したときのコールツリーは「_trace」パラメタを「true」にすると取得することができます。

$ curl "http://localhost:8080/calc/plus?arg1=1&arg2=2&_trace=true"  | jq
{
  "status": 200,
  "data": 3,
  "trace": {
    "kind": "root",
    "trace": [
      {
        "kind": "invoke",
        "timestamp": "1619340084576",
        "label": "Script",
        "enter": "(calc.plus :arg1 1 :arg2 2)",
        "leave": "3",
        "lap": 8,
        "trace": [
          {
            "kind": "invoke",
            "timestamp": "1619340084577",
            "label": "Function(Operation):service-script-kaleidox(calc.plus)",
            "enter": "(calc.plus :arg1 1 :arg2 2)",
            "leave": "3",
            "lap": 6,
            "trace": [
              {
                "kind": "invoke",
                "timestamp": "1619340084578",
                "label": "Lambda:calc.plus",
                "enter": "(1 2)",
                "leave": "3",
                "lap": 5,
                "trace": [
                  {
                    "kind": "invoke",
                    "timestamp": "1619340084581",
                    "label": "Script",
                    "enter": "(+ arg1 arg2)",
                    "leave": "3",
                    "lap": 2,
                    "trace": [
                      {
                        "kind": "invoke",
                        "timestamp": "1619340084582",
                        "label": "Function(Eval):+",
                        "enter": "(+ arg1 arg2)",
                        "leave": "3",
                        "lap": 1,
                        "trace": [
                          {
                            "kind": "invoke",
                            "timestamp": "1619340084582",
                            "label": "Variable:arg1",
                            "enter": "arg1",
                            "leave": "1",
                            "lap": 0
                          },
                          {
                            "kind": "invoke",
                            "timestamp": "1619340084582",
                            "label": "Variable:arg2",
                            "enter": "arg2",
                            "leave": "2",
                            "lap": 1
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

まとめ

サービスのモデルを作成し、Kaleidoxで直接実行してみました。今回はAPIのみでしたが、コンポーネントの回に検討したBusなどのメカニズムとそのモデルについても順次実現していく予定です。

同じモデルがコマンドライン、REPL、Webのそれぞれでそのまま実行できることを確認できました。モデルを直接実行できれば、プログラミングの工数削減、仕様と実装のズレの低減といった大きなメリットがあります。

また、Kaleidoxのようなモデル実行プラットフォームが提供するアプリケーションフレームワーク機能により、ドメインモデルではスコープ外の非機能要件についても自動的に利用可能になるメリットもあります。

今回はKaleidoxが提供する機能であるトレース機能を紹介しました。実運用では、本番環境でしか発生しない障害などが発生することが多々ありますが、トレース機能を用いると効率的に障害調査を行うことができることを期待できます。

諸元

Kaleidox
0.1.16
Pbj
0.0.2

2021年3月31日水曜日

SimpleModeling/Component

SimpleModelingでは、コンポーネントをソフトウェア開発を行う上での中軸となるモデル要素と捉えています。今回はコンポーネントのメタモデルを検討します。

コンポーネントはオブジェクトやサービス、システムと同様にメタモデル上は分類子(classifier)を親としており分類子の構造を引き継いでいます。コンポーネントのメタモデルの検討を行うのはコンポーネントのメタモデルを軸に、上方向ではサービスやシステム、下方向ではオブジェクトのメタモデルを考える上でのベースラインにする狙いもあります。

Componentの構造

SimpleModelingではComponentの構造を以下の図に示すメタモデルをベースにメタモデルの検討を行っています。

以下でそれぞれのモデル要素についてみていきます。

API

本案では以下の3つのAPIを定義しました。

  • Service API
  • Management API
  • Resource API

APIではOperation群を定義します。

Operationの実装はプログラム言語のメソッドが基本で、必要に応じてRESTを含むRPCとして実装します。

Service API

コンポーネント利用者向けのAPIです。

Webなどフロントエンド・アプリケーションやその延長線上にある他コンポーネントからの利用を想定しています。

Management API

コンポーネントの提供する機能やコンポーネントが管理するデータの運用管理をするためのAPIです。

管理コンソールやその延長線上にある他コンポーネントからの利用を想定しています。

Resource API

リソース操作用のAPIです。

リソース操作用のAPIは個々のOperationの責務は前述のService API、Management APIに分類されるため分類上の重複がありますが、モデルからの自動生成の対象なので図では独立した形で記述しています。

SPI

SPI(Service Provider Interface)はComponentに対してサービスを影響するコンポーネントやオブジェクトを接続するためのインタフェースです。

たとえば、ECシステムで外部の決済サービスを利用する場合、決済サービスを呼び出しすためのドライバを作成しSPIを通じてコンポーネントと接続します。

SPIを経由して接続する外付けのプログラムでComponentの機能を拡張していくことができます。このため、SPIはComponentの拡張点(Extension Point)ということができます。

Bus

クラウド・アプリケーションを開発する上で重要な構成要素がBusです。クラウド・アプリケーションはクラウド内で発生する各種イベントに即応するためイベント駆動型の振舞いが極めて重要です。単純にAPIが提供するOperationを呼び出すだけの処理ではまかないきれなくなっているわけです。

このクラウドワイドなイベント駆動処理の基盤となるのがBusです。

SimpleModelingではBusを第一級の構成要素としてメタモデル上での扱いを明確にし、SimpleModelerやKaleidoxといったツールでもBusの使用を前提とした機能セットを提供する予定です。

Busには以下の示す特性があります。

  • イベント駆動
  • 透過性
  • 疎結合
  • 非同期
  • スケーラビリティ
  • 可用性(availablity)

これらの特性はクラウド・アプリケーションを構築する上で重要な役割を担います。

Busも用途に応じていくつかの種類が考えられます。図では以下のBusを示しています。

  • Service Bus
  • Inter-Component Bus
  • Async Bus
  • Sync Bus

それぞれ見ていきましょう。

Service Bus

ネットワークワイドでコンポーネント間の同報通知を行うバスです。

Apache KafkaやAWS SNS、AWS Kinesis、AWS EventBridgeといったサービスの利用を想定しています。

基本のBusとなります。Service Busを使うことでComponent内のObject間通信もインターネットワイドなサービス間の通信も透過的に行うことができるので、理想的にはService Busのみを使用するのが望ましいといえます。

ただ、現実のアプリケーションではさまざまなニーズが存在するので、それらのニーズをすくい取るためにメタモデルでは用途に応じたBusを定義しています。

Inter-Component Bus

同一プロセス内でComponentを接続するバスです。

通常のOperationに対してBusを使う上での問題点として以下のものがあります。

  • 非同期になってしまう。
  • データベース・トランザクションの制御から外れてしまう。

非同期の問題点はエラー情報をその場ではクライアントに伝えることができなくなることです。このため大掛かりなエラー処理の仕掛けを作る必要が出てくるのでアプリケーション開発の複雑度が一気に増加します。

いうまでもなくデータベース・トランザクションから外れてしまう問題もエラー処理の複雑度が大きく増加します。

もちろんBusの提供するイベント駆動、透過性、疎結合の特性は魅力的です。

そこで同一プロセス内で動くComponentやObject間の協業では、本来同期型&トランザクションは可能なはずなので、イベント駆動、透過性、疎結合の特性を持ちつつ、同期型&トランザクションのサポートを行うBusとしてInter-Component Busを用意しました。

Async Bus と Sync Bus

Component内部で使用するBusです。このメタモデルでは以下の2つに分けています。

  • Async Bus
  • Sync Bus

いずれもComponent内に閉じていることにより効率的な実行を想定しています。

Async Busはシグナルの同報処理を非同期で行うバスです。Service Busと同じ特性を持ちます。

Sync Busははシグナルの同報処理を同期で行うバスです。Inter-Component Busと同じ特性を持ちます。

Async BusとSync Busは、プラットフォームによってはそれぞれService Bus、Inter-Component Busを直接使用する方式でよいかもしれません。

Object

Component内には用途ごとに各種オブジェクトが存在することになります。

図では以下のObjectを図示しています。

  • Service API, Management API, Resource APIを司るObject
  • SPIを司るObject
  • Bus(Async Bus, Sync Bus)に接続したObject
  • Entity
  • 図の中央にあり各Objectを中継しているObject

StateMachine

Objectのメタモデルを定義する上で重要と考えているのがState Machineです。本来オブジェクト指向の動的モデルはState Machineを使ってモデル化するのが筋ですが、既存のプログラミング言語に該当する機能がないこともあり、一般のエンタープライズやWebアプリケーションでは現状はほとんど利用されることがないと思います。

しかし、イベント駆動が重要な位置を占めるクラウド・アプリケーションではStateMachineが動的モデルの要のモデルです。このためSimpleModeingではStateMachineをメタモデルで定義し、SimpleModelerやKaleidoxといったツールで直接使用できるようにする予定です。

Entity

データベースに格納して管理するPersistent ObjectをSimpleModelingではEntityと呼びます。

SimpleModelingではEntityはデータベース内にあるため直接操作はせず、一旦メモリ内のObjectに転記し、転記したObjectで状態を更新した上ででデータベース上のEntityに書き戻すと、という操作モデルを取ります。

メモリ内のObjectに転記する場合に、必ずしもデータベース上のEntityのクローンである必要はなく、アプリケーションのモデルに応じたメモリ内のObjectに必要な情報を転記することになります。

EntityはStateMachineを持つことができます。実装的には、Entityをメモリ上に展開したObjectにStateMachineを定義し、そのStateMachineが動作するという形になります。

設定

Componentの振舞いをComponentの想定した範囲で変えるための変化点(Variation Point)のメカニズムとして以下の2つを用意しました。

  • Configuration
  • Rule

Configuration

ロケールやタイムゾーンといったアプリケーションの国際化情報やタイムアウト時間など、Componentの基本的な振舞いに対するパラメタ設定を行います。。

格納場所は配備時にファイルを添付したり、外部のリポジトリに格納といった手段が考えられます。

Rule

アプリケーションがモデル化したRuleを、アプリケーションのユースケースに合わせて設定します。

消費税率といったパラメタ的なものから、エキスパート型AIの推論ルールのようなものまでを想定しています。

記録

運用上の様々な要件からコンポーネントの動作記録を取っておく必要があります。

  • Log
  • Metrics
  • Audit trail

Log

動作ログです。

アプリケーションの各種メトリックスの計算、デバッグ情報、性能改善の基礎データ、課金情報として用いることを想定しています。

上記の用途に必要な情報を採取できるよう、ログとして採取する情報についても分析・設計が必要です。

Audit trail

セキュリティの監査記録です。セキュリティ監査のための基本情報としてユーザーがComponentをどのように使ったか、どのリソースを参照・更新したかの記録を取ります。

Logよりも厳密な情報を採取する必要があるので、モデルを分けています。

Metrics

コンポーネントの振る舞いをデータ化したメトリックス情報です。オペレーションの呼び出し回数やキャッシュのヒット率といった情報を記述します。

性能改善の基礎データや課金情報として用いることを想定しています。

まとめ

今回はSimpleModelingで重要視しているモデル要素であるComponentについてメタモデルを検討しました。

次回はこのメタモデルをベースに、ComponentをKaleidoxで扱う方法について考えてみます。

2021年2月28日日曜日

Kaleidox/データ型

アプリケーション開発をモデル駆動で行う時に、見過ごしがちですが案外重要なのがデータ型の扱いです。

データ型の標準化

一般的にプログラミング言語では数値や文字列を中心に必要最小限のデータ型を定義し、アプリケーションで必要なデータ型はクラスライブラリで定義して使用するという建付けになっています。

UMLを使用したモデリングも事情は同じで、アプリケーションで必要なデータ型を定義して使用することになります。プログラミング言語と違ってクラスライブラリ的な共通モジュールはあまり提供されていないので、データ型の問題はより深刻といえます。

まだモデル駆動開発という観点からは、モデリング側のデータ型とプログラミング言語側のデータ型の連携も問題となります。

このためアプリケーション開発を始めるにあたっては、アプリケーション開発者側で以下の定義が必要になります。

  • モデリングでのデータ型
  • プログラミング言語でのデータ型
  • モデリングのデータ型とプログラミング言語のデータ型のマッピング

エンタープライズアプリケーションは最初に小さなWebシステムを作るだけであっても、次々と追加のアプリケーションを開発し、それらを連携させて動作させることになりがちです。このような場合、アプリケーションごとに独自のデータ型を定義指定使っていては連携に支障が出てくる可能性が高いでしょう。

リテラル問題

データ型の標準化を行う際には、データ型の文字列表現であるリテラルの標準化も重要な問題です。

モデリング、プログラミング、データ入出力の各フェーズでデータの表現形式が異なるのは非効率ですし、トラブルの元になります。

移入、移出するデータフォーマットの統一という観点からもリテラルの標準化、共通化が重要です。

国際化

アプリケーション開発で、分かっていても開発期間や工数の関係から後回しになりがちなのが国際化(I18N, L10N)です。

直近では使わないかもしれないけれど、海外展開する時には必要になる、という優先度の見えにくい機能なのでアプリケーションを普通に開発すると自然と国際化対応できているという形が理想的です。

ここで鍵になるのがデータ型です。時間や文字列などで国際化を意識したデータ型を用いることで、特別な意識なしに開発したアプリケーションを国際化対応にすることが可能になります。

SimpleModelingでの解決策

データ型の問題に対しては、上流のモデリングからプログラミングまで共通のデータ型を共通化するのが有力な作戦です。

本Blogで進めているSimpleModelingでは以下のアプローチで対応しています。

  • Action言語Kaleidoxで、アプリケーション向けのデータ型を定義する
  • データ型はできるだけ文字列リテラルで記述可能にする
  • SimpleModelerでのモデリングでKaleidoxで定義したデータ型を使えるようにする
  • 移入、移出するデータフォーマットもデータ型のリテラルを扱えるようにする

実行例

データ型をリテラルで指定する例です。

準備

準備として以下のinit.kldを用意します。

schema区画でスキーマpersonを定義しています。

data-store区画でデータベースのテーブルpersonに移入するデータを定義しています。

* env

db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false"

* schema

** person

| 特性 | 名前          | 型       | 多重度 | ラベル  |
|------+---------------+----------+--------+---------|
| 属性 | id            | int      | 1      | User ID |
| 属性 | name          | string   | 1      | 名前    |
| 属性 | city          | string   | ?      | 市      |
| 属性 | age           | int      | ?      | 年齢    |
| 属性 | registered_at | datetime | ?      | 登録日  |

* data-store

** person

100,Taro,Yokohama,28,2021-01-10T00:00:00
200,Hanako,Kawasaki,24,2021-02-20T00:00:00

データ定義の際に「2021-01-10T00:00:00」という形で日時をリテラルで記述しています。これはローカル日時を記述するデータ型localdatetime型のデータとなります。

データベース移入時には、実行環境のタイムゾーンを補完したdatetime型のデータに自動的にマッピングされます。

使用例

上記のinit.kldに初期化の結果、インメモリデータベースのpersonテーブルにデータが2件移入されています。

store-select関数で取得すると以下になります。

kaleidox> store-select 'person
Table[5x2]
kaleidox> :show
Table[5x2]
┏━━━┯━━━━━━┯━━━━━━━━┯━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃id │name  │city    │age│registered_at            ┃
┣━━━┿━━━━━━┿━━━━━━━━┿━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃100│Taro  │Yokohama│35 │2021-01-10T00:00:00+09:00┃
┃200│Hanako│Kawasaki│24 │2021-02-20T00:00:00+09:00┃
┗━━━┷━━━━━━┷━━━━━━━━┷━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━┛

このテーブルに対して30代の会員の検索を行います。

「30代」を30以上、39以下と考えるとinterval型のリテラル「30~39」で記述することができます。

このリテラルを検索条件に指定すると、目的通りの結果が出力されました。

kaleidox> store-select 'person age=30~39
Table[5x1]
kaleidox> :show
Table[5x1]
┏━━━┯━━━━┯━━━━━━━━┯━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃id │name│city    │age│registered_at            ┃
┣━━━┿━━━━┿━━━━━━━━┿━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃100│Taro│Yokohama│35 │2021-01-10T00:00:00+09:00┃
┗━━━┷━━━━┷━━━━━━━━┷━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━┛

次に2021年2月1日以降の入会者の検索はを行います。

「2021-02-01~」はlocaldatetimeinterval型として解釈されます。

データベース検索時にはタイムゾーンの補完が必要ですが、これはKaleidoxの実行コンテキストによって補完されます。

kaleidox> store-select 'regestered_at=2021-02-01~
Table[5x1]
kaleidox> :show
Table[5x1]
┏━━━┯━━━━━━┯━━━━━━━━┯━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃id │name  │city    │age│registered_at            ┃
┣━━━┿━━━━━━┿━━━━━━━━┿━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃200│Hanako│Kawasaki│24 │2021-02-20T00:00:00+09:00┃
┗━━━┷━━━━━━┷━━━━━━━━┷━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━┛

このリテラルを検索条件に指定すると、目的通りの結果が出力されました。

RESTサーバーでの指定

将来KaleidoxをRESTサーバー化した場合は以下のような指定方法になる想定です。

curl https://example.com/person?age=30~39

リテラル「30~39」という表現でデータ型intervalのデータを、モデリング段階の表記と同じ表記で記述できています。

SimpleModelerとの関係

init.kldのschema区画でデータのスキーマを定義していました。このスキーマでデータ型を指定していますが、このデータ型はSimpleModelerと共通のものになります。

SimpleModelerでのモデル定義からKaleidoxでのスキーマ定義へ、データ型がシームレスに引き継がれます。

まとめ

モデル駆動開発の重要な要素技術であるデータ型に対して、モデリングからプログラミング、データ記述までデータ型、リテラルを共通化するアプローチについて説明しました。

Kaleidoxを中心にSimpleModelerと共通のデータ型、リテラルを使用することでモデリングからプログラミング、運用までシームレスにデータ型を連携させることができます。

標準で共通化できるデータ型を十分に用意できれば、非常に強力なアプローチになると思います。アプリケーション開発に必要なデータ型については必要に応じて拡張していく予定です。

諸元

  • Kaleidox : 0.1.14

データ型一覧

現時点でKaleidoxで定義しているデータ型一覧です。

データ型説明
booleanBool値
shortShort型整数
intInt型整数
longLong型整数
floatFloat型浮動小数点数
doubleDouble型浮動小数点数
integer整数
decimal10進固定小数点数
rational有理数
complex複素数
rangeレンジ
intervalインターバル
string文字列
binaryバイナリ
i18nstring国際化文字列
i18ntemplate国際化テンプレート
regex正規表現
clobCLOB
blobBLOB
slipスリップ(伝票)
schemaスキーマ
queryクエリ
recordレコード
tableテーブル
vectorベクター
matrixマトリックス
dataframeデータフレーム
lxsvLXSV
urlURL
urnURN
uriURI
expression
scriptスクリプト
xmlXML
htmlHTML
xpathXPath
xslXSL
pugPUG
jsonJSON
datetime日時(タイムゾーン付き)
localdatetimeローカル日時
localdateローカル日
localtimeローカル時
montyday月日
datetimeinterval日時インターバル
localdatetimeintervalローカル日時インターバル
duration経過時間
periodピリオド
money金額
percentパーセント
unit単位

2021年1月31日日曜日

SimpleModeling 2021

Modegramming Styleブログではモデリングとプログラミングの一体化を指向したModegrammingというコンセプトを提唱しており、その実現のための技術体系としてSimpleModelingを整備しています。

整備活動

2019年5月に以下の記事でSimpleModelingによるモデル駆動開発の活動をリブートしました。

整備活動の内容はプロダクトの開発とメタモデルの整備に分けられます。

プロダクト

SimpleModelingでは以下の4つのプロダクトの開発を進めています。いずれもオープンソースです。

また商用製品としてボクがCTOをやっているEverforth社でクラウドプラットフォームであるPrefer Cloud Platform(以下PCP)を開発しています。

Smartdox

SmartDoxは以前開発していたSmartDocの後継となる汎用の文書処理系です。

SmartDocはXMLをメタ言語としていましたが、SmartDoxは独自のプレインテキスト(MarkDownとEmacs orgから派生)をメタ言語としています。

SimpleModelingではLiterate Modeilingのアプローチを取っているので、モデルの中の自然言語記述部分の取扱いを重要視しています。

この部分の中核技術となるのがSmartDoxというわけです。

後述するSimpleModelerやKaleidoxはSmartDoxをメタ言語として使用し、この上に固有のメタモデルを構築しています。

SimpleModeler

SimpleModelerはSimpleModelのモデルからプログラムなどの成果物を生成するモデルコンパイラです。

SmartDoxをメタ言語として記述し、SimpleModelメタモデルのインスタンスとして記述したモデル部の情報から各種成果物を生成します。

以前開発していたXMLスキーマコンパイラである Relaxer によるプログラムの自動生成が極めて有効だったことを受けて、プログラムの自動生成のターゲットをオブジェクトモデルに広げるために新規に開発したのがSimpleModelerです。

SimpleModelerは基本機能は動作済みで後述のPCPの開発にも適用しています。

現在、後述するようにSimpleModelingのメタモデルの刷新を行っています。SimpleModelerは、この新メタモデルへの対応を行う予定です。

Kaleidox

Kaleidoxはオブジェクトモデリングとプログラミングをシームレスに連携させることを目的とするアクション言語です。

Kaleidoxの開発を進めながら以下の記事を書いてきました。

Kaleidoxはかなりよい感じで開発が進んでおり、プログラム開発のテスト環境としてボクが日常的に使用するツールになっています。

今年は、SimpleModeler統合を行うことで、モデル駆動開発のアクション言語として本格的に活用できるようにする予定です。

Arcadia

クラウド・アプリケーションでは、サーバーサイドのRESTサービスを中心に、Web、スマートフォン(iOS, Android)、デスクトップの3種類のUIフロントエンドの構成になります。

この中でWebフロントエンドのためのWebフレームワークとして開発中なのがArcadiaです。

モデルコンパイラが扱うオブジェクトモデルとWebアプリケーションの間はインピーダンスミスマッチが大きく、その間を埋めるミドルウェアの存在が重要になってきます。

Webアプリケーション独特の振る舞いや特性を吸収して、モデル駆動開発したアプリケーションロジックとWebでの実装をスムースに連携させることを目的としています。

Webアプリケーションも、大きくWebサーバー上での実行を中心としてWebページの遷移で振る舞いを構成する伝統的な方式(以下Webページ方式)とJavaScriptフレームワークを中心にGUIアプリケーション的な振る舞いを行う方式(以下JavaScriptフレームワーク方式)の2方式に分けることができ、現実的には両者の式の折衷案の方式(以下Web/JavaScript折衷方式)が使用されるケースが多いでしょう。

ArcaidaではWebページ方式をサポートするとともに、JavaScriptフレームワーク方式で必要になるJavaScriptベースのWebフレームワークの実行コンテナとしての機能を提供し、合わせてWeb/JavaScript折衷方式に対応していくというアプローチを取っています。

SimpleModelerから生成されるコードに対して、HTMLページのデザインを行えばアプリケーションが完成するエコシステムの構築を目指しています。

Arcaidaは基本部は開発済みです。Kaleidox、SimpleModelerを組み込んでモデル駆動対応を達成できた後に公開する予定です。

Prefer Cloud Platform

Prefer Cloud Platform(PCP)はEverforth社から商用のクラウド・プラットフォームとしてリリースされています。

PCPはAPIベースのクラウド・プラットフォームとして各種機能を提供するとともに、運用環境なども提供しており、多くのプロダクトで活用して頂いています。

PCPは開発当初からモデル駆動開発を実現する上で、クラウドプラットフォームの存在が重要となる、という認識のもと開発を進めてきており、モデル駆動開発とのシームレスな連携を行うための仕掛けを内包しています。

SimpleModeingは、対象となるプラットフォームに依存しないニュートラルな技術体系を指向していますが、高機能のサービスを提供しているプラットフォームの能力を引き出すことも重要機能としています。

両方向からのアプローチにより、SimpleModelingではPCPの提供する高度な各種機能を活用したアプリケーション開発も可能になる予定です。

SimpleModeingのオープンソースプロダクトのみのモデル駆動開発でも十分に有効ですが、PCPを併用すると運用やセキュリティも含めたより高度なクラウド・アプリケーションの開発・運用が可能になるという形を目指しています。

メタモデル

SimpleModelingでは以下の書籍で解説したモデルをベースとしています。

これらのモデルはボクがwakhokでモデリングを教えていた時に教科書としても使用できるように執筆したものです。教育用に使えると同時に、モデル駆動開発のメタモデルとしての利用も目的の一つにしています。

ただし、このメタモデルを設計した2008年当時とは状況が大きく変わっています。

クラウド・プラットフォームがシステム開発の日用品として普及したことで、クラウド・アプリケーションを簡単に構築できるようになりました。この効果を考える補助線として、大規模エンタープライズシステムのミドルウェア群が超低価格(数億円→数千円)で利用できるようになったと考えるとよいと思います。

これらのミドルウェアを活用すると、高度なアプリケーションが簡単に構築できるわけですが、逆にミドルウェアを使いこなすスキルがいと宝の持ち腐れになってしまいます。

またモデリング段階でもミドルウェアの活用を前提としたモデリングが必要になります。

このような状況に対応するために、SimpleModelのメタモデルを再設計することにしました。

最新のアプリケーション開発事情を踏まえた検討を行うこととして、まずそのスコープについて考えました。

この後、一連の以下の記事で検討を進めています。

一通り切り口の整理ができたので、SimpleModelerに取り込む準備をしているところです。

まとめ

SmartDox, SimpleModeler, Kaleidox, Arcadiaとモデル駆動開発を構成する各種ツールの開発を粛々と進めてきましたが、それなりに動くところまで来ることができました。

当面は、従前通りツールの開発状況の紹介や、メタモデルの検討を続ける予定ですが、今年の後半ぐらいに具体的な応用につながる内容の記事を書くことできればと考えています。