Quantcast
Channel: Modegramming Style
Viewing all 150 articles
Browse latest View live

Kaleidox: HTML

$
0
0

Kaleidoxでは、実用的に利用できるアクション言語としてXML, HTML, JSON, CSV, Excelといったクラウドアプリケーションで使用する各種データ形式を簡単に扱えるようになっています。

前回はこの中でXMLの操作方法について紹介しました。

今回はHTMLの操作方法について紹介します。

HTMLリテラル

HTMLは元々SGMLベースですが、XMLベースのXHTMLもあります。

XHTMLのみを対象にするとXML処理的には楽ですが、実際のところはSGMLベースのHTMLが主流なのでこちらの方も扱えないといけません。

Kaleidoxでは、SGMLベース、XMLベースのどちらのHTMLもHTMLデータとして扱い、内部的にはDOMで操作しています。

まず以下のHTML文書を考えます。XML的な観点ではすこしブロークンですが、このような形のタグ構造も扱える必要があります。

<b>HTML文書

HTMLリテラルは、文字列リテラルのプレフィックスにHTMLをつけたものになります。

kaleidox> html"""<b>HTML文書"""
<html><head xmlns="http://www.w3.org/1999/xhtml"/><body><b>HTML文書\n</b></b...

showコマンドを使うとHTML全体を表示することができます。

kaleidox> :show
SHtml: <html><head xmlns="http://www.w3.org/1999/xhtml"/><body><b>HTML文書
</b></body></html>

元のHTMLの内容はB要素のみのHTMLの断片ですが、読み込み時にはHTML要素から始まる本格的なHTML文書になっています。これは、HTMLに対するXSLTなどの処理が統一的に行えるように必要な情報を補完しているためです。

ファイル

ファイルに格納されているHTMLは、URIを指定して取り込むことができます。

kaleidox> file:sample.html
<html><head xmlns="http://www.w3.org/1999/xhtml"/><body><b>HTML文書\n</b></b...
kaleidox> :show
SHtml: <html><head xmlns="http://www.w3.org/1999/xhtml"/><body><b>HTML文書
</b></body></html>

XPath

HTMLに対してもXMLと同様にXPathによるアクセスを行うことができます。

まず、HTML文書を読み込みます。

kaleidox> file:sample.html
<html><head xmlns="http://www.w3.org/1999/xhtml"/><body><b>HTML文書\n</b></b...

HTML文書がスタックに積まれたので、これに対してXPath「htmlbody/b」を適用します。

kaleidox> /html/body/b
"HTML文書\n"

XPathを適用の結果、B要素の内容である「HTML文書」を取り出すことができました。

XPathの式の直後にHTMLファイルを指定しても同じ結果を得ることができます。

kaleidox> /html/body/b file:sample.html
"HTML文書\n"

XSLT

HTMLに対してもXMLと同様にXSLTによる変換を行うことができます。

XSLTに使用するXSL文書として以下のものを用意しました。

HTML文書の一部を変更する目的の典型的なXSL文書です。ここではB要素をI要素に変換するXSL文書になっています。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:template match="b">
<i><xsl:value-of select="."/></i>
</xsl:template>

<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

それではXSL文書をHTMLに適用してみましょう。

XSLT文書のファイル名の後ろにHTML文書名を指定します。すると内部的にはxslt関数が実行され、XSLT変換が行われます。

kaleidox> file:sample.xsl file:sample.html
<html><head xmlns="http://www.w3.org/1999/xhtml"/><body><i>HTML文書\n</i></b...

実行結果のHTML文書をshowコマンドで表示すると以下のようになりました。無事B要素がI要素に変換されています。

kaleidox> :show
SHtml: <html><head xmlns="http://www.w3.org/1999/xhtml"/><body><i>HTML文書
</i></body></html>

スクレイピング

KaleidoxはHTML文書内の表データを抽出する機能を提供しています。

まず表を記述したHTML文書を用意します。

<html>
<head>
<title>表サンプル</title>
</head>
<body>
<p>表のサンプルです</p>
<table>
<thead>
<tr><th>A</th><th>B</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>11</td></tr>
<tr><td>2</td><td>12</td></tr>
<tr><td>3</td><td>13</td></tr>
</tbody>
</table>
</body>
</html>

このHTML文書に対してtable-make関数を適用します。

kaleidox> table-make file:table.html
Table[2x3]

その結果、幅2、高さ3の表を得ることができました。

この表の内容をshowコマンドで表示すると以下になります。無事HTMLの表の内容を取得できています。

kaleidox> :show:print
┏━┯━━┓
┃A│B ┃
┣━┿━━┫
┃1│11┃
┠─┼──┨
┃2│12┃
┠─┼──┨
┃3│13┃
┗━┷━━┛

まとめ

今回はXMLの操作について説明しました。

次回はJSONの操作方法についてみていく予定です。

諸元

  • Kaleidox : 0.1.4

Kaleidox: JSON

$
0
0

Kaleidoxでは、実用的に利用できるアクション言語としてXML, HTML, JSON, CSV, Excelといったクラウドアプリケーションで使用する各種データ形式を簡単に扱えるようになっています。

前々回、前回とXMLとHTMLの操作方法について紹介しました。

今回はJSONの操作方法について紹介します。

JSONリテラル

例として以下のJSON文書を考えます。

また、このJSON文書を格納したJSONファイルをfile.jsonとして用意します。

{
"id": "0001",
"name": "taro",
"point": 100
}
リテラル記述

KaleidoxではJSON文書をそのままリテラルとして記述することができます。

REPLでも以下のように直接入力することができます。

kaleidox> {
"id": "0001",
"name": "taro",
"point": 100
}
{\n "id": "0001",\n "name": "taro",\n "point": 100\n}
ファイル入力

REPLでJSON文書が格納されているJSONファイルからJSON文書を取り込む時は以下のようにJSONファイルのURLを記述すればOKです。

kaleidox> file:sample.json
{\n "id": "0001",\n "name": "taro",\n "point": 100\n}\n

この例はプロトコルに「file」を指定してローカルファイルを読み込んでいますが、「http」を指定してリモートファイルを読み込むこともできます。

kaleidox> http://example.com/sample.json
{\n "id": "0001",\n "name": "taro",\n "point": 100\n}\n

XPath

KaleidoxではJSON文書に対してXPathでパス検索をかけることができます。

{
"id": "0001",
"name": "taro",
"point": 100
}

まずJSONファイルsample.jsonに対してXPath「@name」で検索すると以下になります。

JSON文書にある属性nameの値を取得することができました。

kaleidox> @name file:sample.json
"taro"

次にXPath「/name」で検索すると以下になります。こちらもJSON文書にある属性nameの値を取得することができました。

JSONにはXMLにある属性と要素の区別がないので、要素に対する検索ですがJSONの属性に対しても有効になっています。

kaleidox> /name file:sample.json
"taro"

XSLT

KaleidoxはJSON文書をXML文書にみたててXSLT変換を行うことができます。

サンプルとして使用しているJSON文書です。

{
"id": "0001",
"name": "taro",
"point": 100
}

このJSON文書に対して提供するXSL記述は以下になります。

<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"></xsl:output>

<xsl:template match="/">
<HTML>
<BODY>
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>

<xsl:template match="record">
<TABLE>
<THEAD>
<TR>
<TH>ID</TH>
<TH>Name</TH>
<TH>Point</TH>
</TR>
</THEAD>
<TBODY>
<TR>
<TD><xsl:value-of select="id"/></TD>
<TD><xsl:value-of select="name"/></TD>
<TD><xsl:value-of select="point"/></TD>
</TR>
</TBODY>
</TABLE>
</xsl:template>
</xsl:stylesheet>

XMLやHTMLの場合と同様にXSLファイルに続けてJSONファイルを指定するとXSL変換が行われます。

kaleidox> file:sample.xsl file:sample.json
<HTML><BODY><TABLE><THEAD><TR><TH>ID</TH>
<TH>Name</TH><TH>Point</TH></TR>...

変換後のXML文書を詳細を表示すると以下になります。

無事XSLTでJSONファイルをHTML文書に変換することができました。

kaleidox> :show:print
<HTML><BODY><TABLE><THEAD><TR><TH>ID</TH>
<TH>Name</TH><TH>Point</TH></TR></THEAD>
<TBODY><TR><TD>0001</TD><TD>taro</TD>
<TD>100</TD></TR></TBODY></TABLE>
</BODY></HTML>

Table

XMLやHTMLと同様にJSON文書で記述した表情報をTableデータとして扱うことができます。

サンプルとして使用しているJSON文書です。

{
"id": "0001",
"name": "taro",
"point": 100
}

このJSON文書に対してtable-make関数を適用します。

kaleidox> table-make file:sample.json
Table[3x1]

その結果、幅3、高さ1の表を得ることができました。

この表の内容をshowコマンドで表示すると以下になります。無事HTMLの表の内容を取得できています。

kaleidox> :show
Table[3x1]
┏━━━━┯━━━━┯━━━━━┓
┃id │name│point┃
┣━━━━┿━━━━┿━━━━━┫
┃0001│taro│100 ┃
┗━━━━┷━━━━┷━━━━━┛

JSON文書がJson Objectの場合は1行のテーブルに変換されます。

レコードシーケンス

JSON文書がJson Objectの配列だった場合は配列の長さ分の行を持ったテーブルに変換されます。

まずJson Objectの配列を持ったJSON文書を用意します。

[{
"id": "0001",
"name": "taro",
"point": 100
},{
"id": "0002",
"name": "hanako",
"point": 200
}]

このJSON文書に対してtable-make関数を適用します。

kaleidox> table-make file:sample-table.json
Table[3x2]

その結果、幅3、高さ2の表を得ることができました。

この表の内容をshowコマンドで表示すると以下になります。無事HTMLの表の内容を取得できています。

kaleidox> :show:print
┏━━━━┯━━━━━━┯━━━━━┓
┃id │name │point┃
┣━━━━┿━━━━━━┿━━━━━┫
┃0001│taro │100 ┃
┠────┼──────┼─────┨
┃0002│hanako│200 ┃
┗━━━━┷━━━━━━┷━━━━━┛

まとめ

今回はJSONの操作について説明しました。

JSONではXPath(パス検索)はXSLT(データ変換)といったXMLで用意されている便利な機能が基本機能として提供されていません。

KaleidoxではJSON文書をXML文書として操作可能にすることで、XMLの便利な機能をJSON文書にも適用できるようにしました。

前々回、前回、今回でXML、HTML、JSONの操作方法についてみてきました。

KaleidoxではXML、HTML、JSONについて詳細を意識することなくシームレスに操作することができることを確認できました。

次回はこのメカニズムの土台となっているRecordについてみていく予定です。

諸元

  • Kaleidox : 0.1.5

Kaleidox: LXSV

$
0
0

Kaleidoxはレコードを記述するRecordというデータ型を提供しています。

このRecordをテキストとして入出力するためのテキストフォーマットとしてLXSVを開発しました。LXSVを使うことでkaleidoxプログラム内でRecordをリテラルとして記述できます。

LXSVはLTSV(Labeled Tab-separeted Values)的なフォーマットを拡張したもので以下の特徴があります。

  • Kaleidoxプログラム内でリテラルとして記述可能
  • LTSVの概ね上位互換
  • 区切り記号を選択することができる

LXSVフォーマット

LXSVはUnicodeによるテキストフォーマットで区切り記号によってキーと値の対の列によるレコードと、改行コードで区切られたレコードの列を表現できます。

例えば以下のようなテキストがLXSVです。

name:Taro,city:Yokohama
name:Hanako,city:Kawasaki

このテキストではキーと値の対の区切り記号として「:」、キーと値の対の間の区切り記号として「,」を用いています。

キーと値の対の区切り記号は「:」固定ですが、キーと値の対の間の区切り記号は以下のルールによって決められます。

  • TAB、SPACE、「,」、「;」の中で最初に登場した文字を区切り記号とする。

このため以下のLXSVはすべて同じデータ構造を記述しています。

区切り記号: TAB

name:Taro city:Yokohama
name:Hanako city:Kawasaki

区切り記号: SPACE

name:Taro city:Yokohama
name:Hanako city:Kawasaki

区切り記号: ,

name:Taro,city:Yokohama
name:Hanako,city:Kawasaki

区切り記号: ;

name:Taro;city:Yokohama
name:Hanako;city:Kawasaki

区切り記号の入力

値の中にTAB, SPACE, 「,」, 「;」といった区切り記号を入れたい場合、以下の3つの方法があります。

  • 区切り記号の使い分け
  • 「"」で囲んで文字列として記述する。
区切り記号の使い分け

区切り記号を可変にしている理由の1つは区切り記号を値に入れたい場合の文字エスケープを回避することを可能にするためです。

name:Taro;city:Yokohama,Kawasaki
name:Hanako;city:Kawasaki,Yokohama

たとえば以下のように値の中に値の列を記述することも可能になります。ここではLXSVの区切り記号に「;」を使っています。そして、値の中の区切り記号に「,」を使っています。

name:Taro;city:Yokohama,Kawasaki
name:Hanako;city:Kawasaki,Yokohama
文字列

値の中にTAB, SPACE, 「,」, 「;」といった区切り記号を入れたい場合には、前述したように別の区切り記号を使うのが有効ですが、別の方法として「"」を使って文字列を指定することもできます。

name:Taro;city:"Yokohama,Kawasaki"
name:Hanako;city:"Kawasaki,Yokohama"

「"」を使って文字列を記述する場合は、「\n」や「\r」といったエスケープ文字を使って文字列に制御文字を入れることができます。また「”」の文字列内に「"」を入れる場合は「\"」として「\」を使ってエスケープします。

name:Taro;city:"Yokohama\nKawasaki"
name:Hanako;city:"Kawasaki\"Yokohama"

LXSVリテラル

Kaleidoxではレコードを記述するRecordというデータ型を提供しています。このRecordをリテラルとして記述する時にLXSVを用います。

kaleidox> name:Taro,city:Yokohama
name:Taro,city:Yokohama
kaleidox> :show
Record[2] name:Taro,city:Yokohama
文字列リテラルでの入力

Recordを文字列に対する修飾を使って入力することができます。文字列に対する修飾は文字列リテラルの前に修飾を示すプレフィックスを指定します。Recordの場合は「record」です。

以下のように使用します。

kaleidox> record"name:Taro,city:Yokohama"
name:Taro,city:Yokohama
kaleidox> :show
Reord[2] name:Taro,city:Yokohama

KaleidoxではLXSVのデータ型も用意されています。このデータ型を使う場合には修飾を示すプレフィックスとして「lxsv」を指定します。

kaleidox> lxsv"name:Taro,city:Yokohama"
name:Taro,city:Yokohama
kaleidox> :show
Lxsv[2] name:Taro,city:Yokohama

まとめ

Recordを使用するための前提となるLXSVについてご紹介しました。

次回はRecordの具体的な使い方について説明する予定です。

諸元

  • Kaleidox : 0.1.6

Kaleidox: Record

$
0
0

Kaleidoxはレコードを記述するRecordというオブジェクトを提供しています。

RecordはKaleidoxの中軸となるオブジェクトで、データ処理を行う場合などRecordをハブにして様々な連携を行うようになっています。

今回はRecordの使い方について説明します。

準備

Recordをデータベース入出力で使用するための環境としてKaleidoxの初期化ファイルinit.kldに以下の設定をします。

この設定をしておくと、H2データベースのメモリデータベース上にpersonテーブルが作成され、1レコードが格納された状態になります。

* env

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

* voucher

** person

#+caption: 特性一覧
|特性 | 名前 | 型 | 多重度 | ラベル |
|------+------+--------+--------+---------|
| 属性 | id | int | 1 | User ID |
| 属性 | name | string | 1 | 名前 |
| 属性 | city | string | ? | 市 |

* main

store-create 'person
store-insert 'person id:100,name:Taro,city:Yokohama

入力

LXSVによるリテラル記述とデータベース読込みでRecordを作成することができます。

LXSV

