アプリケーション開発をモデル駆動で行う時に、見過ごしがちですが案外重要なのがデータ型の扱いです。
データ型の標準化
一般的にプログラミング言語では数値や文字列を中心に必要最小限のデータ型を定義し、アプリケーションで必要なデータ型はクラスライブラリで定義して使用するという建付けになっています。
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で定義しているデータ型一覧です。
データ型 | 説明 |
---|---|
boolean | Bool値 |
short | Short型整数 |
int | Int型整数 |
long | Long型整数 |
float | Float型浮動小数点数 |
double | Double型浮動小数点数 |
integer | 整数 |
decimal | 10進固定小数点数 |
rational | 有理数 |
complex | 複素数 |
range | レンジ |
interval | インターバル |
string | 文字列 |
binary | バイナリ |
i18nstring | 国際化文字列 |
i18ntemplate | 国際化テンプレート |
regex | 正規表現 |
clob | CLOB |
blob | BLOB |
slip | スリップ(伝票) |
schema | スキーマ |
query | クエリ |
record | レコード |
table | テーブル |
vector | ベクター |
matrix | マトリックス |
dataframe | データフレーム |
lxsv | LXSV |
url | URL |
urn | URN |
uri | URI |
expression | 式 |
script | スクリプト |
xml | XML |
html | HTML |
xpath | XPath |
xsl | XSL |
pug | PUG |
json | JSON |
datetime | 日時(タイムゾーン付き) |
localdatetime | ローカル日時 |
localdate | ローカル日 |
localtime | ローカル時 |
montyday | 月日 |
datetimeinterval | 日時インターバル |
localdatetimeinterval | ローカル日時インターバル |
duration | 経過時間 |
period | ピリオド |
money | 金額 |
percent | パーセント |
unit | 単位 |