MVC (Model/View/Controller)を使ってIBM i アプリケーションを近代化する
アプリケーションの近代化という言い方には、さまざまな定義があります。おそらく、異なるインターフェースをサポートするために、アプリケーションを機能強化するプロセスを近代化するという言い方をする人もいれば、データ・アクセスを、さらに多くの対象者と幅広いデバイス群に拡大するという目標を持ち、新しいアプリケーションを再度既存のデータに対して作成するプロセスとして定義する人もいます。私はアプリケーションの近代化を、幅広いデバイス群と新しいテクノロジーに対応し、既存のアプリケーションを引き続き機能させるソリューションのフレームワークを、開発者が実装するプロセスとして定義しています。原則的に、そのフレームワークは既存のビジネス・ロジックと新しいテクノロジーを使用して、豊富な機能とコンテンツを提示するインターフェースを実現します。
私のアプリケーションの近代化の定義では、次のようにいくつか目標を設定しています。
- 既存のアプリケーションは変更せず、機能する状態のままにしておくこと。
- 既存のデータ構造およびアプリケーションの新しいインターフェースを実装すること。
- 新しいインターフェースにより追加されたプログラミング言語およびアプリケーション・サービスにアクセスでき、それらが引き続き追加のデバイスにアクセスできるようにする。
IBMのLab-Based Services and Training(LBST)アプリケーション近代化チームは、データ抽象化技法および PHP スクリプティングを実装することで容易に IBM i アプリケーションの近代化を行う、一連のパターンおよび標準を開発しました。これらの技法は、より豊かなカスタマー・エクスペリエンスを目指してアプリケーションとデータを Web にもたらし、そのデータに基づいて動作する追加機能を含めることができます。またZend Server 6は、モバイル・デバイスで新しいインターフェースを使用できるよう、モバイル・デバイスに対応しています。この記事で紹介した方法論は LBST チームによる仕事の結果です。特に、Jeff Minette、Brad Bentley、Rich Diedrich、Jim Diephuisには同じ考えを共有させてもらい感謝しています。
LBSTチームのアプローチでは、REST、SOAP、WSDL、XMLService、IBM i Integrated Web Services Server などのサービスを使用していません。それらはサービス指向アーキテクチャー(SOA)を対象としています。これはアプリケーションを呼び出し可能サービスに転換し、それらのサービスとその使用(消費)方法の情報を公開するケースが多いです。それよりむしろこのアプローチは、DB2ストアード・プロシージャー、データベース・ビューなどのプログラミングおよびデータベース技法を使用して、呼び出し可能サービスをRPGアプリケーション周辺にラップします。
この記事で重点的に説明するアプローチは、関連する次の3つの方法論を活用しています。
- 既存のアプリケーションのビジネス・ロジックはSQLビューの形で抽出されており、ストアード・プロシージャーのコード量を削減します。
- 関数を使用して、ビューで使用されている既存のプログラムまたはサービス・プログラムをラップします。
- プログラムのインターフェースがしっかりと定義されており、必要なビジネス・メソッドが提供されるという前提で、ストアード・プロシージャーが既存のプログラムから作成されます。
アプリケーション近代化のこの定義をこの記事の背景とし、企業が既存の RPG アプリを Web アプリとして活用できるパターンおよび標準のフレームワークを LBST チームが最近実装したプロセスについて説明します。既存のプログラムのビジネス・ロジックをマルチ環境で抽出し、再利用できるようにするため、そのビジネス・ロジックを十分に理解してください。
アプリケーション近代化のこの定義をこの記事の背景とし、企業が既存のRPGアプリをWebアプリとして活用できるパターンおよび標準のフレームワークを LBST チームが最近実装したプロセスについて説明します。既存のプログラムのビジネス・ロジックをマルチ環境で抽出し、再利用できるようにするため、そのビジネス・ロジックを十分に理解してください。
これまで、開発者はModel/View/Controller (MVC)パラダイムを利用して、ソリューションの中のさまざまなパターンを明確に区別してきました。多くの情報システムは、データ・ストアからデータを取得し、それをユーザーに表示してユーザーがデータを変更したり、アップデートをデータ・ストアに保存したりできるようにすることを意図しています。昔ながらの開発者は多くの場合、UIとデータ操作 (retrieve/update) 関数をまとめて必要なコーディング量を減らし、アプリのパフォーマンスを向上させています。
今日のような Web 中心の世界では、アプリケーションのデータ・ストア部分より UI の方が頻繁に変更されます。すでにお話ししたように、かつてないほど早いペースで既存のエンド・ユーザー・デバイスが更新され、新しいデバイスがリリースされています。ビジネス・アプリケーションのデータとインターフェースを連結すると、アプリケーションのデータ送信または表示をはるかに越えたビジネス・ロジックが必要になる傾向があります。ソリューションの構造を変更する場合に、優れた設計原則を順守することは大きな価値があります。Web サービスや MVC のような設計パラダイムは、迅速な開発モデルに対応しつつ、機能が豊富で、ダイナミック・コンテンツを活用できるアプリケーションの開発と展開に大いに役立ちます。
Webアプリの開発プロジェクトを立ち上げる前に、次の点を検討してください。
- UIはビジネス・ロジックより頻繁に変更される傾向にあり、効率的で視覚的にアピールする HTML ページの設計と開発には、複雑なビジネス・ロジックを開発する際とは異なるスキル・セットが必要です。さらに、アプリケーションはさまざまなフォーマットで同じデータを表示できます (Web ブラウザー対スマートフォンなど)。
- UI内で実行されたアクティビティーは、一般的に以下の2つの部分で構成されています。
それらは、データを取得し、表示するために書式設定するプレゼンテーションと、制御をビジネス・ロジックに渡してユーザー処置に基づいてデータを更新するアップデートです。 - UIコードは、ビジネス・ロジックよりデバイスに依存する傾向があります。例えば、アプリケーションのインターフェースをブラウザーからスマートフォンに切り替えるには、開発者は UI コードのほとんどを置き換える必要がありますが、多くの場合、ビジネス・ロジックを変更する必要はありません。ビジネス・ロジックとUIを分離すると速く転送でき、ビジネス・ロジックにもたらされるエラーを最小限に抑えることができます。
MVC 設計パターンは、ユーザー入力に基づき 3 つのクラスである、ドメインのモデル化、プレゼンテーション、およびアクションに分かれます (図1)。
- モデルは、アプリケーションのビジネス・ロジックとデータ管理機能を提供し、ビジネス・サービスを公開します。
- ビューはユーザーからの情報を表示し、収集します。
- コントローラーは入力を代行受信し、モデルにより実行されるアクションに変換します。
効果的な設計パラダイムは、ビュー (UI など) が簡単に交換または展開できるよう、データ層とインターフェースを分離します。すべてのビューはデータのオブザーバーであるため、MVC では、モデル・データへの変更はすべてのインターフェースに反映されます。この設計パラダイムは、UI とアプリケーション・ロジックを分離し、Web サービスの別の重要な側面であるネットワークでの配信を簡略化するため、より優れたスケーラビリティーをサポートします。また MVC は、ビジネス・ロジックの変更によりプレゼンテーション層が中断される可能性を抑え、反対に、プレゼンテーション層の変更によりビジネス・ロジックが中断される可能性を抑えることで、保守の負担を緩和するのに役立ちます。MVC は、マルチ統制がとれたチーム開発アプローチを促進しています。それは、開発者はUI を中断するという心配をせずに堅固なビジネス・コードの作成に集中でき、設計者はビジネス・コードの開発に使用する言語の心配をしなくても、UI の構築と作業に集中できるためです。MVC は、開発プロセスのそれぞれの側面に最適なツールを使用することを促進しています。
図2 のダイアグラムは、アプリ近代化フレームワークの全体構造を表しています。この例では PHP をアプリケーション・サーバーとして使用していますが、実際はアプリケーション・サーバー部分 (つまりコントローラーおよびビュー層) は WebSphere Application Server などの他のアプリケーション・サーバーであったり、RPG、Cobol、Java で作成されたネイティブ・アプリケーションであったりします。さまざまなアプリケーション・サーバーを持つ能力は図3 に示す MVC アーキテクチャーで非常にわかりやすく示しています。図3 は、異なるコントローラーが同じモデルとのインターフェースを取っているところを図示しています。
モデル層
アプリケーション近代化の取り組みでは、モデル層は以下のもので構成されます。
- 永続データを含むテーブル
- データ・テーブルへのインターフェースを表すテーブルの Data Access Objects (DAO)
- SQL ビュー・インターフェースとビジネス・ロジックを表す Data Access Object Views (DAOV)
- ビュー・インターフェースそれぞれのストアード・プロシージャー定義 (コントローラー層がモデル層にアクセスするメソッド)
各DAOは、ビジネス相互作用のためにIBM i サービス・プログラムにより表されます。モデル層 (図4) はSQLを使用して永続データにアクセスし、データ構造体のセットをインターフェース・パラメーターとして定義します。これらのデータ構造体は、データ・モデル、テーブル・データ・アクセス、ビュー・データ・アクセスにより外部に記述されます。図4 に示すデータ・モデルの各種層は以下のとおりです。
- 既存のデータベース表上に構築されているSQLビュー
- DAOVからアクセスできる外部プロシージャー定義を備えた RPG サービス・プログラムとして実装されているData Access Object Tables (DAOTs)
- DAOT を通してデータにアクセスするDAOV。ビジネス・オブジェクト層が DAO を操作する場合に使用するプロシージャー名という形で「verb」のセットを通してアクセスされます。
- 各種 SQLコマンド (INSERT、UPDATE、DELETE、SELECTなど)を介してデータベース表にアクセスする対応するAPI セット
- 図4 の DAO アーキテクチャーの最上位層に示すサービス・プログラム。コントローラー層で使用される呼び出し可能インターフェース (この例では PHP)
データ・モデル・インターフェースは DAOV を通して提供されます。各 DAOV は、コントローラー層からアクセスできる外部プロシージャー定義を備えた RPG サービス・プログラムとして実装されています。代表するオブジェクトにはそれぞれ、RPG 外在的データ構造体または SQL ビューの形でデータ・オブジェクトが入っています。
ビジネス・オブジェクトには、プレゼンテーション層がビジネス・オブジェクトを操作する場合に使用するプロシージャー名という形で「verb」のセットがあります。設計に使用する一般的な verb は、get、add、update、cancel、delete、is、validate です。可能な限り、ビジネス・ロジックはビュー定義に組み込まれています。ビジネス・ロジックをビュー定義内で表現できない場合、SQL 関数が定義されている、またはストアード・プロシージャーが RPG プロシージャーのラッパーとして実装されている可能性があります。使用されるメソッドは、 RPG プロシージャーにより実行される関数に大きく依存しています。各 DAOV には、PHP および他の外部コントローラーのストアード・プロシージャー・インターフェースがあります。ストアード・プロシージャーの名前はラップ・プロシージャーと同じです。図5 はストアード・プロシージャーの作成方法の例を示しています。
コントローラー層
MVC のコントローラー層は、データに対して実行される操作をサポートすることが目的です。コントローラーはビューにモデル・データを提供し、ユーザー処置をボタンのクリックと解釈します。コントローラー層は、ビュー層とモデル層両方に依存しています。IBM i 環境では、Zend の PHP エンジンを使用して、すべての MVC コンポーネントを同じハードウェア・プラットフォームに配置し、同じ OS でホストできます。これにより開発者は、IBM i の PASE 環境で Zend アプリケーション・サーバー上の PHP を使用して、コントローラー層を構築できます。
PHP はページ・フローを制御します。通常は以下のようになります。
- HTML 入力フォームは、ストアード・プロシージャーの要求するデータを取得します。
- PHP スクリプトは、入力フォームで指示された関数 (GET、INSERT、DELETE、UPDATE など) をサポートする IBM i ストアード・プロシージャーを呼び出します。ストアード・プロシージャーはモデル層の一部です。
- モデルはストアード・プロシージャーの結果を使用して、次の HTML ページにデータを設定します。
- クライアント Web ブラウザーは、更新された HTML ページをレンダリングします。
図6 のダイアグラムは、PHP スクリプトがストアード・プロシージャーを呼び出す方法の流れを詳細に表しています。図7 から 図10 には、コントローラー層が機能する様子か説明するのに役立つコードが入っています。この例では、コントローラー層の PHP スクリプトが、図5 で作成されたストアード・プロシージャーRETRIEVEDRINKBYCODEをどのように呼び出すのかを説明します。
図7 で最初に注目すべき点は、SQL ステートメントに入出力パラメーターの疑問符 (?) プレースホルダーがあることです。また、db2_prepare コールが (この場合は、ストアード・プロシージャーへ) 準備した SQL ステートメントを作成している点に注意してください。この SQL ステートメントは最終的に、値がパラメーター・マーカーにバインドされた後に db2_exec() ステートメントにより実行されます。$conn 変数は、db2_connect (または db2_pconnect) ステートメントを通して以前に確立されていたと思われるデータベースへの接続を表しています。$stmt 変数は、後続のステートメントで使用される db2_prepare コールで戻されるリソースを表しています。
プロセスの次のステップは、db2_prepare() ステートメント値により戻されたリソース経由で PHP 変数を SQL パラメーター・マーカーにバインドすることです (図8)。変数 (および変数タイプ) がパラメーター・マーカーにバインドされたら、以前に準備したステートメントを実行することが次のステップになります (図9)。このステップでは、db2_execute() ステートメントのパラメーターとして指定された順序で使用される値の配列($call_values) を作成します。
図5 で作成したストアード・プロシージャーは、結果セット DYNAMIC RESULT SETS 1 が戻されることを示している点を思い出してください。(図10 で示す) この結果セットは $result 変数 (この場合はリソース) で表され、戻されるレコードをループします。図10 のコードはビュー層の一部である点にも注意してください。
ビュー層
ビュー層は、データを表示する、または変更するためのインターフェースを提供します。また、モデル・データを表示し、ユーザー処置 (ボタンのクリックおよびフォーム入力データなど) をコントローラーに提供します。ビュー層は、モデルとコントローラー両方から独立できます。またはコントローラーとしてモデルに依存している場合があります。私の例では、ビュー層は、モデルとコントローラー両方から独立しています。
このアプローチでは、ビュー層はコントローラーにより行われ、モデルにより表現されたアクションの結果を表示する HTML ページにより提供されています。ここで PHP スクリプト記述がまた関与し始めます。PHP アプリは、 PHP と HTML を混合する (つまり、PHP から HTML を生成する) ことが多く、読みにくいスクリプトに役立ちます。LBST チームは、 TinyButStrong という PHP フレームワークを活用することにしました。TBS によって HTML「テンプレート」を確立することで、 HTML を PHP スクリプトから分離できます。テンプレートには、Web ページをレンダリングする前に TBS フレームワークが PHP コードから記入する、マーカーおよびトークンが入っています。図11 のダイアグラムは、 TBS 文書から簡単な例を使用して、PHP データをマージした HTML ページのレンダリングに関わるステップについて説明しています。以下のステップは TBS が機能する様子を説明しています。
- 図11 の HTML テンプレート部分 [onshow.message] で、PHP コード経由で値と置換されるトークンを確立します。Onshow は TBS キーワード、message は値の置換に使用する変数を確立します。
- 図11 の PHP コード部分では、include_once ('ts_class.php') ステートメントには TBS クラスが含まれており、TBS クラスには TBS 構文のクラス定義 (プロパティーとメソッド) が入っています。
- ステートメント 'TBS = new clsTinyButStrong' は clsTinyButStrong のクラス定義に基づく新しいオブジェクトを作成します。新しいオブジェクトの値と関数 (プロパティーとメソッド) は $TBS 変数を介してアクセスされます。
- ステートメント TBS- > LoadTemplate('template.htm') は (コピーのため) HTML テンプレートを $TBS 変数にロードします。
- ステートメント $message = 'Hello' は PHP でのシンプルな変数割り当てです。ただし、HTML テンプレートには message 変数 (onshow.message など) への参照があるため、変数割り当てによりトークンは変数値と置換されます。
- $TBS->Show() は $TBS オブジェクトの HTML をレンダリングします。
- 結果は、onshow.message トークンが $message 変数の値 (Hello) と置換されたことを示しています。
TBS ライブラリーがツールボックスにある状態で、JSON および PHP 配列などのデータ構造体を使用して、モデル層で戻された結果を HTML テーブル、書式フィールド、Ajax プロパティーに挿入できます。
アプリケーション近代化に取り掛かる
この記事では、RPG アプリと DB2 データを Web にもたらすインターフェースを開発する方法論を共有しました。この方法論を使用して、PHP スクリプト記述などのソリューションを使用して、ダイナミック・コンテンツを HTML ページに挿入できます。いったんフレームワークが配置されれば、豊富な機能と機能強化された開発機能を提供するソリューションを活用できます。この記事で、アプリの近代化がもたらす可能性に心躍らせ、アプリ近代化への道を走り始めるのに必要なツールがあることがおわかりになったと思います。