LXSVリテラルによってRecordを作成することができます。

kaleidox> name:Taro,city:Yokohama
name:Taro city:Yokohama

showコマンドで内容を表示すると2つのプロパティを持つRecordであることが分かります。

kaleidox> :show
Record[2] name:Taro city:Yokohama
データベース読込み

Kaleidoxでは、データベースアクセスの仕組みとして以下の2つを用意しています。

Store
データストア機能
SQL
SQLで直接データベースアクセス
Store

データストア機能を使うと、スキーマ定義といったメタ情報を登録することで、データベースに対してレコードベースのインタフェースでアクセスすることができます。

store-get関数ではデータベースのテーブルからデータをRecordとして読み込むことができます。

以下ではpersonテーブルからID 100のRecordを取得しています。

kaleidox> store-get 'person 100
ID:100 NAME:Taro CITY:Yokohama

データストアからstore-selectでRecordを検索すると、検索結果がテーブルを記述するTableオブジェクトに格納されて返されます。

以下ではstore-selectに検索条件を指定せずテーブル名のみを指定しているので全件検索になります。(ただし、読込件数はデフォルト値の件数で制限されます。)

kaleidox> store-select 'person
Table[3x1]

読み込んだTableの詳細情報を表示すると以下になります。

kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛

Tableはオブジェクトなのでプロパティまたはメソッドを使って必要な情報を取り出すことができます。

ここではheadメソッドを使用して先頭の要素を取り出しています。この先頭の要素は本記事のテーマであるRecordとして取り出されます。

kaleidox> .head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[2] name:Taro city:Yokohama
SQL

データストア機能を使わず直接SQLを使用してデータベース内のデータをTableとRecordとして取得することもできます。

sql関数でSQL文を指定するとSQLが発行されます。SELECT文の場合は結果がTableとして返ってきます。

前述したとおり、Tableオブジェクトのheadメソッドを呼び出すと先頭の行がRecordとして返ってきます。

kaleidox> sql "select * from person"
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃ID │NAME│CITY ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
kaleidox> .head
ID:100 NAME:Taro CITY:Yokohama

出力

データストア機能を使ってRecordをデータベースに格納することができます。

以下ではstore-insert関数を使って、personテーブルにRecordを追加しています。

kaleidox> store-insert 'person id:101,name:Hanako,city:Kawasaki
(101)
kaleidox> store-get 'person 101
ID:101 NAME:Hanako CITY:Kawasaki
kaleidox> store-select 'person
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃101│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

参照

Recordの内容はプロパティとして参照することができます。

以下のように変数にpにRecordを束縛します。

kaleidox> setq p id:100,name:Taro,city:Yokohama
id:100 name:Taro city:Yokohama
プロパティ取得

プロパティ取得は以下のようにオブジェクトのプロパティを参照することで行なえます。

kaleidox> p.name
"Taro"
XPath

XPathを使ってRecordからプロパティ取得することもできます。

kaleidox> /name p
"Taro"

まとめ

今回はKaleidoxの中軸オブジェクトであるRecordについて説明しました。

次回はもう一つの中軸オブジェクトであるTableについて説明する予定です。

諸元

  • Kaleidox : 0.1.7

Kaleidox: Table

$
0
0

前回はKaleidoxの中軸となるRecordオブジェクトについて説明しました。

今回はRecordオブジェクトと同様にKaleidoxの中軸オブジェクトであるTableオブジェクトについて説明します。

Tableオブジェクトは文字通り表を記述するオブジェクトで、Recordオブジェクトの列にスキーマとヘッダ、フッタの情報を加えたものになっています。

準備

Tableをデータベース入出力で使用するための環境としてKaleidoxの初期化ファイルinit.kldに以下の設定をします。

この設定をしておくと、H2データベースのメモリデータベース上にpersonテーブルが作成され、2レコードが格納された状態になります。

* env

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

* voucher

** person

#+caption: 特性一覧
|特性 | 名前 | 型 | 多重度 | ラベル |
|------+------+--------+--------+---------|
| 属性 | id | int | 1 | User ID |
| 属性 | name | string | 1 | 名前 |
| 属性 | city | string | ? | 市 |

* data

** person

*** x

100,Taro,Yokohama
200,Hanako,Kawasaki

* main

store-create 'person
store-insert 'person x
DATA区画

準備として用意したinit.kldでは以下のデータ区画を定義しています。

* data

** person

*** x

100,Taro,Yokohama
200,Hanako,Kawasaki

変数xにCSVで記述された表データを持つTableオブジェクトが束縛されます。

入力

Tableオブジェクトの入力方法として以下の方法について見ていきます。

  • データベース読込み
  • CSVファイル
  • LTSVファイル
  • XMLファイル
  • JSONファイル
  • HTMLファイル
データベース読込み

Kaleidoxでは、データベースアクセスの仕組みとして以下の2つを用意しています。

Store
データストア機能
SQL
SQLで直接データベースアクセス
Store

データストア機能を使うと、スキーマ定義といったメタ情報を登録することで、データベースに対してレコードベースのインタフェースでアクセスすることができます。

データストアからstore-selectで検索すると、検索結果がテーブルを記述するTableオブジェクトに格納されて返されます。

以下ではstore-selectに検索条件を指定せずテーブル名のみを指定しているので全件検索になります。(ただし、読込件数はデフォルト値の件数で制限されます。)

kaleidox> store-select 'person
Table[3x2]

読み込んだTableの詳細情報を表示すると以下になります。

kaleidox> :show
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

Tableはオブジェクトなのでプロパティまたはメソッドを使って必要な情報を取り出すことができます。

以下headメソッドを使用して先頭の要素を取り出しています。

kaleidox> .head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[2] name:Taro city:Yokohama
SQL

データストア機能を使わず直接SQLを使用してデータベース内のデータをTableとRecordとして取得することもできます。

sql関数でSQL文を指定するとSQLが発行されます。SELECT文の場合は結果がTableとして返ってきます。

kaleidox> sql "select * from person"
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃ID │NAME│CITY ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
kaleidox> .head
ID:100 NAME:Taro CITY:Yokohama
CSVファイル

CSVファイルからテーブルを読み込むことができます。

以下のCSVファイルpersons.csvを用意します。

id,name,city
100,Taro,Yokohama
200,Hanako,Kawasaki

CSVファイルの読込みにはtable-load関数を用います。table-load関数の引数にCSVファイルのURLを指定します。ローカルファイルでもHTTP経由でのリモートファイルでも読込み可能です。

kaleidox> table-load file:persons.csv
Tabble[3x2]

showコマンドで内容を表示すると以下のようにTableオブジェクトとして読み込まれています。

kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
LTSVファイル

LTSVファイルからテーブルを読み込むことができます。

以下のLTSVファイルpersons.ltsvを用意します。

id:100 name:Taro city:Yokohama
id:200 name:Hanako city:Kawasaki

LTSVファイルの読込みにはtable-load関数を用います。table-load関数の引数にLTSVファイルのURLを指定します。ローカルファイルでもHTTP経由でのリモートファイルでも読込み可能です。

kaleidox> table-load file:persons.ltsv
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
XMLファイル

XML文書から以下のいずれかの構造を読み取り、その情報に基づいてTableオブジェクトを生成することができます。

  • 表データ
  • レコードデータ
表データ

XML文書が以下のようにリスト構造になっている場合は表データとして解釈することができます。

<accounts>
<account>
<id>100</id>
<name>Taro</name>
<city>Yokohama</city>
</account>
<account>
<id>200</id>
<name>Hanako</name>
<city>Kawasaki</city>
</account>
</accounts>

table-make関数はXML文書の構造を解釈してTableオブジェクトとして読み込みます。

このXML文書をpersons.xmlとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

kaleidox> table-make file:persons.xml
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
レコードデータ

XML文書が以下のようにレコード構造になっている場合はレコードデータとして解釈することができます。

<account>
<id>100</id>
<name>Taro</name>
<city>Yokohama</city>
</account>

このXML文書をperson.xmlとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

レコード構造の場合は1レコードを持つTableオブジェクトとなります。

kaleidox> table-make file:person.xml
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
JSONファイル

JSON文書から以下のいずれかの構造を読み取り、その情報に基づいてTableオブジェクトを生成することができます。

  • 表データ
  • レコードデータ
表データ

JSON文書が以下のように配列になっている場合は表データとして解釈することができます。

[{
"id": "100",
"name": "Taro",
"city": "Yokohama"
},{
"id": "200",
"name": "Hanako",
"city": "Kawasaki"
}]

このJSON文書をpersons.jsonとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

kaleidox> table-make file:persons.json
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
レコードデータ

JSON文書が以下のようにレコード構造になっている場合はレコードデータとして解釈することができます。

{
"id": "100",
"name": "Taro",
"city": "Yokohama"
}

このJSON文書をperson.jsonとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

レコード構造の場合は1レコードを持つTableオブジェクトとなります。

kaleidox> table-make file:person.json
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
HTMLファイル

HTML文書からTableオブジェクトを生成することができます。この場合は、HTML文章内の表構造を抽出し、条件に適合するものをTableオブジェクトとして取り出します。

以下のHTMLファイルpersons.htmlにはtableタグによって表が1つ定義されています。

<html>
<head>
<title>表サンプル</title>
</head>
<body>
<p>表のサンプルです</p>
<table>
<thead>
<tr><th>id</th><th>name</th><th>city</th></tr>
</thead>
<tbody>
<tr><td>100</td><td>Taro</td><td>Yokohama</td></tr>
<tr><td>200</td><td>Hanako</td><td>Kawasaki</td></tr>
</tbody>
</table>
</body>
</html>

このHTMLファイルに対してtable-make関数を適用するとHTML文書内の表データをTableオブジェクトとして抽出することができました。

kaleidox> table-make file:persons.html
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

出力

データストア機能を使ってTableのデータをデータベースに格納することができます。

以下ではstore-insert関数を使って、personテーブルにTableの情報を追加しています。

kaleidox> store-insert x
(101)
kaleidox> store-get 'person 101
ID:101 NAME:Hanako CITY:Kawasaki
kaleidox> store-select 'person
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃101│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

参照

Tableの内容はRecordのシーケンスとして参照することができます。

準備

前述のinit.kldの設定によって、変数xにTableオブジェクトが束縛されています。

kaleidox> x
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

このTableオブジェクトを参照の対象にします。

プロパティ取得

Tableオブジェクトのプロパティは以下のようにプロパティ名を指定して取得することができます。

以下ではTableオブジェクトのカラム数をプロパティwidthで、レコード数をプロパティheightで取得しています。

kaleidox> x.width
3
kaleidox> x.height
2
レコード操作

Tableオブジェクトの先頭レコードはプロパティheadで取得することができます。

kaleidox> x.head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[3] id:100 name:Taro city:Yokohama

また、先頭レコードを除いた残りのレコードを保持したTableオブジェクトはプロパティtailで取得することができます。

kaleidox> x.tail
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name │city ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

Tableオブジェクトが空の場合はプロパティheadはnilを返します。

kaleidox> setq y x.tail
Table[3x1]
kaleidox> y.tail
Table[3x0]
kaleidox> :show
Table[3x0]
┏━━┯━━━━┯━━━━┓
┃id│name│city┃
┣━━┿━━━━┿━━━━┫
┗━━┷━━━━┷━━━━┛
kaleidox> .head
nil
スキーマ

Tableオブジェクトのスキーマ情報はプロパティschemaで取得することができます。

kaleidox> x.schema
Schema[3] id,int,1 name,string,1 city,string,?
kaleidox> :show
Schema[3]
┏━━━━┯━━━━━━━━┯━━━━━━━━━━━━┓
┃name│datatype│multiplicity┃
┣━━━━┿━━━━━━━━┿━━━━━━━━━━━━┫
┃id │int │1 ┃
┃name│string │1 ┃
┃city│string │? ┃
┗━━━━┷━━━━━━━━┷━━━━━━━━━━━━┛

まとめ

今回はKaleidoxの中軸オブジェクトの一つであるTableについて説明しました。

データベースやCSVファイルといった外部リソースの情報をTableオブジェクトとして読込み、Recordオブジェクト単位で処理していくのがKaleidoxの基本処理モデルです。TableとRecordをハブにして各種の連携を進めていきます。

諸元

  • Kaleidox : 0.1.8

Kaleidox: Matrix

$
0
0

BigDataやAIなどがアプリケーションを構成する重要部品となってきています。このBigDataやAIをアプリケーションで扱う上で重要な技術要素として行列(matrix)があります。

Kaleidoxでは行列をMatrixオブジェクトとして記述して各種行列演算をすることができます。

入力

Matrixオブジェクトの入力方法として以下の方法について見ていきます。

  • Matrixリテラル
  • matrix-load関数
Matrixリテラル

Matrixオブジェクトのリテラルは以下のように二重のカギ括弧で囲まれたエリアに改行と空白を区切り記号として記述したものです。

[[
43.055248 141.345505 8.0 1158
38.254162 140.891403 11.9 1219
35.680909 139.767372 15.3 1460
35.154919 136.920593 14.9 1575
34.702509 135.496505 16.2 1400
34.377560 132.444794 15.0 1603
33.579788 130.402405 16.0 1690
26.204830 127.692398 22.4 2128
]]

REPLから入力すると以下のようになります。

kaleidox> [[
43.055248 141.345505 8.0 1158
38.254162 140.891403 11.9 1219
35.680909 139.767372 15.3 1460
35.154919 136.920593 14.9 1575
34.702509 135.496505 16.2 1400
34.377560 132.444794 15.0 1603
33.579788 130.402405 16.0 1690
26.204830 127.692398 22.4 2128
]]
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌ ┐
│43.055248 141.345505 8.0 1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756 132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483 127.692398 22.4 2128.0│
└ ┘
matrix-load関数

matrix-load関数でCSVファイルの内容からMatrixオブジェクトを生成します。matrix-load関数では内容の中から自動的に行列化可能な数値部分を取り出してMatrixオブジェクトにします。

日本の都市について緯度経度と平均気温、降水量を記述したCSVファイル city.csv を用意します。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

matrix-load関数を使うと以下のようにMatrixオブジェクトを取得することができます。

kaleidox> matrix-load file:city.csv
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌ ┐
│43.055248 141.345505 8.0 1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756 132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483 127.692398 22.4 2128.0│
└ ┘
Tableオブジェクト

TableオブジェクトからMatrixオブジェクトを取得することができます。

引き続きCSVファイル city.csv を使用します。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

このCSVファイルをtable-load関数を使ってTableオブジェクトとして読み込みます。

kaleidox> table-load file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市 │緯度 │経度 │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌 │43.055248│141.345505│8.0 │1158 ┃
┃仙台 │38.254162│140.891403│11.9 │1219 ┃
┃東京 │35.680909│139.767372│15.3 │1460 ┃
┃名古屋│35.154919│136.920593│14.9 │1575 ┃
┃大阪 │34.702509│135.496505│16.2 │1400 ┃
┃広島 │34.377560│132.444794│15.0 │1603 ┃
┃福岡 │33.579788│130.402405│16.0 │1690 ┃
┃那覇 │26.204830│127.692398│22.4 │2128 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

Tableオブジェクトを起点にさまざまな操作を行うことができますが、ここではmatrixメソッドを使用してMatrixオブジェクトに変換しています。matrix-load関数と同様に行列化可能なデータを抽出してMatrixオブジェクト化しています。

kaleidox> .matrix
Matrix[0x8]
kaleidox> :show
Matrix[4x8]
┌ ┐
│43.055248 141.345505 8.0 1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756 132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483 127.692398 22.4 2128.0│
└ ┘

参照

Matrixオブジェクトを参照して各種データを取得することができます。

準備としてcity.csvに入っているデータをMatrix化したものを変数xに束縛します。

kaleidox> setq x (matrix-load file:city.csv)
Matrix[4x8]
kaleidox> x
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌ ┐
│43.055248 141.345505 8.0 1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756 132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483 127.692398 22.4 2128.0│
└ ┘
行の参照

