まっつんです。今回は Web VelocityRuby on Rails (以下、Rails) を比較しながら、 ポテトバーガー注文アプリケーション を実装していきます。

MATSUFUJI Hideharu

ポテトバーガー注文アプリケーションとは?

最初に今回実装する ポテトバーガー注文アプリケーション について簡単に説明します。

ポテトバーガー注文アプリケーション は PHP のアプリケーションフレームワーク Piece Framework のクィックスタートドキュメント「Piece Framework で作る対話的なアプリケーション」で題材となっている、対話的にポテトバーガーを注文するアプリケーションで、メインメニューの選択、サイドメニューの選択、確認、完了の 4 ページで構成されています。

ページの遷移やデータベースアクセスといった Web アプリケーションで必ず出てくる処理が盛り込まれているため、このアプリケーションは評価対象のフレームワークの特徴を掴むためにもってこいの題材といえるでしょう。

リポジトリとアプリケーションの作成

Web Velocity では、最初にアプリケーションを格納するためのリポジトリを作成します。リポジトリの保存先には一般的な RDBMS を使うことができます。今回は PostgreSQL を使うことにし、リポジトリ用とアプリケーション用の 2 つのデータベースを作成します。データベースの情報は以下のとおりです。

リポジトリ用データベース
データベースrepos
ユーザrepos
パスワードrepos
アプリケーション用データベース
データベースpiece_conversation
ユーザpiece
パスワードpiece
ノート: Web Velocity では、PostgreSQL 以外にも OracleMySQL などさまざまな RDBMS を利用することができます。

それではリポジトリを作成しましょう。[New] -> [Repositry] をクリックすると、Add Repository ダイアログが表示されるので、以下のように入力します。

NameRepos
PlatformPostgreSQL
Addresslocalhost
Port5432
Databaserepos
Schemapublic
Usernamerepos
Passwordrepos

[Repositories] -> [Repos] をクリックし、作成したリポジトリを選択します。続いてアプリケーションを作成しましょう。[New] -> [Application] をクリックすると、Create Application ダイアログが表示されるので、以下のように入力します。

NameConversation
Generate - Schemaオン

ドメインモデルとテーブルの作成

Web Velocity では、Rails と同様にデータへアクセスするためのアーキテクチャとして Active Record が採用されています。Active Record の性質上ドメインモデルとテーブルの構造は深く関係します。そのため Web Velocity では、ドメインモデルの作成時にテーブル生成メソッドも合わせて作成できるようになっています。

それでは Order ドメインモデルを作成しましょう。[New] -> [New Model] をクリックすると、Create Persistent Model ダイアログが表示されるので、orders テーブルのジェネレータのみ生成するようにします。

Nameorder
Database Generation - #tableForOrderオン
上記以外オフ
web-velocity-2-create-persistent-model.png

次にデータベースの接続情報を設定するため、[Database] をクリックし、以下のように入力します。

PlatformPostgreSQL
Addresslocalhost
Port5432
Databasepiece_conversation
Schemapublic
Usernamepiece
Passwordpiece

入力が完了したら、[Test Login] をクリックし、データベースに接続できることを確認します。

続いて orders テーブルを生成するためのコードを追加します。[Go to Schema1] をクリックし、Source Code をクリックします。テーブル生成メソッドとして tableForORDERS が定義されているので、それを以下のように変更します。

Schema1 tables - tableForORDERS メソッド
tableForORDERS: aTable

    (aTable createFieldNamed: 'id' type: platform serial) bePrimaryKey.
    (aTable createFieldNamed: 'main' type: platform integer) beNullable: false.
    (aTable createFieldNamed: 'side' type: platform integer) beNullable: false.
    (aTable createFieldNamed: 'created_at' type: platform timestamp) beNullable: false.
    (aTable createFieldNamed: 'updated_at' type: platform timestamp) beNullable: false.

