Buddyではアプリの構成要素のうちBuddy側で用意しているもの(例えばスクリーンモジュールなど)を総称してフレームワークと呼んでいます。フレームワークにユーザーが作成したデータベースやスクリーンなどの設計情報が組み合わされて、実際に動作するアプリとなります。2023年6月のアップデートで、フレームワークの新しいバージョンをリリースしました。従来のフレームワークをフレームワーク1、新しいフレームワークをフレームワーク2と呼んでいます。
フレームワーク2はフレームワーク1との互換性は考慮せずに一から設計し直して、より使いやすくなるようにしました。その基本的な考え方は、従来のフレームワーク1ではどうしても一定量のJavascriptのスクリプトを書く必要があった機能について、その必要をなくしたり、簡潔でわかりやすい書き方にすることです。具体的には次のような特徴があります。
・スクリーンスクリプトの書き方がシンプルになりました。Buddyが提供する様々な機能は全てbuddyというオブジェクトから利用できます。
・データベース操作などの非同期処理が最近の主流であるプロミスを使用した方式になり、簡潔でわかりやすい書き方ができるようになりました。
・データベースとモジュールの結びつきを扱うDataLinkerという仕組みが導入され、非常に簡潔に書けるようになりました。
・スクリーンテンプレートが一新され、作成後のスクリーンにモジュールの追加・削除を行った際にも、スクリプトはできるだけそのままで動作するようになりました。
・新しいスクリーンテンプレート「一覧」「閲覧・入力」が追加され、よりシンプルな画面構成が可能となりました。これを利用したアプリをExcelデータから簡単な操作で作成できるようになりました。
・スクリーンモジュールはすべてフレームワーク2用に一新されました。使用頻度の高い基本的なモジュールのみが標準モジュールとなり、それ以外はプラグインとして必要な時にリポジトリから取り込んで使用するようになりました。今後、特別な機能を持ったモジュールもプラグインとして提供し、作成できるアプリの幅を広げていく予定です。
詳しくは開発ガイドやプログラミングガイドなどのマニュアルに記載していますが、この記事ではプロミスによる非同期処理、DataLinker、プラグインについて簡単に紹介します。
○プロミスによる非同期処理
プロミスは非同期処理を扱うための比較的新しい仕組みです。従来はJavascriptでの非同期処理はコールバック方式で、フレームワーク1でもコールバック方式でした。フレームワーク2ではプロミス方式に変更されています。
例えばフレームワーク1でデータベーステーブルtable1からID1のレコードを読み出してnameカラムの値を表示するには次のようにします。(エラー処理については省略しています。)
const table = this.tables["table1"]; table.readData({where: {ID: 1}}, (function(error, data) { this.items.TEXTBOX1.setvalue(data[0].name); }).bind(this));
フレームワーク2では次のようになります。
const table = buddy.app.findModel("table1"); const reulst = await table.select().where({ID: 1}); buddyscreen.items.TEXTBOX1.value = result.rows[0].name;
フレームワーク1ではreadData()のコールバック関数の中で、読み出した結果を得て、それを表示する処理をしています。それに対してフレームワーク2ではselect()はプロミスを返し、プロミスの処理終了を待ってその結果を得るキーワード「await」を利用することで、「result = await …」と結果を得ています。
上記の例のように単独の処理であればどちらの書き方でも大差ないように見えますが、いくつかの非同期処理を順次行いたい場合には大きな違いがあります。例えばtable1のnameカラムに「サンプルA」「サンプルB」「サンプルC」という値をこの順に入れるようにレコード追加したいとします。フレームワーク1では次のようになります。
const table = this.tables["table1"]; table.insertRecord({data: {name: "サンプルA"}}, (function(error, result){ table.insertRecord({data: {name: "サンプルB"}}, (function(error, result){ table.insertRecord({data: {name: "サンプルC"}}, (function(error, result){ }).bind(this)); }).bind(this)); }).bind(this));
コールバック関数の中で次のinsertRecord()を実行する必要があるので、このようにコールバックの入れ子になります。省略しているエラー処理もおこなうようにすると、とても複雑なスクリプトになります。
フレームワーク2では次のようになります。
const table = buddy.app.findModel("table1"); await table.insert({name: "サンプルA"}); await table.insert({name: "サンプルB"}); await table.insert({name: "サンプルC"});
awaitで処理終了まで待つことができるので、上記のように単純に書き並べることで順次処理ができ、非常にわかりやすいスクリプトになります。
○DataLinker
DataLinkerはスクリーンモジュールとデータベースとの仲立ちをしてくれる仕組みです。スクリーンに配置したテキストボックスなどのモジュールの「データリンク」という属性で、そのモジュールとどのデターベーステーブルやビューとそのカラムが対応するかを指定しておきます。すると、そのテキストボックスなどの値をデータベースから読み出した値にセットしたり、逆に入力された値をデータベースに保存したりする処理は、DataLinkerが面倒を見てくれます。
例えばデータベーステーブルtable1のID1のレコードを読み出して、その値をスクリーンモジュールの「データリンク」でtable1が指定されているものにセットするには、次のようにします。
const tableName = "table1"; const table = buddy.app.findModel(tableName); const data = await table.select().where({ID: 1}); const linker = new buddy.lib.DataLinker(buddy, tableName); linker.set(data);
逆にテキストボックスなどの入力用のスクリーンモジュールに入力された値を、データベーステーブルにレコードとして追加するには、次のようにします。
const tableName = "table1"; const linker = new buddy.lib.DataLinker(buddy, tableName); await linker.insert();
「linker.insert()」だけで、スクリーンモジュールからの値の収集と、それをデータベーステーブルにinsert()する処理をまとめて行ってくれます。
○プラグイン
フレームワーク1では、テキストボックスやボタンなどの基本的なものから、地図やカレンダーなどの複合的なものまで、様々なスクリーンモジュールが用意されています。Buddyの応用範囲も広がるにつれて、Buddyのアップデートによって少しずつ新たなモジュールが加わったり、モジュールの機能が強化されたりしてきました。これにより、次第にモジュールが肥大化し、アプリが重くなる要因となる恐れが出てきました。
そこでフレームワーク2では、標準で用意するモジュールは基本的なものに絞り、使用頻度が低いと思われるものはプラグインとして必要なときにアプリに取り込む仕組みとしました。フレームワーク1にあったモジュールがプラグインに移ったものもありますが、新しく作られたプラグインモジュールもあります。今後さらに充実させて、Buddyでのアプリ制作の幅を広げていく予定です。
以上、かいつまんでフレームワーク2をご紹介しました。現時点ではベータバージョンであり、未実装の機能もありますが、今後完成度を高めていきます。ぜひ試していただければと思います。
(2023/6/14 中島)