Matrixオブジェクトの行はrowメソッドで取得することができます。引数に行番号を指定します。行番号は0始まりです。

kaleidox> x.row(0)
[43.055248 141.345505 8.0 1158.0]
列の参照

Matrixオブジェクトの列はcolumnメソッドで取得することができます。引数に列番号を指定します。列番号は0始まりです。

kaleidox> x.column(3)
[1158.0 1219.0 1460.0 1575.0 1400.0 1603.0 1690.0 2128.0]
データの参照

Matrixオブジェクトのデータはatメソッドで取得することができます。引数に列番号、行番号を指定します。

kaleidox> x.at(2,3)
14.9

演算

準備として2✕2の正方行列を変数xに束縛します。

kaleidox> setq x [[
1 2
3 4
]]
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌ ┐
│1.0 2.0│
│3.0 4.0│
└ ┘
加算

加算は+メソッドです。

kaleidox>+ x x
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌ ┐
│2.0 4.0│
│6.0 8.0│
└ ┘
積算

積算は*メソッドです。

kaleidox> * x x
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌ ┐
│7.0 10.0│
│15.0 22.0│
└ ┘
逆行列

逆行列はinvメソッドで行います。

kaleidox> x.inv
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌ ┐
│-1.9999999999999996 0.9999999999999998 │
│1.4999999999999998 -0.4999999999999999│
└ ┘
ランク

行列のランクはrankメソッドで取得します。

kaleidox> x.rank
2

出力

Matrixオブジェクトの出力方法として以下の方法について見ていきます。

  • matrix-save関数
  • Table

準備としてcity.csvに入っているデータをMatrix化したものを変数xに束縛します。

kaleidox> setq x (matrix-load file:city.csv)
Matrix[4x8]
kaleidox> x
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌ ┐
│43.055248 141.345505 8.0 1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756 132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483 127.692398 22.4 2128.0│
└ ┘
matrix-save関数

Matrixオブジェクトはmatrix-save関数を使ってCSV形式でファイルに保存することができます。

第1引数に保存するファイル名、第2引数にMatrixオブジェクトを指定します。

kaleidox> matrix-save file:output.csv x
t

matrix-save関数で保存したCSVファイルoutput.csvには以下のCSVが格納されます。

"43.055248","141.345505","8.0","1158.0"
"38.254162","140.891403","11.9","1219.0"
"35.680909","139.767372","15.3","1460.0"
"35.154919","136.920593","14.9","1575.0"
"34.702509","135.496505","16.2","1400.0"
"34.37756","132.444794","15.0","1603.0"
"33.579788","130.402405","16.0","1690.0"
"26.20483","127.692398","22.4","2128.0"
Table

Matrixオブジェクトのtableメソッドで行列データをTableオブジェクトに変換することできます。表のカラム名は1からの連番となります。

kaleidox> x.table
Table[4x8]
kaleidox> :show:print
┏━━━━━━━━━┯━━━━━━━━━━┯━━━━┯━━━━━━┓
┃1 │2 │3 │4 ┃
┣━━━━━━━━━┿━━━━━━━━━━┿━━━━┿━━━━━━┫
┃43.055248│141.345505│8.0 │1158.0┃
┃38.254162│140.891403│11.9│1219.0┃
┃35.680909│139.767372│15.3│1460.0┃
┃35.154919│136.920593│14.9│1575.0┃
┃34.702509│135.496505│16.2│1400.0┃
┃34.37756 │132.444794│15.0│1603.0┃
┃33.579788│130.402405│16.0│1690.0┃
┃26.20483 │127.692398│22.4│2128.0┃
┗━━━━━━━━━┷━━━━━━━━━━┷━━━━┷━━━━━━┛

Tableオブジェクトを起点にMatrixオブジェクトによる行列演算の結果を各種応用に利用していくことができます。

まとめ

今回はKaleidoxで行列を扱うMatrixオブジェクトについて説明しました。

Matrixの演算に加えて、CSVによる外部入出力、Tableオブジェクトとの連携を容易に行うことができます。モデル駆動開発の場合でも、BigDataやAIの応用を考えた場合、アクション言語ではドメインモデルと行列を併用してシームレスに連携できる必要があるはずです。Matrixオブジェクトはこのような応用で便利に使用できると思います。

諸元

  • Kaleidox : 0.1.9
気象データ

以下のページ「5.おもな都市の月平均気温・月降水量」のデータを使用しました。

http://www.biodic.go.jp/reports/2-2/hyo/aa126_001.html

Kaleidox: 単回帰分析

$
0
0

KaleidoxプログラムではTableオブジェクトとRecordオブジェクトを中心に演算を行っていきます。

このためTableオブジェクトとRecordオブジェクトを操作するための機能を多数サポートする予定にしています。

今回はそういった便利な機能の中で、Tableオブジェクトのチャート表示と単回帰分析機能について説明します。

データ

単回帰分析を行う対象のデータをCSVファイルcity.csvとして用意しました。このデータでは日本の都市の緯度経度と平均気温、降水量を記述しています。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

データの読み込み

KaleidoxのREPLからURIリテラルで上記CSVファイル名を投入すると、データを読み込んだTableオブジェクトが生成されます。

kaleidox> file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市 │緯度 │経度 │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌 │43.055248│141.345505│8.0 │1158 ┃
┃仙台 │38.254162│140.891403│11.9 │1219 ┃
┃東京 │35.680909│139.767372│15.3 │1460 ┃
┃名古屋│35.154919│136.920593│14.9 │1575 ┃
┃大阪 │34.702509│135.496505│16.2 │1400 ┃
┃広島 │34.377560│132.444794│15.0 │1603 ┃
┃福岡 │33.579788│130.402405│16.0 │1690 ┃
┃那覇 │26.204830│127.692398│22.4 │2128 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

table-chart関数

データを読み込んだ直後にtable-chart関数を投入すると、以下に示すようにTableオブジェクトから必要な情報を取得して散布図を表示します。

kaleidox> table-chart

デフォルトでは表の第1列を項目名、第2列をX軸、第3列をY軸と解釈して自動でデータを読み込みます。

Kaleidoxは関数の投入結果をスタックとヒストリに保存しています。table-chart関数を引数なしで起動するとスタックの先頭にあるオブジェクトを引数として使用するのでこのようなことが可能になっています。

historyコマンドで確認するとCSVファイルをローディングした結果のTableオブジェクトは6番目に格納されていました。今後はヒストリの6番目のTableオブジェクトを使用します。

kaleidox> :history
1: nil
2: Table[3x10]
3: Matrix[1x10]
4: Matrix[2x10]
5: Matrix[1x2]
6: Table[5x8]
7: Window

行列

回帰分析のような数値演算を行う場合、通常はTableオブジェクトを行列に変換してから行列に対して線形代数の演算を行っていきます。

Kaleidoxの場合はtable-matrix関数でTableオブジェクトから行列を抽出することができます。

kaleidox> table-matrix #6
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌ ┐
│43.055248 141.345505 8.0 1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756 132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483 127.692398 22.4 2128.0│
└ ┘

この例から分かるように、Tableオブジェクトの持つ表データのヘッダ行と数値以外の情報が入っている列を取り除いた情報を行列に再構築してくれます。

ただし今回は行列は使用しません。

table-select関数

回帰分析のような数値演算を行う場合、通常はMatrixオブジェクトを使用しますが、単回帰分析のような定番の分析手法は表に対して直接使用できるようになっています。

この記事の先頭でtable-chart関数によってTableオブジェクトの内容から自動抽出した情報を散布図として表示する操作を行いました。

この散布図に回帰分析の結果を重ねて表示してみることにします。

file.csvのデータをそのまま使ってもよいのですが、都市の緯度と経度に対して単回帰分析を行っても面白くないので、都市の緯度と平均気温に対して単回帰分析を行ってみます。

まずTableデータの第1列に都市名、第2列に緯度、第3列に平均気温を取るTableオブジェクトを生成します。これはtable-chart関数が散布図を描く時に、デフォルトでは第1列に項目名、第2列にX軸の値、第3列にY軸の値を想定しているためです。

この変換はtable-select関数で行うことができます。以下の例ではtable-select関数の引数に範囲オブジェクト「0,1,3」を指定しています。この結果オリジナルの表の第1列、第2列、第4列の内容をこの順番で並べたTableオブジェクトが生成されます。なお範囲オブジェクトの添字は0ベース、表の表現では添字は1ベースで表現しています。

kaleidox> table-select 0,1,3 #6
Table[3x8]
kaleidox> :show:print
Table[3x8]
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━┓
┃都市 │緯度 │平均気温┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━┫
┃札幌 │43.055248│8.0 ┃
┃仙台 │38.254162│11.9 ┃
┃東京 │35.680909│15.3 ┃
┃名古屋│35.154919│14.9 ┃
┃大阪 │34.702509│16.2 ┃
┃広島 │34.377560│15.0 ┃
┃福岡 │33.579788│16.0 ┃
┃那覇 │26.204830│22.4 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━┛

このTableオブジェクトに対してtable-chart関数を適用すると以下の散布図が表示されました。

kaleidox> table-chart

単回帰分析

単回帰分析を行った結果をチャート上に表示する場合はanalyzeオプションにsimple-regressionを指定します。

先程作成したTableオブジェクトのヒストリを確認します。

:history
1: nil
2: Table[3x10]
3: Matrix[1x10]
4: Matrix[2x10]
5: Matrix[1x2]
6: Table[5x8]
7: Window
8: Table[3x8]

8番目にあることが分かったので「#8」でアクセスすることができます。

単回帰分析の結果を散布図上に表示するためにはanalyzeオプションにsimple-regressionを指定します。

kaleidox> table-chart :analyze 'simple-regression #8

上記のtable-chart関数の結果、以下の単回帰分析付きの散布図が表示されました。


まとめ

CSVファイルから読み込んだTableオブジェクトに対して、table-selection関数による簡単な加工のみで散布図の表示、単回帰分析の結果表示を行うことができました。

通常のプログラミング言語でこの処理を行うとCSVファイルの読み込み、チャート機能の利用、数値演算処理による単回帰分析など案外大変なコーディングが必要になりますが、Kaleidoxではあっさりと実現できました。

このようなことが可能になるのは、Kaleidoxで汎用データ構造であるTableオブジェクトを言語の中軸機能と位置付け、Tableオブジェクトを対象にさまざまな関数を用意しているからです。

Kaleidoxはアクション言語として設計していますが、PIM(Platform Independent Model)的な抽象処理のみが記述できるだけだと実用性に乏しくなります。そういった抽象的な機能と同時に今回のTableデータ処理のような地味な実用機能もサポートし、シームレスに連携できることが必要だと考えています。

諸元

  • Kaleidox : 0.1.10
気象データ

以下のページ「5.おもな都市の月平均気温・月降水量」のデータを使用しました。

http://www.biodic.go.jp/reports/2-2/hyo/aa126_001.html

Kaleidox: モデル駆動開発

$
0
0

Kaleidoxはモデル駆動開発のアクション言語を指向しています。実用言語の観点から、データ操作の枠組みとしてRecordとTableを中心とした機能群を用意しています。

一方、モデル駆動開発に適用するためにはモデル側との連携も必要になります。

今回はモデル駆動開発のためのモデル定義とアクション言語の連携について、現時点で実装している簡単な機能を例に探っていきます。

初期設定

以下のinit.kldを用意します。

* env

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

* voucher

** City

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル |
|------+---------------------+--------+--------+--------------|
| 属性 | name | int | 1 | 都市 |
| 属性 | latitude | string | 1 | 緯度 |
| 属性 | longitude | int | 1 | 経度 |
| 属性 | average_temperature | int | 1 | 平均気温 |
| 属性 | precipitation | int | 1 | 降水量 |

* prologue

store-create 'City 'city

この初期設定により以下の設定が行われます。

  • メモリDBの初期化
  • モデルの定義
  • モデルに従ったデータベースのテーブルの作成
メモリDBの初期化

envセクションで組み込みRDBのH2をメモリモードで起動するように記述しています。

モデルの定義

voucherセクションでモデルの定義を行っています。

モデルに従ったデータベースのテーブルの作成

prologueセクションでテーブルを作成する記述を行っています。

モデル

voucherセクションで以下のモデルを記述しています。

ボクは2008年ごろから帳票指向アーキテクチャをターゲットにしたモデリングの手法SimpleModelingを整備しています。

SimpleModelingではSimpleModelerというモデルコンパイラでプログラムの自動生成を行うことが可能です。

voucherはSimpleModelingのアーキタイプで「伝票」を記述するためのモデルです。一般のOOADではValue ObjectやDTO(Data Transfer Object)という方向性のモデルです。

SimpleModelingでは、voucher以外にも多数の種類のモデルを定義していますが、現時点ではKaleidoxではvoucherのみサポートしています。

現在SimpleModelerの新版を開発中で、これをKaleidoxに組み込めば各種モデルの操作をKaleidoxで行うことができるようになる予定ですが、現在は暫定的にvoucherのみ扱い可能にしています。

voucherセクションで定義しているvoucherは都市の緯度・経度、平均気温、降水量を定義した以下のものです。

* voucher

** City

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル |
|------+---------------------+--------+--------+--------------|
| 属性 | name | int | 1 | 都市 |
| 属性 | latitude | string | 1 | 緯度 |
| 属性 | longitude | int | 1 | 経度 |
| 属性 | average_temperature | int | 1 | 平均気温 |
| 属性 | precipitation | int | 1 | 降水量 |

この表の定義によってvoucher Cityが定義されます。

テーブルの作成

前述のinit.kldのprologueセクションは以下になっています。

* prologue

store-create 'City

store-create関数はテーブルの作成を行います。第1引数にモデル名Cityを指定しています。

このためKaleidox起動時にprologueセクションでこのstore-create関数が実行され、バウチャーCityのモデル定義に従ったテーブルCityがメモリDB内に作成されます。

今回はテスト目的でメモリDBを使用していますが、MySQLなどのRDBを使う場合にすでにテーブルが作成されている場合はこの処理は不要です。

データ格納

init.kldの設定によりKaleidox起動後はテーブルcityが作成されています。このテーブルにデータの格納を行ってみます。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

「file:city.csv」によりcity.csvを読み込みます。 city.csvはTableオブジェクトとして読み込まれます。

kaleidox> file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市 │緯度 │経度 │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌 │43.055248│141.345505│8.0 │1158 ┃
┃仙台 │38.254162│140.891403│11.9 │1219 ┃
┃東京 │35.680909│139.767372│15.3 │1460 ┃
┃名古屋│35.154919│136.920593│14.9 │1575 ┃
┃大阪 │34.702509│135.496505│16.2 │1400 ┃
┃広島 │34.377560│132.444794│15.0 │1603 ┃
┃福岡 │33.579788│130.402405│16.0 │1690 ┃
┃那覇 │26.204830│127.692398│22.4 │2128 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

読み込んだTableオブジェクトをテーブルCityに書き込みます。

Tableのヘッダにあるカラム名をキーにしてテーブルに書き込みます。このカラム名はVoucherモデルの名前だけでなくラベルとも照合されます。

たとえばVoucherモデルの定義ではCityオブジェクトの都市名を格納する属性はnameですが、ラベルが「都市」になっています。このためTableオブジェクトのカラム名nameだけでなくカラム名「都市」も格納対象となります。他のカラムも同様に、Cityオブジェクトの各属性とも対応付けられます。そして、Cityオブジェクトを格納するCityテーブルの該当するカラムとの対応付けも行われます。

テーブルへの追加格納はstore-insert関数で行います。

第1引数にテーブル名、第2引数にTableオブジェクトを指定します。ここではTableオブジェクトの読み込み直後で、Tableオブジェクトがスタックの先頭に積まれているので第2引数を省略してスタック上のTableオブジェクトを指定しています。

kaleidox> store-insert 'City
(0 0 0 0 0 0 0 0)

store-insert関数の返却値は新規作成したレコードのIDのリストです。CityテーブルはIDを持たないテーブルのためレコード数分の0を要素として持つリストが返されています。