これで orders テーブルを生成する準備が整いました。[Mappings] をクリックし、[Recreate all tables] をクリックすると、確認ダイアログが表示され、orders テーブルが生成されます。

web-velocity-2-order-table.png

このように Web Velocity はテーブルを定義する機能を提供しています。これは Rails のマイグレーションに似ていますが、Web Velocity はテーブルの変更点のみを定義する方法を提供しておらず、毎回テーブルを再作成する必要がある点が異なっています。

それでは、テーブルのフィールドとドメインモデルのプロパティのマッピングを定義しましょう。[Classes] -> [Order] をクリックし、[Mappings] をクリックします。Add instance variable named:xxxx リンクをクリックするとマッピングを定義することができます。今回は、すべてのフィールドに対してそれぞれ対応するプロパティをマッピングし、それらのアクセサメソッドも作成します。

web-velocity-2-mappings.png

ユーザインターフェイスの作成

最後にユーザインターフェイスを作成します。[New] -> [New Component] をクリックすると、Create Web Component ダイアログが表示されるので、以下のように入力します。

NameOrderUI
Register as applicationオン
Configure for Glorpオン
Use tamplateオフ

Glorp は Active Record ベースのデータアクセスフレームワークです。当初、筆者は Configure for Glorpオフ にしていたことが原因で注文データを orders テーブルに登録することができず、原因究明に半日を費やすことになりました。

次にインスタンス変数を定義します。[Variables] をクリックし、Instance Variables の横の [Add Variable...] をクリックします。

NameDescriptionCreate accessors
order<Order> domain model.オフ
currentState<String> current state.オフ
message<String> validation result.オフ

次に、デフォルトのエントリポイントを削除し、新たに別のエントリポイントを登録します。[Component] をクリックし、既存の Conversation/OrderUI の [Remove] をクリックして削除します。そして [Add Entry Point...] をクリックし、Conversation/order エントリポイントを追加します。

web-velocity-2-entry-point.png

それでは [Source Code] をクリックし、コードを追加していきましょう。まず、初期化コードの追加を行います。

OrderUI - initialize-release initialize メソッド
initialize

    super initialize.

    order := Order new bePersistent.
    currentState := 'MainMenu'.
    message := ''.

次に HTML 表示コードを追加します。最初に renderContentOn メソッドが呼び出されるので、このメソッドで各ページのステートに応じたメソッドを呼び出すようにしています。

OrderUI - rendering renderContentOn メソッド
renderContentOn: html

    currentState = 'MainMenu' ifTrue: [
        self renderMainMenu: html.
    ].
    currentState = 'SideMenu' ifTrue: [
        self renderSideMenu: html.
    ].
    currentState = 'Confirmation' ifTrue: [
        self renderConfirmation: html.
    ].
    currentState = 'Finish' ifTrue: [
        self renderFinish: html.
    ].
OrderUI - rendering renderMainMenu メソッド
renderMainMenu: html

    html heading
        level: 3;
        with: 'メインメニューは何になさいますか?'.
    html break.
    html text: message.
    html break.
    html anchor
        callback: [ self validateForMainMenu: 1 ];
        with: 'ジャーマンポテトバーガー (650円)'.
    html break.
    html anchor
        callback: [ self validateForMainMenu: 2 ];
        with: 'ポテトコロッケバーガー (600円)'.
    html break.
    html anchor
        callback: [ self validateForMainMenu: 3 ];
        with: '肉じゃがバーガー (700円)'.
    html break.
OrderUI - rendering renderSideMenu メソッド
renderSideMenu: html

    html heading
        level: 3;
        with: 'サイドメニューは何になさいますか?'.
    html break.
    html text: message.
    html break.
    html anchor
        callback: [ self validateForSideMenu: 1 ];
        with: 'フライドポテト'.
    html break.
    html anchor
        callback: [ self validateForSideMenu: 2 ];
        with: 'ポテトサラダ'.
    html break.
    html anchor
        callback: [ self validateForSideMenu: 3 ];
        with: 'スイートポテト'.
    html break.