データの読み込み

store-select関数でテーブルに格納したデータを読み込みます。

kaleidox> store-select 'City
Table[5x10]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━┓
┃name │latitude │longitude │average_temperature│precipitation┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━┫
┃札幌 │43.055248│141.345505│8.0 │1158.0 ┃
┃仙台 │38.254162│140.891403│11.9 │1219.0 ┃
┃東京 │35.680909│139.767372│15.3 │1460.0 ┃
┃名古屋│35.154919│136.920593│14.9 │1575.0 ┃
┃大阪 │34.702509│135.496505│16.2 │1400.0 ┃
┃広島 │34.37756 │132.444794│15.0 │1603.0 ┃
┃福岡 │33.579788│130.402405│16.0 │1690.0 ┃
┃那覇 │26.20483 │127.692398│22.4 │2128.0 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛

store-select関数のデフォルト動作ではモデルの属性名が使用されます。このため、都市はname、緯度はlatitudeといったヘッダ名を使用したTableオブジェクトとなっています。

プログラム的にデータを処理する場合はこの方が都合がよいですが、外部出力を行う場合はモデル側のラベル名がTableオブジェクトのヘッダ名になっている方が便利です。

このための指定を行うオプションとしてstore-select関数ではtable-headerスイッチを用意しています。

以下では(Lispの)キーワード指定によってtable-headerスイッチにlabelを指定しています。このためstore-select関数では、データを読み込むTableオブジェクトのカラム名をモデルのラベル名にしています。

kaleidox> store-select :table-header 'label 'City
Table[5x10]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市 │緯度 │経度 │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌 │43.055248│141.345505│8.0 │1158.0┃
┃仙台 │38.254162│140.891403│11.9 │1219.0┃
┃東京 │35.680909│139.767372│15.3 │1460.0┃
┃名古屋│35.154919│136.920593│14.9 │1575.0┃
┃大阪 │34.702509│135.496505│16.2 │1400.0┃
┃広島 │34.37756 │132.444794│15.0 │1603.0┃
┃福岡 │33.579788│130.402405│16.0 │1690.0┃
┃那覇 │26.20483 │127.692398│22.4 │2128.0┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

チャート表示

最後に、テーブルから読み込んでみたデータをチャートに表示しましょう。ここからは前回「Kaleidox/単回帰分析」と同じ処理です。詳細はそちらを参照してください。

まずTableオブジェクトからチャートに表示するデータを抽出します。

kaleidox> table-select 0,1,3 x
Table[3x8]
kaleidox> :show:print
Table[3x8]
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━┓
┃都市 │緯度 │平均気温┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━┫
┃札幌 │43.055248│8.0 ┃
┃仙台 │38.254162│11.9 ┃
┃東京 │35.680909│15.3 ┃
┃名古屋│35.154919│14.9 ┃
┃大阪 │34.702509│16.2 ┃
┃広島 │34.377560│15.0 ┃
┃福岡 │33.579788│16.0 ┃
┃那覇 │26.204830│22.4 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━┛

このTableオブジェクトをtable-chart関数でチャートに表示します。

まず、抽出後のTableオブジェクトを変数xに束縛します。Tableオブジェクトは抽出直後なのでスタックの先頭に積まれています。setq関数の第2引数を省略することでスタック上のTableオブジェクトが束縛対象となります。

kaleidox> setq x
kaleidox> table-chart x

以下のようなチャートが表示されます。


また単回帰分析を行う場合はanalyzeスイッチにsimple-regressionを指定します。

kaleidox> table-chart :analyze 'simple-regression x

以下のようなチャートが表示されます。


まとめ

頭出しレベルですが、モデル駆動開発のイメージを確認するために簡単な連携例を説明しました。

基本的な方向性としては、モデル定義を行った後は簡単なアクション言語による記述のみでアプリケーションを記述したいということです。

モデル定義がのままプログラミングにつながることで、モデルをプログラムに翻訳することによって起きているプログラミングの工数を大幅に低減することできます。また、これと同じぐらい重要なのはモデルとプログラムのインピーダンスミスマッチをなくすることができることです。モデルとプログラミングが一体となることで、よりモデリングに集中することができます。

SimpleModelerの改版版は現在開発中ですが、これをKaleidoxに組み込むことでより広範囲のモデルをモデル駆動の対象としてアプリケーション開発に活用できることができるようになります。

諸元

  • Kaleidox : 0.1.10
気象データ

以下のページ「5.おもな都市の月平均気温・月降水量」のデータを使用しました。

http://www.biodic.go.jp/reports/2-2/hyo/aa126_001.html


Kaleidox/スタック

$
0
0

アクション言語は複雑なアルゴリズムを記述するというより、入力データと状態の組み合わせに対してデータ変換を行い変換後のデータを後続のシグナルに乗せて発信するという処理が中心となります。

このような処理の記述にはパイプラインのセマンティクスが適しています。

パイプラインを記述するためのプログラミング後の構文としてはUNIXシェルの以下の形式が有力です。

cat file.txt | grep foo | sort

この記述方式は直感的で強力ですが、一般的なプログラミング言語の文法とセマンティクスが異なるため、汎用言語の一要素として併存させることは苦労が伴います。パイプラインで記述できない処理が出てきた時に、パイプライン以外の方式で記述した上で、それをパイプラインにどのように簡潔な形で統合していくのかという点が問題です。煩雑な記述方式で統合すると、"直感的で強力"な文法が失われてしまいます。

この問題への対応としてKaleidoxではスタックのメカニズムを用意しています。スタックを用いることで、パイプラインのセマンティクスに近い形で通常のプログラミング言語との"直感的で強力"な統合を目指しています。

スタック

式の評価結果はスタックにプッシュされます。

たとえばREPLから1、2、3と順に入力するとそれぞれの式の評価結果である数値がスタックにプッシュされていきます。

kaleidox> 1
1
kaleidox> 2
2
kaleidox> 3
3

スタックの様子はstackコマンドで表示することができます。先程入力した数値がスタック上に逆順で積まれていることが確認できました。

kaleidox> #stack
1: 3
2: 2
3: 1
...略...

関数は必須引数数が定義されており、引数の数がこれに満たない場合は不足分をスタックから持ってくるようになっています。

前述のスタックの状態の元で関数+を引数なしで投入してみます。+関数の必須引数の数は2なので、スタックから2つの値をポップし、これを引数として利用します。

kaleidox> +
6

+関数実行後のスタックは以下になります。

kaleidox> #stack
1: 1
...略...

より実用的な例としてCSVデータをチャートで表示する処理を考えてみます。

以下のCSVデータをcity.csvとして用意します。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

table-load関数でCSVデータをtableオブジェクトとして読み込みます。

kaleidox> table-load file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市 │緯度 │経度 │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌 │43.055248│141.345505│8.0 │1158 ┃
┃仙台 │38.254162│140.891403│11.9 │1219 ┃
┃東京 │35.680909│139.767372│15.3 │1460 ┃
┃名古屋│35.154919│136.920593│14.9 │1575 ┃
┃大阪 │34.702509│135.496505│16.2 │1400 ┃
┃広島 │34.377560│132.444794│15.0 │1603 ┃
┃福岡 │33.579788│130.402405│16.0 │1690 ┃
┃那覇 │26.204830│127.692398│22.4 │2128 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

続けて、table-select関数を使って読み込んだ表の必要部分だけ切り取ります。ここでは第0、1、3カラムを残し、都市、緯度、平均気温の表にしています。

kaleidox> table-select 0,1,3
Table[3x8]
kaleidox> :show:print
Table[3x8]
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━┓
┃都市 │緯度 │平均気温┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━┫
┃札幌 │43.055248│8.0 ┃
┃仙台 │38.254162│11.9 ┃
┃東京 │35.680909│15.3 ┃
┃名古屋│35.154919│14.9 ┃
┃大阪 │34.702509│16.2 ┃
┃広島 │34.377560│15.0 ┃
┃福岡 │33.579788│16.0 ┃
┃那覇 │26.204830│22.4 ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━┛

table-select関数は第1引数に選択するカラムを示す範囲を第2引数に対象のtableオブジェクトを取ります。第1引数のみ指定されてるので、第2引数はスタックよりtable-load関数の評価結果であるcity.csvを読み込んだtableオブジェクトが指定されます。

続けてtable-chart関数を使ってチャートの表示を行います。

kaleidox> table-chart :analyzes 'simple-regression

table-chart関数ではキーワードanalyzesにsimple-regressionを指定しているので、散布図の上に単回帰分析の結果が表示されます。キーワードの後ろに指定する引数ではtableオブジェクトを取ります。ここが省略されているので、スタックよりtable-select関数の評価結果であるカラム射影後のtableオブジェクトが指定されます。

この結果、以下のチャートが表示されます。

関数

ここまでREPLで試してきた処理では以下の3つの関数を順に実行しています。

  • table-load
  • table-select
  • table-chart

これは前出のUNIXシェルのパイプラインの記述方式を使うと以下のようなイメージです。

table-load file:csv | table-select 0,1,3 | table-chart :analyzes 'simple-regression

この処理を通常のLisp文法で関数化したものが以下のshowchart関数です。

(defun showchart (uri)
(setq a (table-load uri))
(setq b (table-select 0,1,3) a)
(table-chart :analyzes 'simple-regression b))

前段の処理結果を後段に受け渡していくパイプライン的な処理ですが、この例でも分かるように手続き型的な記述方式では変数を使ってデータを受け渡していく形になります。

この記述方式でも実用的には問題ありませんが、UNIXシェルの記述方式に比べると煩雑であることは否めません。

KaleidoxではUNIXシェルのような記述はできませんが、関数呼び出しをシーケンシャルに並べてパイプライン的な処理を簡潔に記述することができます。

この記述を用いて関数化したものが以下のshowchart関数です。

(defun showchart (uri)
(table-load uri)
(table-select 0,1,3)
(table-chart :analyzes 'simple-regression))

table-load, table-select, table-chartのそれぞれの評価結果をスタックを用いて後続の関数に受け渡しています。

スタックを用いてこのような記述方式を可能にすることで、パイプライン的な処理を簡潔に記述することが可能になっています。

まとめ

アクション言語は、汎用言語としての記述力も重要ですが、処理の中心はデータ変換のパイプライン処理になるので、パイプライン処理を簡潔に記述する記述能力も重要になります。

Kaleidoxではスタックを用いてパイプライン処理を簡潔に記述することを可能にしているわけです。

関数型言語ではFunctor(Scalaではmap関数)やMonad(ScalaではflatMap関数)を用いてパイプライン処理を記述することが可能になっています。この関数型言語方式もパイプラインの記述方式としては有力、というか汎用言語としては本命と思いますが、アクション言語にはやや重いのではないかというのがボクの見立てで、スタックによる記述方式を開発しました。

関数型言語方式とスタック方式の比較検討はいずれ行いたいと思います。

諸元

  • Kaleidox : 0.1.11

モデル駆動によるクラウド・アプリケーション開発

$
0
0

「クラウド」というとすでにややレトロな響きも出てきたかもしれません。しかし、Kubernetes/Dockerといった足回りやAWS Lambdaのような要素技術は登場していますが、クラウド・アプリケーション全体を構築するための開発手法の整備にはまだ手がついていない状況だと思います。

当ブログではModegrammingをキーワードに、モデリングとプログラミングを融合したモデル駆動開発を提唱しており、このModegrammingのクラウド・アプリケーションへの適用を中心的なテーマとしています。

Modegrammingを成立させるためには、開発手法を下支えする開発ツールや実行プラットフォームの存在が不可欠です。この目的で現在、以下の5つのプロダクトを開発しています。

SmartDox
文書処理系
SimpleModeler
モデルコンパイラ
Kaleidox
アクション言語
Arcadia
Webフレームワーク
Prefer Cloud Platform
クラウド・アプリケーション・プラットフォーム

2008年からScalaを使って少しずつ開発を進めてきましたが、かなり整備が進んできたので現在の状況についてまとめてみました。

SmartDox

SmartDoxはSmartDocの後継となる文書処理系です。OSSとして開発しています。

SmartDocは文書形式としてXMLを採用していましたが、SmartDoxではMarkdownとEmacs orgを融合させた独自のプレインテキストを文書形式として使用します。

本ブログもSmartDox形式で記述したものを、SmartDoxでBlogger形式を生成したものをBloggerに貼り付けています。

文書処理系とモデル駆動開発との関係は一見なさそうにもみえますが、Modegrammingの中でSmartDoxを重視しているのは、Literate Programming、Literate Modeling、ひいてはLiterate Modegrammingの基盤となる文書処理基盤を提供するためです。具体的には、後述するSimpleModelerとKaleidoxがSmartDox基盤を使用してLiterate Modeling, Literate Programmingを実現しています。

SmartDoxは当面はSimpleModeler、Kaleidox、Arcadiaの中でLiterate Modegramming(Literate Modeling + Literate Programming)を実現するための要素技術として使用していく予定です。

将来的にはSmartDocと同様に、独立した文書処理系として公開するかもしれません。

SimpleModeler

SimpleModelerはRelaxerの後継となるモデルコンパイラです。OSSとして開発しています。

RelaxerはXMLスキーマ言語(RELAX)からJavaなどのプログラムを生成するスキーマコンパイラです。

RelaxerはXMLを扱うアプリケーション開発に非常に有益だったと思いますが、スコープがXMLに閉じているため応用範囲が限られました。ただ、プログラムの自動生成の可能性については十分認識することができました。

次の段階としてオブジェクトモデルからのプログラムの自動生成を行うために開発を始めたのがSimpleModelerです。SimpleModelerはオブジェクトモデルからJavaやScalaなどのプログラムを生成するモデルコンパイラです。

2008年から開発を始め、一応の実用化レベルの機能は提供できています。後述のPCP開発にも使用しています。

Scalaの内部DSLを主となるDSLとして採用したのですが、オブジェクト・モデルの記述にはあまり適さないことが分かってきたのでSmartDoxをベースとした外部DSLを主DSLとするように切り替える開発を進めていました。

同時に、オブジェクト・モデルのメタモデルの拡張をクラウド・アプリケーション向けに拡張する作業を進めています。

Kaleidox

モデル駆動開発をターゲットにしたアクション言語です。OSSとして開発しています。

モデル駆動開発のアキレス腱となっているのが、振る舞いの記述です。オブジェクト・モデルでは、静的構造は自動生成可能な精度のモデル記述が可能ですが、動的振る舞いについては状態機械モデルまでが自動生成可能な精度のモデル記述が可能なものの、それ以上の振る舞いについてはスコープ外になっています。

このため、モデル・コンパイラでプログラムの自動生成をする場合でもプログラミングとの併用が必須となり、ちらにしてもプログラミングが必要となるのであればプログラミングを主軸にし、モデリングは概念レイヤーのメモ書きレベルの使用に限るようなバランスが妥当ともいえます。

この「振る舞い」に関する問題がモデル駆動開発のアキレス腱となっていました。

この問題は、モデル駆動開発用のアクション言語によって解決できるのではないか、というアイデアのもと開発したのがKaleidoxです。

Kaleidoxについては本ブログで紹介してきました。スクリプト言語としては実用ゾーンに入って来たと思いますが、引き続き本命のアクション言語として活用できるように、SimpleModelerとの繋ぎ込みを進めていく予定です。

Arcadia

Arcadiaはモデル駆動開発をターゲットにしたWebフレームワークです。OSSとして開発しています。

モデルコンパイラでプログラムの自動生成を行う際に問題となるのが、自動生成したプログラムの実行基盤です。

この問題に対応するために、ArcadiaはWeb UIを構築するWebアプリケーションの自動生成を用意にするための以下のような仕組みを導入しています。

  • プログラムではなくメタデータ設定でWebアプリケーション開発を可能にする。
  • バックエンドのクラウド・プラットフォームとシームレスに連携できるようにする。
  • シナリオによるWeb入力機構を搭載している。
  • アクション言語(kaleidox)を使って処理の記述が可能になっている。

バックエンドのクラウド・プラットフォームとして後述するPrefer Cloud Platformも使用できますが、アダプタを作れば任意のクラウド・プラットフォームを使用することが可能です。

アクション言語であるkaleidoxとの統合は、モデル駆動開発との連携を指向したものです。

Arcadiaは基本部は開発済みです。KaleidoxとSimpleModelerが一段落した後に公開したいと考えています。

Prefer Cloud Platform

Prefer Cloud Platform(以下PCP)はボクがCTOをやっているEverforth社が提供する商用のクラウド・アプリケーション・プラットフォームです。

PCPを用いることでクラウド・アプリケーションを高速、低コストで開発することができます。

PCPは、モデル駆動開発の実行環境としても使用できるように設計されており、現時点でもSimpleModelerによる自動生成を活用して開発を行っています。

しかし、現時点ではPCP上で動作するクラウド・アプリケーションを自動生成するところまでは到達できていません。SimpleModeler、Kaleidox、Arcaidaが整備されることで、オブジェクト・モデルからのクラウド・アプリケーションの自動生成が可能になることを目指しています。

関連書籍

モデル駆動開発を行うためにはオブジェクト・モデルのメタモデルの整備も必要です。

この整備はwakhok時代から進めており、2008年当時の成果を以下の書籍にまとめています。いずれもwakhok時代に教科書として使うことを目的に書いたものです。

しかし、2008年当時とはクラウド環境をめぐる状況が大きく変わっており、それらの要素を取り込んだメタモデルの拡張が必要です。

上記の書籍の内容をベースに、SimpleModelerの開発を進めながらメタモデルの拡張も同時に行っています。

その成果もいずれ文書としてまとめていきたいと思います。

まとめ

本ブログが提唱しているModegrammingを支える開発ツール、実行プラットフォームの開発の近況について説明しました。

2008年から少しずつ進めてきた開発ですが、すでに商用化されているPCPに加えて、いくつかのOSSも実用ゾーンに入りつつあります。

OSSが実用ゾーンに入ってきたことで、クラウド・アプリケーション向けのオブジェクト・モデルのメタモデルを、実用化を前提として具体的に検討をすすめることが可能になってきました。メタモデルの拡張はSimpleModelerの開発と並行して行っています。

まだまだ開発途上ですが、本ブログで継続して開発の成果を報告していく予定です。

SmartDox

$
0
0

前回の記事ではModegrammingをキーワードにしたモデル駆動開発向けに開発している5つのプロダクトについて説明しました。

SmartDox
文書処理系
SimpleModeler
モデルコンパイラ
Kaleidox
アクション言語
Arcadia
Webフレームワーク
Prefer Cloud Platform
クラウド・アプリケーション・プラットフォーム

今回は、この中のSmartDoxについて紹介します。

SmartDoc

2000年ごろに文書処理系のOSSであるSmartDocを開発していました。

SmartDocはXML形式のSmartDoc文書で記述したソースから、HTML、PDF(Tex経由)、プレインテキストを生成します。

SmartDocは個人用文書作成ツールとして便利に使っていたのですが、モデル駆動開発のDSLの基盤としても活用できないか、検討を重ねてきました。というのは、文芸的プログラミング(literate programming)をモデル駆動に適用した文芸的モデリング(literate modeling)の実現しようと考えたからです。

文言的モデリングを実現するためには、モデルの内容を説明した文章とモデル定義を同一のプレインテキスト内に自然な形で同居させる必要があります。

モデル記述言語

Modegrammingにおけるモデル駆動開発を行うためのモデル記述言語を考えた場合、前述した文芸的モデリングが重要な要素になります。

一方オブジェクト指向モデリング言語のデファクトであるUMLは、以下のような理由でモデル駆動開発で本格活用するのは難しいのではないか、と個人的に考えています。

  • UMLはグラフィカル言語であるためモデルの入力が煩雑
  • グラフィカル言語は大規模モデルの編集が難しい

また、UMLの編集に専用ツールが必要、というのも運用上の問題点です。

格納形式も独自形式になるので、UMLモデルを作成したツールでしか編集することができません。商用製品の場合、製品にロックインされることになるため、経費がかかることに加えて、将来製品が販売停止になった時にはモデルの再利用や保守などにも問題がでてきそうです。

格納形式が独自形式になることで、テキストベースのバージョン管理システムで管理することが難しくなるという問題もあります。

このようにグラフィカル言語のUMLを、本格的な開発に適用することは色々と問題がありますが、その一方でUMLで定義しているオブジェクト・モデルのメタ・モデルは業界標準としてのコンセンサスがとれているものなので活用したいところです。

以上のことを考えると、モデル駆動開発向けのモデリング言語として以下の要件に行き着きました。

  • プレインテキストでモデル定義とモデルの説明文を文芸的モデリング的に同居できる
  • UMLのメタ・モデルをベースにしている

これを実現するためのメタメタモデルとしてSmartDocが活用できないかと考えたわけです。

SmartDox

SmartDoxはOSSで開発しているSmartDoc後継の文書処理系です。

モデル駆動開発のためのモデリング言語のDSLを構築するためのメタメタモデルを提供しています。

同時に、本来の機能である文書処理系にもSmartDocと同様の機能セットを提供することを目標にしています。本ブログもSmartDoxで書いたものをBlogger形式に変換しています。

SmartDoxはEmacs org形式をベースにMarkdownとHTML、XMLの文法をマージした文法を定義しました。

SmartDocはXMLベースでしたが、SmartDoxはプレインテキストベースの文書形式になっています。近年はMarkdownによるプレインテキストがソフトウェア開発での文章作成のデファクトになっているのでMarkdownを取り入れています。また、ボクが通常Emacs上でEmacs orgモードで文章作成しているのでEmacs org形式もサポートしています。ざっくりいうとEmacs org形式とMarkdown双方の緩い上位互換をとりつつ、拡張文法としてHTMLやXMLによる詳細指定を可能にした文法になっています。

このSmartDox文法によって、以下の3種類の文書を構築する構成要素が得られます。

  • セクションの入れ子による木構造
  • テーブルによる表構造
  • マークアップ付き自然言語

この中で「セクションの入れ子による木構造」と「テーブルによる表構造」をモデル駆動開発におけるモデル記述のメタメタモデルとして使用するのがSmartDoxによるモデル記述の基本アイデアになっています。

また「マークアップ付き自然言語」によってモデルに対する説明文をモデル記述内に自然に配置することができます。

SmartDoxベースのDSL

SmartDoxによるDSL基盤を使ってSimpleModelerとKaleidoxを実装しています。

SimpleModeler

SimpleModelerはモデル駆動開発に用いるモデルコンパイラです。

元々ScalaのDSL機能を用いてモデル定義をする方式を主にしていましたが、現在開発中の新バージョンよりSmartDoxベースのモデル記述方法に一本化しました。

SimpleModelerのモデル定義の例を以下に示します。

#+title: サンプル

SimpleModelerのサンプルです。
以下のようにコンパイルします。

```
$ sm java sample.org
```

* Resource

** Person

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル | カラム | データ型 | 備考 |
|------+---------+---------+--------+--------+--------+----------+------|
| 属性 | name | token | 1 | | | | |
| 関連 | address | Address | 1 | | | | |

** Address

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル | カラム | データ型 | 備考 |
|------+------+-------+--------+--------+--------+----------+------|
| 属性 | zip | token | ? | | | | |

リソース・エンティティの2つクラスPersonとAddressを定義しています。

SmartDoxのセクションの階層構造を利用してクラス種別のResourceとその配下にクラスPersonとAddressを定義しています。

Kaleidox

次の例はモデル駆動開発向けのアクション言語Kaleidoxです。

Kaleidoxでは、スクリプトを用途ごとに文法の違う複数のセクションで構成する構造になっています。

Kaleidoxのスクリプトの例を以下に示します。

* description

Kaleidoxでモデルを使用する例です。

* env

db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:mem:"

* voucher

** user

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル |
|------+------+--------+--------+---------|
| 属性 | id | int | 1 | User ID |
| 属性 | name | string | 1 | 名前 |
| 属性 | age | int | ? | 年齢 |

* main
(store-query 'user nil)

スクリプト全体はSmartDoxの文法によって記述されており、プログラムを記述するmainセクションにKaleidoxのスクリプトが書かれています。

以下の例はdescription, env, voucher, mainの4つのセクションで構成されたKaleidoxスクリプトです。

descriptionセクションはスクリプトの説明を書くセクションです。SmartDox形式のプレインテキストを記述します。

envセクションはスクリプト実行時の環境変数をHOCON(typesafe config)形式で定義します。

voucherセクションはVoucherステレオタイプを持ったクラスを定義するセクションです。SimpleModeler形式の表形式でモデルを記述します。

mainセクションはスクリプト本体をKaleidoxスクリプト形式(S式)で記述します。

以上から分かる通り、各セクションの構造はSmartDoxのセクションを利用し、自然言語による記述を行うセクションではSmartDox形式を用いています。

まとめ

今回はオブジェクトモデル記述のためのDSL基盤の側面からSmartDoxについて紹介しました。

次回はSimpleModelerの紹介をする予定です。

SimpleModeler

$
0
0

前前回の記事ではModegrammingをキーワードにしたモデル駆動開発向けに開発している5つのプロダクトについて説明しました。

SmartDox
文書処理系
SimpleModeler
モデルコンパイラ
Kaleidox
アクション言語
Arcadia
Webフレームワーク
Prefer Cloud Platform
クラウド・アプリケーション・プラットフォーム

今回はSimpleModelerについて紹介します。

SimpleModeler

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

SimpleModelerはSimpleModel形式で記述されたモデルを入力し、JavaやScalaのプログラムを始め各種生成物を生成します。

モデル

SimpleModelerはSmartDox形式の文書として記述したSimpleModelを入力とします。SmartDox形式はざっくりEmacs org形式とMarkdown形式を折衷した形式です。

SimpleModelは、現在、静的構造モデル(UMLではクラス図、パッケージ図など)とユースケースモデルを記述することができます。この中でユースケースモデルと静的構造モデルはモデル検証用に、静的構造モデルはプログラムの生成に使用します。

静的構造モデルでは以下のような種類のオブジェクトをステレオタイプとして定義しています。

Resource
リソース
Event
イベント
Actor
アクター
Role
ロール
Voucher
バウチャー
Powertype
パワータイプ

これらのオブジェクトを適材適所で使用してモデルを記述することで、モデルの精度や情報量も高まり、より適切なプログラムの生成につなげることができます。

今回はシンプルにResourceのみを定義したモデルを使います。

#+title: サンプル

* Resource

サンプルモデルのリソースです。
PersonとAddressを定義しています。

** Person

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル | カラム | データ型 | 備考 |
|------+---------+---------+--------+--------+--------+----------+------|
| 属性 | name | token | 1 | | | | |
| 関連 | address | Address | 1 | | | | |

利用者です。

住所を記述するAddressへの関連を持っています。

** Address

#+caption: 特性一覧
| 特性 | 名前 | 型 | 多重度 | ラベル | カラム | データ型 | 備考 |
|------+------+-------+--------+--------+--------+----------+------|
| 属性 | zip | token | ? | | | | |

住所です。

ここではEmacsでの編集が楽なorg形式の文法を使用して記述しています。

このモデルではリソースPersonとAddressを定義しています。

まず「* Resource」で以下のクラス定義がリソースであることを示しています。

つぎに段落を一つ下げた「* Person」、「* Address」でそれぞれPersonとAddressを定義してます。Personは利用者、Addressは住所を記述するためのリソースです。

オブジェクトの属性や関連は「特性一覧」の表で定義しています。

段落と表以外はモデルとして認識しないので、モデルの説明などの文章を自由に書くことができます。

このモデルをsample.orgというファイルに格納します。

生成

前出のサンプルから各種成果物を生成することができます。

Java

SimpleModelを格納したsample.orgを引数にsmコマンドを起動します。

第1引数にjavaを指定するとJavaプログラムを生成します。

$ sm java sample.org

以下のようなJavaプログラムが生成されます。

import java.math.*;
import java.util.*;
import org.json.*;
import org.simplemodeling.SimpleModeler.runtime.USimpleModeler;

public class Person {
public static final String PROPERTY_NAME = "name";
protected String name;
protected Adress address;

public Person() {
}

public Person(Person o) {
this.name = o.name;
this.address = o.address;
}

public Person(String name, Adress address) {
this.name = name;
this.address = address;
}

public Person(PersonVoucher o) {
this.name = o.name;
this.address = o.address;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Adress getAddress() {
return address;
}

public void setAddress(Adress address) {
this.address = address;
}

public Person withName(String name) {
this.name = name;
return this;
}

public Person withAddress(Adress address) {
this.address = address;
return this;
}
}
Scala

smコマンドの第1引数にscalaを指定するとScalaプログラムを生成します。

$ sm scala sample.org

以下のようなScalaプログラムが生成されます。

class Person(var name: String) {
private String name;

def public String getName() = {
return name;
}

def public void setName(String name) = {
this.name = name;
}

def public Person withName(String name) = {
this.name = name;
return this;
}
}
UML

smコマンドの第1引数にumlを指定するとUMLのクラス図を生成します。

$ sm uml sample.org

生成したクラス図は以下になります。


まとめ

今回はSimpleModelerについて説明しました。

次回は、SimpleModelerの扱うオブジェクトメタモデルSimpleModelについて説明します。

SimpleModel

$
0
0

簡単なWebサイトの開発などはDBスキーマ設計+プログラミングで十分なケースも多いと思いますが、複雑な業務や高度なユーザー経験を実現する場合は、何らかの分析設計を行い、その結果を元に実装に落とし込む必要があります。この分析設計手法の最右翼がOOAD(Object-Oriented Analysis and Design)です。

しかし、OOADは難しい技術で独学でマスターするのはなかなか大変です。

独学でマスターすることが大変な理由として、そもそもOOADがソフトウェア工学の集大成という位置付けのものなのでカバーする技術分野の範囲も広く難易度が高いということがあります。その上で独学に適したよい教科書がないということもあります。また、モデリングをアシストするためのツール類の不足も大きな問題です。

以前、大学でモデリングを教えていた時、授業やゼミで使えそうな教科書がないことが悩みのタネでした。

一つは具体的なモデリングの手順を解説した本。UMLの文法解説の本は多いのですが、最上流から実装までの流れを順を追って解説している本がなかなかありません。

また、UMLはすべての応用に適用できるように仕様が巨大でチューニング項目も沢山ありますが、ターゲットのシステム開発向けに必要最小限の大きさにカスタマイズして使用することが想定されています。この「ターゲットのシステム開発向けに必要最小限の大きさにカスタマイズ」してあるUMLのカスタマイズ仕様、いわゆるプロファイルが定義されている本はほぼないと思います。つまり、UMLの記法を学んだだけではUMLを活用することはできないわけです。

そこで中小規模の業務アプリケーションをターゲットに整備したメタモデルとしてSimpleModelを設計しました。

SimpleModelをベースにこれらの問題を解決するために授業やゼミで使える教科書の目的で以下の2つの本を書きました。

UMLを記述言語として書いたものが『上流工程UMLモデリング』、マインドマップを記述言語としたものが『マインドマップではじめるモデリング講座』です。

『上流工程UMLモデリング』が教科書、『マインドマップではじめるモデリング講座』がゼミでのワークショップ用という位置付けです。

ソフトウェア構築技術の進化

SM2008を作成したのが2008年前後ですが、すでに12年の月日が流れており、ソフトウェアの構築技術にも大幅な変化がありました。

特に以下の3つの分野での大きな進展があります。

  • クラウド
  • AI
  • DX(Digital Transformation)
クラウド

クラウドの登場によって大きく変わったのは、大規模アクセス・大規模データのアプリケーションを簡単に構築できるようになった点だと考えています。大規模アクセス・大規模データのアプリケーション構築するための部品が多数用意され、運用管理コストを含めたコストが安価に提供されるようになりました。

逆に言うと大規模アクセス・大規模データの業務アプリケーションを開発する必然性が生まれたわけで、スケールアウトや非同期処理・分散処理を達成するための技術力が求められるようになりました。

それに伴い、以下のようなアーキテクチャが登場してきました。

  • CQRS
  • Event Sourcing
  • Microservice

これらのアーキテクチャに対して、業務アプリケーションのモデリング上でどのように対峙していくのかが論点になるでしょう。

AI

業務アプリケーションの開発においてもAIは無視できない存在になってきました。

ただ、業務アプリケーションそのものがAIのエンジンを開発するということはなく、既存のAIエンジンを使用し、数理モデルを新規開発または既存モデルの改良という形で利用していくことになるケースがほとんどだと思います。

AIも大きく従来型の知識ベースや推論エンジンによるAIと、最近流行の機械学習型の2種類があります。

前者については、AIシステムをコンポーネントやサブシステムとしてモデル化し、利用方法を考えていく形になるでしょう。後者については利用方法を設計するのに加え、学習に必要な情報の収集方式についても検討する必要がでてきます。

DX

DXはもともと「ITの浸透が、人々の生活をあらゆる面でより良い方向に変化させる」という意味とのことですが、ソフトウェア開発の文脈では、企業活動のあらゆる側面をIT化して、企業の形態をIT中心に変換する、というようなニュアンスで語られることが多いと思います。

DXの文脈では、単なる業務アプリケーションの開発ではなく、企業活動全体を俯瞰した企業システムの構築の一環として業務アプリケーションを開発することになります。業務アプリケーションの設計ではなく、企業システム全体をモデル化した上で、その中に組み込まれる1コンポーネントという形での設計になってくるでしょう。

こうなってくると、プログラミング主導の開発では不十分で、全体像を俯瞰し、ターゲットの開発スコープを明確にするモデルの作成が必要なのは明らかです。

SimpleModel 2020

このように、SimpleModelを開発した2008年当時から見るとシステム開発を取り巻く要素技術は大幅に進化しています。この技術進化を取り込むためにSimpleModelの拡張を行うことにしました。その内容については本ブログでこれから検討していくことにします。

前述の書籍で使用しているSimpleModelをSimpleModel 2008年版と呼ぶことにします。そして、このブログでこれから検討していく新しい時代背景に対応したSimpleModelをSimpleModel 2020年版と呼ぶことにします。また簡易表記はSimpleModel 2008年版をSM2008、SimpleModel 2020年版をSM2020とします。

記述言語

前回説明したとおり、モデルコンパイラであるSimpleModelerの記述言語はSmartDoxのDSL基盤上に構築されています。すなわち、節による木構造、表による表構造を使用してのモデル定義と、自然言語による説明文を自然な形で混在させることができます。

文芸的プログラミング(Literature Programming)ならぬ文芸的モデリングということができます。

ツール

OOADによるモデリングを実務に適用するために重要なことは使いやすくて実効性のあるツールによるアシストです。

従来からUMLエディアなどのツールは存在しましたが、実務にモデリングを適用させたり、モデリング教育を効果的に行うといった目的には十分な機能を提供しきれていなかったともいます。

モデリングで作成するモデルは大きく以下の2つに分けることができます。

  • 実行可能モデル
  • 青写真モデル

実行可能モデルは、作成したモデルがプログラムとしてそのまま動いたり、プログラムを自動生成できる、といった形でプログラム開発に直接連携できるモデルです。

一方、青写真モデルはあくまで参考として使える情報であり、実際のプログラムには手作業で開発することになります。

従来モデリングが活用されてこなかった理由の一つは、せっかく苦労してモデルを作っても青写真モデル止まりだったことが大きいと思います。

モデリング活用の阻害要因であるこれらの問題に対応するため、2008年以降、Scalaを使って以下のプロダクトを整備してきました。

SmartDox
文書処理系
SimpleModeler
モデルコンパイラ
Kaleidox
アクション言語
Arcadia
Webフレームワーク
PreferCloudPlatform
クラウド・アプリケーション・プラットフォーム

これらのツールは現在SM2008向けになっていますが、SM2020のメタモデルをベースに拡張していく予定です。

まとめ

業務アプリケーション向けメタモデルであるSimpleModelの最新版SimpleModel 2020について紹介しました。

SM2020の具体的な内容については本ブログで順次検討していきたいと思います。

次回はSM2020を検討する上での論点を整理したいと思います。

クラウド・アプリケーションの特性

$
0
0

前回よりSimpleModel 2020(SM2020)の検討を進めています。

SM2020のターゲットはクラウド上に構築するクラウド・アプリケーションとなります。

そこで、まずクラウド・アプリケーションの以下の特性に対してアプリケーション・アーキテクチャとモデリングの観点から考えます。

  • 並列
  • 分散
  • スケーラビリティ
  • アベイラビリティ
  • リアルタイム
  • UI

アプリケーション・アーキテクチャ

並列

伝統的にプログラムを実行するマシンは1台、プロセッサは1CPU/1コアの時代が長く続いていたわけですが、クラウド・アプリケーションでは複数CPU/複数コアのマシンを複数台使用したシステム構成が普通となっています。

このため、この環境ではプログラムさえ書ければ容易に並列実行が可能です。

しかし、伝統的なプログラムの手法では逐次的に処理を進めるプログラミングが主で、並列処理は難易度の高いプログラミングが必要でした。

しかし、このままではクラウドによって潤沢に使用することが可能となったハードウェアの能力を活かすことができません。

積極的にクラウドの持つ並列処理能力を活かしたいところですが、アプリケーション開発で高度な並列プログラミング技法を使用することは避けたいところです。

つまりクラウド・アプリケーション開発における並列処理に求められるのは、通常のプログラミング・モデルの範囲内で無理をせず並列性能を得られる方式を整備することといえるでしょう。

アプリケーション・アーキテクチャの考慮点

アプリケーションで並列を扱う必要があるケースとして以下のものが挙げられます。

  • 並列に発生する物理事象に対する処理を高レスポンス実行
  • 大規模計算を並列で高スループット実行

CPUリソースをふんだんに使うことで高レスポンスや高スループットを実現します。

「並列に発生する物理事象に対する処理を高レスポンス実行」に対してはメッセージングベースのオブジェクト指向アーキテクチャであるアクターが有力です。

「大規模計算を並列で高スループット実行」に対しては関数のアプローチが有力です。HadoopやSparkのような大規模データ処理基盤では関数のアプローチによって並列処理のベースとしています。

また大規模データ処理基盤を使わない場合でも、関数型プログラミングによって関数を使った実装を行うことで並列処理と親和性の高いプログラムの構造になります。

アクターによる実装はやや難易度が高いので、可能であればプログラミングが容易な手法が望ましいところです。この目的に合致する技術がリアクティブストリームです。リアクティブストリームを使えば、関数型プログラミングよって関数を合成した作成したパイプラインを、バックグラウンドのアクター上で並列分散実行することが可能になります。つまり、このアプローチが使える状況の場合、通常の関数型プログラミングで安全に並列分散処理を記述することができるわけです。

このため、リアクティブストリームが使える応用ではリアクティブストリームを、そうでない場合は直接アクターを使った実装方式が有力です。

分散

本稿では「分散処理」は複数のマシン上で並行動作するエージェントが協調動作して1つの仕事を行うことを指すこととします。

概ね以下の2つのパターンがあります。

  • 複数の物理事象に対する対応をまとめあげて1つの仕事を行う
  • 1つの大きな仕事を複数のエージェントで分担して行う

いずれの場合も、エージェント間の分散合意の技術がキーポイントとなってきます。最重要な分散合意技術がデータベースに対する分散トランザクションです。

現時点では分散トランザクションは一応の標準プロトコルは存在するものの気軽に使える日用品の技術というわけではありません。

また、分散合意アルゴリズムのPaxosも実用化されていますが、こちらも気軽に使えるという感じではないと思います。

分散については、並列と同様にアプリケーション側では分散を直接意識したプログラミングは避け、プラットフォームやフレームワークが提供する機能を使用して、通常のプログラミング・モデルの範囲内で無理をせず分散の効用を得られる方式を整備することが求められます。

アプリケーション・アーキテクチャの考慮点

分散処理を行うためにはマシンをまたいだエージェント間の通信が必要です。この目的でプラットフォームが提供する以下の機能を使うことになります。

  • RPC
  • メッセージング

RPC(Remote Procedure Call)はプログラミング言語内の手続き呼び出しのセマンティクスでリモートサービスの手続きを呼び出す機能です。本稿ではWeb系で使用されるRESTもRPCの一種として扱います。基本的に、通常の手続き呼び出しと同様に使うことができますが、以下の点で注意が必要です。

  • 性能が遅い
  • 通信層、サービス側でのエラーが発生する可能性がある

特にネットワーク分断などのエラーが発生した場合は、分散処理に参加する各エージェントが独自に動作してシステム全体として誤動作するケースもあるので注意が必要です。

メッセージングは分散処理を構成するエージェント間で非同期メッセージを送受信して処理を進める方式です。RPCとは以下の点で異なります。

  • 非同期
  • キューイング
  • 同報(ブロードキャスト、マルチキャスト)が可能

基本が非同期の処理となるため、エラー時のリカバリ処理が複雑になります。

メッセージングの同報機能はサービスバスの土台となります。

サービスバスを使うことで、複数の疎結合のモジュールを組み合わえてアプリケーションを構築することが可能になります。

エージェント間の通信にメッセージングを使う場合、並列の項でも述べたとおりエージェントの実現方式としてアクターが有力です。「複数の物理事象に対する対応をまとめあげて1つの仕事を行う」場合、アクターを使うと???

また並列の後で述べたように「1つの大きな仕事を複数のエージェントで分担して行う」応用では関数がキーとなる技術です。

スケーラビリティ

クラウド・アプリケーションの重要な特性の一つはスケーラビリティ(scalability)です。

本稿ではサービスを同時に使用できるユーザー数が増えた時に、ハードウェアリソースを追加してシステムを拡張していく能力とします。また、スケーラビリティを達成する手段としては、CPUなどのハードウェア増強によるスケールアップとマシン数の追加によるスケールアウトの2種類がありますが、モデリングに影響があるスケールアウトを対象にします。

アプリケーション・アーキテクチャの考慮点

サービスの実行時に、サービスを実行するエージェント間で共有するリソースがなければサービス実行は完全に並列実行でき、マシン数の追加に対する特別な考慮も要りません。

しかし、通常のアプリケーションはデータベースに格納したデータを共用するので、データベースアクセスが最大のボトルネックになります。特に更新処理が発生するは排他制御が大きなボトルネックとなります。

スケーラビリティを高めるためには、サービスを実行するエージェント間でのデータベースの競合を以下に減らすかが論点の一つとなります。

一つのアプローチとしてはアプリケーションロジックを可能な限り関数化することで並列実行を阻害する要因を減らすことです。

また、更新処理に関してはデータベースの競合を避けることは難しいですが、冪等性を活用することでクライアントからの再実行が可能となり、楽観的手法など競合を緩和するアプローチが選択可能になります。

アベイラビリティ

アベイラビリティ(availablity)は、システムを止めずに処理を続行する能力です。マシンが1台の場合、そのマシンが落ちてしまえば処理を続行することができませんが、マシンを二重化しておけば1台のマシンが落ちても、もう一方のマシンで処理を続行することができます。

さらに、スケールアウトなどの目的で複数マシン構成になっている場合には、1台のマシンが落ちても残りのマシン群で処理を継続することができるはずです。

複数のマシンを並列動作するクラウド・アプリケーションの性質上、ハードウェア的には要件を満たしているのでできれば実現しておきたい特性の一つです。

アプリケーション・アーキテクチャの考慮点

アベイラビリティを達成するための有力な方式がクラッシュした場合の処理の再実行です。

クライアントはサービス実行を依頼するマシンが落ちた場合、別のマシンに同じサービス実行を依頼することでサービスを提供するマシンが落ちても処理を継続することができます。

このような仕組みでアベイラビリティを高めることを柔軟性(resillient)のキーワードで表すこともあります。

アプリケーション・アーキテクチャ上は以下のような考慮が必要になります。

  • 処理の再実行機能を組み込んだRPC(Remote Procedure Call)
  • メッセージング
  • 関数型
  • 冪等性

処理の再実行自体はプラットフォーム側で提供する機能を利用することになるでしょう。このため、必要なのは再実行可能なアプリケーションロジックです。この目的には関数と冪等性が有効です。

リアルタイム

リアルタイムというと、制御系システムで所定の時間内で処理が完了する性質を表すことが多いと思いますが、ここでは外部の事象に即時に反応して処理を行う機能を指すことにします。

たとえば、事前に登録した商品の在庫がある店舗近くに来た時に通知で知らせる、といった応用を想定しています。

アプリケーション・アーキテクチャの考慮点

リアルタイムを実現するためには、並列で述べた「並列に発生する物理事象に対する処理を高レスポンス実行」や分散で述べた「複数の物理事象に対する対応をまとめあげて1つの仕事を行う」を実現するメカニズムが必要です。

手続き呼び出しベースではなく、非同期性を内包したメッセージングをベースにしたアプリケーション・アーキテクチャにしていくことが重要です。

このメカニズムとして有力なのがアクターです。

UI

UIはシステムが提供するサービスを利用する接点となる機能です。

本稿でのUIはWebブラウザ上やスマートフォン上のネイティブアプリとして実装するフロント側のUIアプリケーションを指しています。ここでの検討では、UIそのものの機能はスコープ外としUI機能とサーバー側で実行されるサービスとのコミュニケーションを中心にみていきます。

アプリケーション・アーキテクチャの考慮点

UIそのものの実現方式はいろいろな議論があると思いますが、サーバー側のサービスとの通信方式は以下の2つに集約されます。

  • RPC
  • メッセージング

RPCはUIからのサービス呼び出しを同期型で行うもので、従来からあるものです。

一方メッセージングはUIからサービスまたはサービスからUIへの呼び出しを非同期で行うものです。

クラウド・アプリケーション的に考慮が必要なのはサービスからUIへの呼び出しです。この使い方では、分散処理を構成するエージェントの一つにUI機能が入るというような構成になります。

モデリングの検討

アプリケーション・アーキテクチャでの考察で以下の要因を抽出しました。これらの要因に対するモデリングの手法を確立することが重要です。

  • 関数
  • 冪等性
  • RPC
  • メッセージング
  • サービスバス
  • アクター
  • リアクティブストリーム

今後SM2020の開発を進めていくにあたって、現時点でのアイデアをまとめました。

関数

クラウド・アプリケーションは並列・分散ネイティブを指向することになるため、関数がキーテクノロジーとなります。つまりアプリケーションの分析・設計時には手続きと関数を明確に峻別し、関数化できるところを最大化するアプローチを取る必要があります。

SM2020では以下のようなアプローチが有力と考えています。

  • ルールを第一級モデル要素とする
  • データフロー図

SimpleModelではリソース、アクター、イベントなどのエンティティは特別な分類子としてステレオタイプで記述可能になっています。従前からルールもこの特別な分類子として用意していましたが、関数の集まりという観点で並列や分散に親和性の高いモデルとして積極的に活用していく予定です。

また、関数の計算過程をデータストアとの関係で記述したデータフロー図も有力です。

冪等性

スケーラビリティやアベイラビリティを最大化するためには、サービスが提供する手続きの冪等性が重要な要因になります。

サービス設計時に冪等性を意識的に取り扱っていく必要があります。

SM2020では以下のようなアプローチが有力と考えています。

  • サービスの手続きの特性として冪等性を記述可能にする
RPC

モデリング的にはRPCは通常の手続き呼び出しと同等に考えることができます。ただし、性能問題とエラーのリカバリの2つの問題は考慮に入れる必要があります。

SM2020では以下のようなアプローチが有力と考えています。

  • サービスの提供する関数や手続きの特性として
メッセージング

メッセージングは従来のUMLではシーケンス図を用いて記述する方法はありますが、コンポーネント図などでの記述方法などは今ひとつ明確化されていないと思います。

SM2020では以下のようなアプローチが有力と考えています。

  • サービスの分析・設計にメッセージング記述用の記法を追加
  • メッセージングの流れを記述するメッセージ図を整備

個人的にはUMLのシーケンス図やコラボレーション図でもメッセージングの記述に曖昧な点が残ると考えています。この問題に対応するためにメッセージ図を開発しました。

SM2020ではこのメッセージ図を整備していく予定です。

サービスバス

サービスバスを使うことで、非同期事象やイベント駆動をうまく扱えるようになります。

SM2020では以下のようなアプローチが有力と考えています。

  • イベントの整備
  • アクター

サービスバスの機能をアプリケーションで活用する場合には、イベントという抽象化を用いるのが有力です。

SM2020ではエンティティとしてイベント・エンティティを用意しているので、これとサービスバスの連携を行うような方向性を考えています。

またサービスバスからの受信するメッセージの処理にはアクターが有力だと思うので、アクターでの記述方式を検討予定です。

アクター

メッセージングやサービスバスで受信したメッセージの処理の実装にはアクターが有力です。

SM2020では以下のようなアプローチが有力と考えています。

  • アクター記述用の記法を追加
  • メッセージ図でアクターの振る舞いを記述可能にする
リアクティブストリーム

前述したように並列分散の処理を実装する場合、リアクティブストリームが使える応用ではリアクティブストリームを、そうでない場合は直接アクターを使った実装方式が有力です。

このためSM2020でもリアクティブストリーム向けのモデリングの枠組みを検討予定です。

SM2020では以下のようなアプローチが有力と考えています。

  • データフロー図
  • メッセージ図

データストアとの関係を重視したい場合はデータフロー図、パイプライン処理の側面を重視したい場合はメッセージ図という使い分けを想定しています。

まとめ

SM2020のモデル検討の前提情報としてクラウド・アプリケーションの性質から、必要と思われるモデル要素の抽出を行いました。

アイデアレベルですが、簡単な検討を行いました。

クラウド以前は並列分散処理は特殊な分野でしたが、クラウド時代に入ってコモディティ化しており、従来型のComand-Controlモデル向けのモデリング手法では対応しきれなくなっています。

とはいえ並列分散向けのモデリングの拡張を安易に入れてしまうと、モデリングの難易度が高くなってしまい実用性に問題が出てしまいます。

通常のアプリケーション開発で使用できる範囲内の難易度で、並列分散についても実用的に取り扱えるモデリング体系のバランスを取っていく必要がありそうです。

SimpleModel/関数

$
0
0

前回は以下に示すクラウド・アプリケーションの各種特性に対してアプリケーション・アーキテクチャへの影響を整理した後、SimpleModel 2020(SM2020)のメタモデル設計の方針検討を行いました。

  • 並列
  • 分散
  • スケーラビリティ
  • アベイラビリティ
  • リアルタイム
  • UI

続けてラウド・アプリケーションを構成する以下の各種要素技術に対して、SM2020のメタモデル設計の方針検討を行います。

  • 関数
  • CQRS
  • Event Sourcing
  • Eventually consistency
  • マイクロサービス
  • BigData
  • AI
  • IoT
  • DevOps

今回は、関数について検討します。

関数

プログラミング言語における「関数」は、C言語の手続き的な関数から、Haskellのような純粋関数型言語の関数まで非常に広い幅があります。

ここでは、Haskellのような純粋関数型言語やScalaのようなオブジェクト指向と関数型のハイブリット言語における紳士協定的な関数まで、数理モデルに基づく特性を意図した「関数」を関数と呼ぶことにします。

プログラミングにおける関数の長所としては以下のものを挙げることができます。

  • バグが出にくい
  • 生産性が高い
  • 並列・分散処理の記述に適している

ボクの体感でも静的型付け言語の場合、オブジェクト指向プログラミングより関数型プログラミングの方が圧倒的に生産性が高く、バグも出にくいと思います。

ただし、関数型言語には以下の短所があります。

  • 実行時性能がやや不利
  • 状態を持つプログラムの記述が困難
  • 外界との入出力の記述が大変

実行時性能がやや不利な点は近年のハードウェアの進化により、よほどのクリティカルな箇所でない限り実用上の問題にはならないでしょう。

しかし、「状態を持つプログラムの記述が困難」と「外界との入出力の記述が大変」についてはかなり大きな問題です。この問題はモナドの実用化により大きく緩和されましたが、それでもオブジェクト指向言語に比べると大きな制約であるのは確かです。

得意とするプログラミングの分野という観点からは以下のことが言えると思います。

  • 関数型はアルゴリズムの記述に向いている
  • オブジェクト指向型は外部世界の制御に向いている

また関数型は並列・分散処理に向いているという特性も重要です。

関数型は数理モデルに近い形でアルゴリズムを記述できるので、適切な並列・分散フレームワークを使用することで並列・分散処理そのものはフレームワーク内で自動的に行うことが可能になることを期待できます。一方、オブジェクト指向の場合は並列・分散処理を意識したプログラミングが必要になりがちです。

上記の点から、アプリケーションはできる限り純粋関数型で記述して、外部世界との接続する部分や状態、永続データを扱う部分をオブジェクト指向で記述するというのが、現代的なプログラミングスタイルとなります。

プログラミングの世界がこのような状況になっている以上、プログラミングよりも数理モデル寄りであるモデリングでは、オブジェクト指向と関数型のハイブリッドなアプローチが有効であることが予想されます。

このハイブリッドなアプローチについてSM2020で検討を進めていく予定です。

モデリングの検討

SM2020での関数に対するアプローチは、今の所以下の3つを考えています。

  • ルール
  • データーフロー
  • リアクティブストリーム
ルール

UMLでは直接関数を取り扱うことはできませんが、シングルトン・オブジェクトのオペレーションにステレオタイプをつけるなどの独自拡張で対応可能です。

ただ、モデリングの中で関数が単独で登場することは稀で、一連の関数群として定義することが多いでしょう。

SMでは複数の関数群をルールとして束ねて管理します。ルールは分類子にスレレオタイプruleをつけて表現します。stereotypeSM2020でもこの方式を踏襲します。

ルールは以下のような形で類型化が可能です。

  • 表構造
  • 木構造
  • プログラム
  • AI

たとえば、市町村別配送料といったルールは簡単な表構造で表現可能です。このような場合、モデル内で表データを定義して、ここからプログラムの自動生成を行うなどの手段が考えられます。

データフロー

データフローはユースケース登場後のOOADではあまり使われませんが、ビジネス・アプリケーションのモデリングには有力な技法です。

複数のデータストアに対して入出力を行うビジネス・ロジックの多くは、データフローを使ってモデル化することができます。

また、クラウド・アプリケーションでの重要な応用分野であるBigData, AI, IoTは多種多様なデータソースからのデータを収集し、このデータを複合的に分析・計算することで新しいデータを出力することになるので、データフローモデルを使ってモデリングすることの価値が高いと思われます。

数理モデルとも近い位置にあるモデルなので、適切な実行基盤を得ることができれば、プログラムの自動生成の対象にすることができるのではないかと期待しています。この実行基盤として候補となるのが次項のリアクティブストリームです。

データフローについては、メタモデル内の位置づけやドメイン・モデルなどとの連携について検討を進める予定です。

リアクティブストリーム

イベント駆動のロジックを考える場合、伝統的なオブジェクト指向のアプローチではいわゆるcall back hellとなりがちです。独立して存在するコールバックの集まりが有機的な連携を行い一つのアプリケーションロジックとして動作することになるわけですが、アプリケーションが大きくなってくると、アプリケーションロジックの見通しが悪くなり、仕様追加や変更などを行うことのコストが増大してきます。

この問題を解決する技術がリアクティブストリームです。

リアクティブストリームには以下の長所もあります。

リアクティブストリームは通しのよい関数型プログラミングで、イベント駆動アプリケーションの一連の処理をわかりやすい形で記述することができます。

また、Akka Streamsのような適切な実行基盤を使えばアプリケーションレベルで意識することなく並列・分散処理を行うことができます。

これらの性質を兼ね備えている要素技術がリアクティブストリームです。並列・分散が日常化するクラウド・アプリケーションでは重要な技術になってくると考えています。

このリアクティブ・ストリームで実現するアプリケーションロジックをモデリングの中でどのように扱っていくのかという点はSM2020の中で検討していく予定です。前回説明したとおり、以下のようなモデル図を使ったモデリングが有力と考えています。

  • データフロー図
  • メッセージ図

データストアとの関係を重視したい場合はデータフロー図、パイプライン処理の側面を重視したい場合はメッセージ図という使い分けを想定しています。

まとめ

今回は9つ挙げた要素技術の中で関数を取り上げました。

次回はCQRS、Event Sourcing、Eventually Consistencyについて検討を行う予定です。


SimpleModel/アプリケーション・アーキテクチャ

$
0
0

クラウド・アプリケーションを構成する以下の各種要素技術に対して、SM2020のメタモデル設計の方針検討を行っています。

  • 関数
  • CQRS
  • Event Sourcing
  • Eventually Consistency
  • マイクロサービス
  • BigData
  • AI
  • IoT
  • DevOps

前回は関数について検討しました。

今回は、CQRS、Event Sourcing、Eventually Consistency、マイクロサービスについて検討します。

CQRS

CQRS(Command Query Responsibility Segregation)は、ざっくりいうとコマンド投入とその結果引き起こされるデータ更新の確認処理を分離するアーキテクチャです。

従来型のCRUD(CreateReadUpdate/Delete)がデータの作成更新が同期型であるのに対して、データの作成更新が非同期で行われる点が重要です。

CQRSのアーキテクチャを取ることによって、データ作成更新のボトルネックを分散させることができ、スケーラビリティを高めることができるメリットがあります。

ただし、利用者からのデータの見え方が参照系と更新系で非対称になるためUX上の見せ方が重要になってきます。

モデリングの検討

CQRSのアーキテクチャをモデリングで扱う場合の論点として以下のものを考えています。

  • ユースケース
  • イベント駆動処理
  • サービス設計
ユースケース

CQRSでは、UX上の見せ方が重要となるため、適切なUXをできるだけ上流で設計していくことが重要です。

この目的で使用することになるモデルはユースケースです。

イベント駆動処理

CQRSアーキテクチャに則ったアプリケーションを作成する場合、ESB(Enterprise Service Bus)を使用したイベント駆動アーキテクチャが有力な選択肢です。

ESBアプリケーションを通常のオブジェクト指向で都度モデリングしてもよいのですが、かなり複雑なモデルになってしまいます。一方、CQRS向けのESBアプリケーションはかなりの定型化ができそうなので、うまい抽象モデルを見つけることができれば、シンプルなモデルとこのモデルからの自動生成を組み合わせて効率的な開発ができそうです。

SM2020では、このような目的の抽象モデルの開発を行っていきたいと考えています。

サービス設計

CQRSでは、参照系、更新系でそれぞれオペレーションが定義されることになりますが、それぞれのオペレーションがCQRSのなかでどのような役割を担っているのか、それぞれのオペレーション間の関係がどうなっているのかという点のモデリングも必要となってきます。

たとえば、CQRSのイベント駆動処理部の振る舞いを変えたときに、どのオペレーションにどのような影響がでるのかといった点をモデル上で検査できるというような用途を想定しています。

Event Sourcing

Event Sourcingは、オブジェクトの状態をイベント列を使って表現、管理していく方式です。スケーラビリティやアベイラビリティを担保する上で非常に有力なアプローチです。

イベント列から状態を計算する方式などを実際の製品開発で試してみましたが、実装が複雑になる、性能的な要件が厳しいなどの問題もあり、なかなか一筋縄ではいかない感じです。

このため、状態に関しては従来どおりリソース側の属性で管理するのが現実解ではないかと思います。

ただし、イベントの発行・記録とリソースの状態遷移を連動させるという方式設計はアプリケーションの見通しをよくし、拡張性や保守性を高めるのに寄与するので積極的に採用したいところです。

モデリングの検討

実現方式は実行プラットフォームに依存する部分が多いと考えられます。ただし、どの実行プラットフォームでも有効な抽象モデルがあると考えられるので、これを探っていきたいと考えています。

SimpleModelでは、従来よりイベントエンティティを重要なモデル要素として扱ってきました。

イベントエンティティを発展させる形でEvent Sourcingとの接点を探っていきたいと考えています。

マイクロサービス

クラウド・アプリケーションでスケーラビリティやアベイラビリティを高めるための実現方式としてマイクロサービスが注目されています。

マイクロサービスといっても単なるSOA的なものから、メッセージ中心の分散プラットフォームまで色々な形態が考えられます。

一つの典型的な方式は、複数のサービス間をスケールアウト可能なRPCを使って接続するというものです。RPC層でスケーラビリティやアベイラビリティの透過性を担保できる場合は、モデリング的には通常のRPCとして扱うことで十分と思われます。

モデリングの検討

前述したとおり、RPC層でスケーラビリティやアベイラビリティの透過性を担保できる場合は、モデリング的には通常のRPCと同様の枠組みで扱うことになると思います。

具体的にはサービスとオペレーションとしてモデリングします。ただし、ステレオタイプを使って、マイクロサービス用のRPCであることを定義していく形を想定しています。

また、マイクロサービスはRPCなどを使った通信が発生するので、オブジェクト指向だけでなくコンポーネント指向の観点から疎結合・凝集、配備の問題をモデルの上で扱っていく必要があります。

Eventually Consistency

Eventually Consistencyは、オペレーション完了時にオペレーションによって変化したデータ更新が保証されず、オペレーション完了後のどこかの時点でデータ更新が最終的には行われることを指します。

従来型のCRUDのオペレーションではオペレーション完了時に、オペレーション内で作成・更新したデータベースのレコードがデータベース内に完全に反映され永続化されることが保証されます。

一方、Eventually Consistencyの性質を持つオペレーションの場合は、オペレーション完了時にこれを保証しません。つまり、オペレーション完了直後に更新したデータを参照した場合に、古いデータを取得してしまう、ということを許容します。

アプリケーション開発的には扱いづらい性質であり、できれば避けたいところですがクラウド・アプリケーションでは以下のような理由により必要なケースが多々発生します。

  • スケーラビリティ
  • イベント駆動処理
  • バッチ処理
スケーラビリティ

クラウド・アプリケーションでは、多数のクライアントを同時接続できることが重要です。

ここでボトルネックになるのはデータベースの更新処理です。

同一レコードに対する書き込み処理が重なると、排他制御によってレスポンス性能、スループット性能のどちらも大幅に低減します。排他制御そのものは避けることはできないので、その他の部分で何らかの対策を取る必要があります。

その有力な対策の一つが Eventually Consistency です。

Eventually Consistency の性質を取ることによって、処理本体とオペレーション呼び出しの完了を分離することができます。オペレーション呼び出しは処理本体をバックグラウンドでの実行スケジュールするだけで完了できるので、レスポンス性能は大幅に更新します。

システム全体のスループット性能も、バックグランド処理をキューイングするなどして平準化したり、複数の処理を一つにまとめたりすることで向上させることが可能になります。

イベント駆動

アプリケーション・ロジックがESBを使用したイベント駆動で実現されている場合には、処理の実行が非同期となるためオペレーションの完了に同期させることが困難です。

この場合はEventually Consistencyを前提にオペレーションの性質を定義する必要があります。

バッチ処理

Webのレスポンスタイムの上限は3秒程度とするケースも多いと思いますが、アクションの実行時間がこれを超える場合にはアクションをバックグラウンドで実行することになります。この場合、当然ながらEventually Consistencyを前提としたオペレーションになります。

モデリングの検討

スケーラビリティ、イベント駆動、バッチ処理の観点からEventually Consistencyについて見てきました。

共通しているのは、メインの処理はバックグラウンドで行われ、オペレーションの返却値では処理の結果を返すことができないということです。

また、処理はバックグラウンド処理で行われますが、必ずしも成功するとは限りません。

上記の点からアプリケーションの設計においては以下の2つの機能が必要になります。

  • バックグラウンド処理の結果確認
  • バックグラウンド処理リカバリ

いずれも、通常のアプリケーション処理として都度モデリングを行ってもよいのですが、かなりの定型化が可能という予感もあります。

実行時のクラウドプラットフォーム側のフレームワーク次第という面も大きいので、フレームワークとの連携を想定した上でモデリングの定型化を図っていきたいと考えています。

ユースケース

ユースケース・モデルの段階で以下のようなEventually Consistencyの影響を取り込んでいく必要があります。

  • リカバリ方式
  • オペレーションの特性情報

SM2020のユースケースモデル設計で上記の性質の定義方法を検討する予定です。

オペレーションの特性情報

サービスのオペレーションによる更新処理に対してステレオタイプなどを用いてEventually Consistencyであることの明示することが有効と思われます。

SM2020のユースケースモデル設計で上記の性質の定義方法を検討する予定です。

モデリングの検討

CQRS、Event Sourcing、Eventually Consistency、マイクロサービスといったクラウド・アプリケーションのアプリケーション・アーキテクチャの整理とモデリングでの対応について検討しました。

検討の結果、以下の項目がSM2020で検討していく候補として抽出できました。

ユースケース

以下の場合にユースケース段階で考慮が必要であることが分かりました。

CQRS
利用者のUX
Eventually Consistency
データが反映されるタイミング

上記の項目をユースケースモデルに取り込んでいく予定です。

イベント・エンティティ

CQRSでのESB利用やEvent Sourcingでイベントが重要なモデル要素になっています。

SimpleModelでは元々イベント・エンティティを軸に静的モデルと動的モデルを連携させるモデル体系になっています。

このイベント・エンティティを拡張してESBやEvent sourcingでの利用をアシストする方法について検討したいと思います。

ESB

CQRSやEventually Consistencyなどの実現方式としてESBが有力であることが分かりました。

ESBアプリケーションを都度スクラッチでモデリングしてもよいですが、可能であればCQRSやEventually Consistencyの観点からのESBの使い方にフォーカスした抽象モデルを定義し、この抽象モデルを使用してモデリングと実装を連携させていくというアプローチを考えていきたいと思います。

オペレーション

オペレーションの特性情報として以下の項目が候補になります。

  • CQRS上の特性
  • Eventually Consistency上の特性
  • マイクロサービス上の特性
コンポーネント指向

ESBやマイクロサービスを用いたアプリケーションでは、疎結合/凝集、配備の問題が重要になってくるので、オブジェクト指向に加えてコンポーネント指向でのモデリングも必要になってきます。

SM2020ではESB、マイクロサービスを視野に入れたコンポーネント指向のモデリングの枠組みを整備したいと考えています。

まとめ

今回は9つ挙げた要素技術の中でCQRS、Event Sourcing、Eventually Consistency、マイクロサービスを取り上げました。

次回はBigData, AI, IoT, DevOpsについて検討を行う予定です。

SimpleModel/テクノロジー

$
0
0

クラウド・アプリケーションを構成する以下の各種要素技術に対して、SM2020のメタモデル設計の方針検討を行っています。

  • 関数
  • CQRS
  • Event Sourcing
  • Eventually Consistency
  • マイクロサービス
  • BigData
  • AI
  • IoT
  • DevOps

前回はCQRS、Event Sourcing、Eventually Consistency、マイクロサービスについて検討しました。

今回は、BigData、AI、IoT、DevOpsについて検討します。また、検討項目にDXを追加することにしました。

BigData

アプリケーション実行中に得られるデータを分析して、有益なデータを抽出し、アプリケーションにフィードバックして活用することが普通になってきました。アプリケーションの基本機能として、実行結果データの分析が必要となってきているといえます。

BigDataを実現する仕組みとしては、以下のような構成を取ることになるでしょう。

  • アプリケーションの実行結果の記録機構
  • アプリケーション実行結果データの収集・保管機構
  • 保管データ整理機構
  • 整理データの分析機構
  • 分析データのアプリケーション取込み機構

アプリケーションの実行結果の記録機構はログまたはデータベースに記録することになります。

アプリケーションでは採取するログデータと記録用のデータベースのエンティティが設計のポイントです。

アプリケーション実行結果データ収集・保管機構はdata lakeやdata warehouseといったサブシステムを中心としたメカニズムになります。

アプリケーションではdata lakeやdata warehouseの基盤の上でデータフォーマットの調整などが主な仕事となるでしょう。

保管データ整理機構はdata lakeやdata warehouse上に格納した生データから、分析に適した正規化を施したデータを作成します。

アプリケーションでは分析に適した正規化データの設計が必要になります。

整理データの分析機構はHadoopやSparkといった大規模演算基盤上に構築したバッチやイベントハンドラとして実現することになるでしょう。

アプリケーションでは、アプリケーションのユースケースに沿った活用方法で直接使用できるデータに変換する処理を行うことになります。

分析データのアプリケーション取込み機構は整理データから作成したデータをアプリケーション側に取り込む処理です。

アプリケーションではデータを取り込むための受け皿としてデータベースのエンティティなどを用意する必要があります。

モデリングの検討

アプリケーションの実行結果の記録機構に対して、アプリケーションではログデータのフォーマットと記録用のデータベースエンティティの設計が必要になります。

アプリケーションのモデリングの観点ではログのフォーマットはデータの最終的な利用方法から逆算して必要十分な情報が取得できるように設計することになります。このため、ユースケースモデルからの一連の連鎖でログのフォーマットまでモデルの連鎖を追跡できると理想的です。

データベースのエンティティという観点では、SM2008からeventエンティティを用意しています。eventエンティティによってアプリケーション上重要な出来事はデータベース上に記録されるので、ここからBigDataに必要な情報を収集することができます。

アプリケーション実行結果データの収集・保管機構から保管データ整理機構にかけてはデータ変換処理になります。

整理データの分析機構に対してもデータ変換処理という観点で考えればよいでしょう。

分析データのアプリケーション取込み機構に対しては、SM2008からsummaryエンティティを用意しています。整理データの分析機構で生成したデータをsummaryエンティティに書き込むことで、アプリケーションで利用することができます。

AI

AIは大きく分けて、従来型の知識ベースや推論エンジンによるAI(推論型AI)と、最近主流となっている学習型AIの2種類があります。

推論型AIに対してアプリケーションでの利用の観点では、外部のサブシステムとして用意したAIエンジンを手続き呼び出しで使用するという形になるでしょう。

一方、学習型AIの場合はアプリケーションの実行結果を使用して学習を行う必要がある点が異なります。このため、アプリケーションとは密結合のアプローチとなります。

学習型AIでは実行結果に対して何らかの計算を行い、計算結果をフィードバックするという処理になりますが、これは前述のBigDataと基本的には同じものです。BigDataの場合はSQL的な集計処理になりますが、学習型AIの場合は深層学習などの複雑な計算になる点が異なります。

モデリングの検討

SM2008ではAIシステムの設計はスコープ外で、外部のAIシステムを利用するというアプローチを取っています。SM2020でも基本的なプローチは同じです。

ただし、推論型AIと学習型AIではモデリングのアプローチもかなり異なりそうです。それぞれについて検討します。

推論型AI

推論型AIの実現方式は外部のAIシステムをRPCなどで利用するという形になります。アプリケーションのモデリングの観点ではこれをアプリケーション内のモデルでどのように表現するのかという選択になります。

シンプルなのはAIサブシステムをサービスとしてモデル化しオペレーション呼び出しで利用する方法です。

ドメイン知識などを保持したエンティティとして実現したい場合は、SM2008から用意しているruleエンティティを使用します。

学習型AI

学習型AIの場合、エンジンそのものは推論型AIと同様に外部システムとして利用する形を想定していますが、アプリケーションの実行結果のデータを使って学習を行う点が大きな相違点です。

学習データの取り込み方式は基本的に前述のBigDataと同じものになります。このためBigDataで議論したアプローチを取ることになります。

学習型AIをアプリケーションから利用する方法ですが、以下の3つが考えられます。

  • サービスへのオペレーション呼び出し
  • ruleエンティティ
  • summaryエンティティ

サービスへのオペレーション呼び出しとruleエンティティは推論型AIと同じアプローチです。

summaryエンティティはBigDataと同じアプローチです。

IoT

ビジネス・アプリケーションあってもIoTを扱うケースが増えてくるのは確実です。アプリケーションでIoTを使う場合、IoTの基盤機能そのものを自ら実現するのではなく、外部のIoT基盤を外部サービスとして使用する方式を想定することにします。

IoT基盤とアプリケーションの接続方式として以下のものが有力です。

  • RPCによるオペレーション呼び出し
  • RPCによるコールバック
  • サービス・バスによるイベント駆動
  • リアクティブ・ストリームによるイベント駆動

RPCによるオペレーション呼び出しはIoT基盤の提供するAPIのオペレーションを、アプリケーションから直接呼び出す方式です。

こちらは、アプリケーションからIoT基盤側を呼び出す方式ですが、IoTの応用では逆にいイベント駆動であるIoT基盤からアプリケーションを呼び出す方式が主となります。

RPCによるコールバックはIoT基盤にコールバックを登録し、コールバックでイベント駆動処理を行う方式です。

サービス・バスによるイベント駆動は汎用のサービス・バスにコールバックを登録し、コールバックでイベント駆動処理を行う方式です。IoT基盤で発生したIoTイベントをより汎用的な形に変換してサービス・バスに流し、サービス・バスに登録されているアプリケーションのイベント・ハンドラを起動します。より汎用的なサービス・バスのイベントを使用する点が異なります。

RPCによるコールバックとサービス・バスによるイベント駆動はいずれもイベントハンドラによるコールバックによる実現方式です。このため、アプリケーションの規模が大きくなるとコールバック地獄と呼ばれるアンチパターンに陥る可能性が高まります。

この問題の解決方法として有力なのがリアクティブ・ストリームです。

関数の回でも取り上げましたが、イベント駆動型のアプリケーションはリアクティブ・ストリームで記述するのが関数型時代の定石といえます。

モデリングの検討

IoTアプリケーションのモデリングはモデル駆動アプリケーションのモデリングという側面が大きいといえます。

イベント駆動というアプリケーションの特性からはコールバック処理がアプリケーションの軸となりますが、いわゆるコールバック地獄とよばれるアンチパターンになりがちです。

コールバック地獄を起こさずイベント駆動のアプリケーション・ロジックを記述する手法として期待しているのがリアクティブ・ストリームです。

リアクティブ・ストリームは一種のパイプラインなので、パイプラインとして抽象化することでモデル化が可能と思われます。ただ、伝統的に使用されているデータフローより動的な側面が大きいと思うので別のメタモデル要素を導入するのが妥当と考えています。SM2020ではこのあたりの検討を行う予定です。

IoTアプリケーションの特性からはイベントの階層化の設計が重要です。SM2020では以下の階層で対応するアプローチを検討中です。

  • IoTイベント
  • 生イベント
  • ビジネス・イベント

    イベント駆動で使用するイベントはeventエンティティと連携するのがSM2008のアプローチでした。SM2020でも引き続きこのアプローチを軸に考えていますが、IoT対応で発生するイベント階層との対応関係について整理していく予定です。

    DevOps

    DevOpsはソフトウエア開発と開発したソフトウェアの配備や運用などを統合した考え方で、運用配備を含めたソフトウェア開発の自動化と見える化を目指しています。

    2000年代初頭の段階では、なかなかそこまでは実現のスコープに入ってきていませんでした。

    UMLでも配備モデルを記述することは可能でしたが、当時はChefなどのDevOpsのライフサイクル全体をカバーした配備・運用ツールなどは存在せず、配備モデルも青写真レベルに留まっていることが一般的でした。

    現在ではツール類を始めとした環境が整っているので、本格的なモデル駆動開発への組み込みも可能と思われます。

    モデリングの検討

    アプリケーション・モデリングの観点では以下の点が重要と考えています。

    • 配備モデルの定義と適用
    • 運用性を高めるためのモデル要素
    • テスト性を高めるためのモデル要素

    モデル駆動開発にDevOpsを適用することを考えると、作成したアプリケーション・モデルを直接、配備や運用の記述データとして使用できると理想的です。この中心となるのが配備モデルです。配備を考えていく上では、モデルの物理的な側面を記述するコンポーネントやモジュールといったモデル要素が重要になってきます。

    SM2008では配備モデルはスコープ外でしたが、SM2020ではDevOpsの観点で配備モデルの設計を行っていきたいと考えています。

    運用性を高めるためのモデル要素としては、エンティティを監視するための属性の追加といったものが考えられます。JMX(Java Management Extension)といったプラットフォームのモニタリングツールと連動させることによって運用性が高まります。

    このような監視のための属性を抽出するためには、運用フェーズのユースケース分析なども必要になってきます。

    テスト性を高めるためのモデル要素としては、エンティティの内部状態を見える化して検証可能にするための属性追加といったものが考えられます。

    運用性やテスト性を高めるためのモデリング上のアプローチは他にも色々あると思うので、SM2020の中に取り込んできたいと考えています。

    DX

    DX(Digital Transformation)は色々な切り口があると思いますが、ここでは企業システムを最適化したビジネス・モデル、業務プロセスをサイバー空間上で新規構築すること、とします。

    基幹システムの入出力の部分を紙ベースからIT化するというものであれば、OOAD(Object-Oriented Analysis and Design)の出番は限定的ですが、ITベースのビジネス・モデル、業務プロセスを一から設計するとなると、超上流からOOADによるモデリングが必要になってきます。

    ビジネス・モデリングを受けてのアプリケーション開発では、通常のOOADによるモデリングになります。

    IoTと同様にDXの場合も、DX基盤といったものを軸にアプリケーション構築を行うようになるケースが多いと考えられるので、モデリング段階では抽象度の高いモデルで設計しDX基盤向けのコードを自動生成するというようなアプローチが有効と思われます。

    モデリングの検討

    SM2020はビジネス・モデリングはスコープ外ですが、ビジネス・モデリングで作成したモデルをモデル駆動開発用に連携させていくことでモデル駆動開発に組み込むアプローチを取っています。ステレオタイプといった拡張機構を使用して超上流のモデルをSM2020内に埋め込んだりリンクを張ったりといった連携を想定しています。

    DXアプリケーションのモデリングについては、IoT基盤との連携を軸に検討していく予定です。鍵となるモデルはワークフローと状態機械と考えています。

    まとめ

    今回は、BigData、AI、IoT、DevOps、DXについて検討しました。

    前々回、前回と合わせて以下の項目について検討しました。

    • 関数
    • CQRS
    • Event Sourcing
    • Eventually Consistency
    • マイクロサービス
    • BigData
    • AI
    • IoT
    • DevOps
    • DX

    全体としてイベント駆動アプリケーションのモデリングがさらに重要になってきていると感じました。

    このため状態機械の価値がさらに高まりました。状態機械は従来は現場の開発ではあまり活用されてきていないと思いますが、モデル駆動開発の助けを借りて本格的に活用していく必然性が増してきたかもしれません。

    また、アプリケーション全体の振る舞いを統合する概念が重要になってくると思います。一つのアプローチはユースケースをハブにして帰納的に束ねていくことでしょう。ユースケースの価値もさらに高まってきたと思います。

    特に重要と感じたのが以下の3つのフロー系のモデルです。

    • データフロー
    • ワークフロー
    • リアクティブストリーム

    SM2020ではこれらのモデルについてモデルのセマンティクスと記述方法、使い分けの指針などの整備に力をいれていきたいと思います。

    SimpleModeling 2021

    $
    0
    0

    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とモデル駆動開発を構成する各種ツールの開発を粛々と進めてきましたが、それなりに動くところまで来ることができました。

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

    Kaleidox/データ型

    $
    0
    0

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

    データ型の標準化

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

    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単位

    SimpleModeling/Component

    $
    0
    0

    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で扱う方法について考えてみます。

    Viewing all 150 articles
    Browse latest View live