OrderUI - rendering renderConfirmation メソッド
renderConfirmation: html

    |mainMenu sideMenu price|

    mainMenu := #('ジャーマンポテトバーガー'
                  'ポテトコロッケバーガー'
                  '肉じゃがバーガー'
                  ) at: order main.
    sideMenu := #('フライドポテト'
                  'ポテトサラダ'
                  'スイートポテト'
                  ) at: order side.
    price := #('650円'
               '600円'
               '700円'
               ) at: order main.

    html heading
        level: 3;
        with: '注文内容は以上で宜しいですか?'.
    html break.
    html text: 'メインメニュー:', mainMenu.
    html break.
    html text: 'サイドメニュー:', sideMenu.
    html break.
    html text: '小計:', price.
    html break.
    html anchor
        callback: [ self register ];
        with: 'OK'.
    html space.
    html anchor
        callback: [ currentState := 'MainMenu' ];
        with: '選び直す'.
OrderUI - rendering renderFinish メソッド
renderFinish: html

    html heading
        level: 3;
        with: 'ご注文ありがとうございました。'.
    html break.

最後にバリデーションとデータベースアクセスのためのメソッドをそれぞれ追加します。

OrderUI - private validateForMainMenu メソッド
validateForMainMenu: mainMenu

    message := ''.
    (mainMenu >= 1) & (mainMenu <= 3) ifTrue: [
        order main: mainMenu.
        currentState := 'SideMenu'.
    ] ifFalse: [
        message := '正しいメインメニューを選択してください。'.
        currentState := 'MainMenu'.
    ]
OrderUI - private validateForSideMenu メソッド
validateForSideMenu: sideMenu

    message := ''.
    (sideMenu >= 1) & (sideMenu <= 3) ifTrue: [
        order side: sideMenu.
        currentState := 'Confirmation'.
    ] ifFalse: [
        message := '正しいサイドメニューを選択してください。'.
        currentState := 'SideMenu'.
    ]
OrderUI - private register メソッド
register

    order createdAt: Timestamp now.
    order updatedAt: Timestamp now.
    order commitUnitOfWork.

    currentState := 'Finish'.

Web Velocity では、データを保存するアーキテクチャとして Unit of Work が採用されています。ステートフルを特徴とする Seaside アプリケーションでは、その利点を生かすために、ビジネストランザクションが複数のリクエストにまたがるような実装を行うことも多いのではないかと思います。このような場合に並行性の問題を解決する Unit of Work は非常に有効なアーキテクチャであると言えます。

ノート: Unit of Work を使用せずにデータを保存することもできます。

動作確認

以上でアプリケーションの実装は完了です。[Browse] -> [/Conversation/order] をクリックして、動作確認を行いましょう。

web-velocity-2-main-menu.png web-velocity-2-side-menu.png web-velocity-2-confirmation.png web-velocity-2-finish.png

問題なく動作することが確認できました。

おわりに

Web Velocity は、SeasideRails それぞれの特徴と利点を上手く組み合わせているという印象を受けました。また、コードリポジトリがデータベースであることや、ブラウザベースの開発環境が提供されていることなど、言語ワークベンチ や IDE の観点からも興味深いフレームワークであると言えます。

しかし残念ながら、現時点では完成度が高いとは言えません。開発環境では親クラスのコードの検索ができないことをはじめ、苦労することが数多くありました。また、スタティックメソッドに不正なコードがあるとアプリケーションをロードすることができないため、それを修正することができず、一つ前のバージョンに戻さなければなりませんでした。

このようにいくつかの問題はあるものの、まだリリースされたばかりという点もあり今後が楽しみなフレームワークです。

使用したソフトウェアのバージョン

WebVelocity Lite1.0

参考文献

トラックバック(0)
  • このブログ記事のトラックバックURL:
コメント