ちょっと間が開いてしまいました。
独自フレームワークCollabo-Xの機能を紹介する第5弾です。

今回はデータベースのアクセス方法について。
この辺は結構いろんな方法があちこちで検討されていて、
それほど独自色を出しているわけではありませんが、
結構お手軽な方法にはなっています。

6.Smartyテンプレートによる動的SQL
動的SQLの出力処理と言うのは結構いつも問題になる箇所です。
ライトウェイト言語のユーザだと、未だに条件分岐でSQL文を結合して出力するパターンを見かけます。
これは、かなり面倒でかつバグが潜みやすい箇所です。

PHPでもいろんなデータベースアクセスの方法が提供されてますが、
Collabo-Xではまず、土台として、Smartyを使って動的SQLを出力することを考えました。

Smartyは本来動的なHTMLをはくためのものですが、
HTMLであろうとSQLであろうと、所詮テキストであることには代わりません。
そして、両方ともある程度構造的なテキストです。
出力する処理には似たような用件が求められることが多いのです。

よく似た形で動的SQLを出力するものとしては、
Seaser2のS2DAOがコメントとして、ifやforeach、変数の埋め込みする機能を持っています。

PHPでやる場合はSmartyがほぼデファクトスタンダードのテンプレートマネージャで、
PHPプログラマならSmartyタグを理解している人が多いので、
SQLについてもSmartyを使うのがいいだろうと考えました。

これを使うとこんなことが出来るようになります。

SELECT * FROM {$table} WHERE TRUE AND {foeach from=$where key=vname item=value}'{$vname}'={$value}{/foreach}

これで、「どれかのテーブルに対してANDで結合した条件で検索する」ための汎用的なSQLテンプレートになります。
もっと複雑な、例えば副問合せなどを含む複雑なSQLであっても、Smartyタグを使うことにより、
比較的簡単に書くことが出来るようになっています。

また、Smartyではユーザ定義タグや修飾子を作成することができるので、
それを利用して、SQLテンプレートをより書きやすくすることができます。
集計関数や日付の計算関数など、使うとわかりづらくなりがちな関数の呼び出しなどを、
ユーザ定義タグとして定義することで、テンプレート自体をわかりやすくすることが可能です。

7.標準的なDBアクセス
Smartyタグを使って動的SQLのテンプレートを作っていくと、
アプリケーション開発の中ではよく似た記述のSQLがほとんどを占めることに気付きます。

例えば、DELETEとINSERTについては、ほとんどがテーブルごとに一つずつ、
決まった形の動的SQLを用意しておくだけで間に合います。
UPDATEやSELECTについても、多くは標準的な形と言うのを定義できそうです。

そこで、標準的なSELECT、DELETE、INSERT、UPDATEのSQLを策定し、
標準DAOとして利用することにしました。

これらは対象のテーブル名もSmarty変数として呼び出し時に引き渡す形になります。
標準形では収まりきらないような複雑なSQLが必要とならない限り、
ほとんどSQLを書かずに開発を進めていけるようになっています。

実際、ある程度の規模のポータルサイトの開発を行った際には、
9割程度は標準DAOだけでデータアクセスができました。
複雑なものだけ、開発時にSQLテンプレートを書き出せばいいのです。

業務システムの場合は、どうしても標準に収まりきらないSQLが出てきますが、
それでも、7割~8割程度、SQLを書き出す作業を削減できます。
独自フレームワーク Collabo-Xを紹介する第4弾。
若干地味な話なんですが、MVCフレームワークとしての特徴の部分です。

5.MVC
Collabo-XはMVCフレームワークです。

一番基本的なことを説明してないのですが、Collabo-Xでは、Webシステムの「業務」や「機能」など、
複数の画面を一まとめにした塊を、ユニットと呼んでいます。

一つのユニットには一つのコントローラ、ビュー、オペレーションと言うクラスが最低一つずつ存在します。

コントローラは、MVCのCで、これは、ブラウザから入力されたリクエストを処理するクラスです。
Collabo-Xではすべてのリクエストをindex.phpが常に受け取ります。

その際URLは、

http://DOMAIN/CONTROLLER/ACTION

の形式で記述されます。これをApacheのmod_rewrite機能を使って、

http://DOMAIN/?contoller=CONTROLLER&action=ACTION

の形に変更されたものが、スクリプトに引き渡されてきます。

CONTROLLERの値にはユニットの名称が書かれています。
index.phpはCONTROLLERの値に対応するコントローラクラスからオブジェクトを生成します。
ACTIONに書かれるのは、コントローラの持つ処理の名前で、これをアクションと呼んでいます。

コントローラクラスに定義されたpublicの関数はすべて、
アクションとして動作することができます。これをアクションメソッドと呼んでいます。

アクションメソッドの中に書かれるのは、オペレーションメソッドとビューメソッドの呼び出しです。
基本的にはアクションメソッドにはあまり複雑な処理は書かないようにします。

処理の内容が画面の表示に直接関係するものであれば、
ビュークラスにメソッドを定義して呼び出すようにします。

DBの更新や、入力値のチェック処理、外部サイトへのリクエストなどは、
オペレーションクラスにメソッドを定義して呼び出します。


ポイントは、コントローラの持つデフォルトの動作です。

コントローラは次の手順で呼び出す処理を判断します。

1. アクションメソッドが存在した場合はアクションメソッドを呼び出す。
2. 上記に該当しない場合で、アクション名に対応するビューメソッドが存在すればそれを呼び出す。
3. 上記に該当しない場合で、アクション名に対応するテンプレートが存在すれば、それをレンダリングする。

また、オペレーションメソッドが存在しない場合でもエラーにはなりません。


これによって何ができるかと言うと、Collabo-Xの開発工程に沿うことの便宜を図っています。

1.とりあえず、データ定義関数を使って、テンプレートだけを作ってしまえば、画面ごとの表示を確認できる。
2.必要に応じてテンプレートの表示処理を定義すれば、そちらが使われるようになる。
3.コントローラにアクションメソッドを定義すれば、画面遷移が確定する。
4.アクションメソッドを定義した後で、オペレーションメソッドを作れる。

見た目周りから完成させていこうとする考え方に沿うためにこうした動きになっています。
滅多なことでは使っていませんが、ビューメソッドやオペレーションメソッドは、
複数のビュークラス、オペレーションクラスに分割して定義することができます。

その場合も、親クラスとなるビュークラス、オペレーションクラスに、
テスト的な関数を定義しておいて、本番の関数は個別に定義したビュークラスに記載するという形で、
テスト関数から本番関数に書き換えていくということが出来るようになっています。
独自フレームワーク Collabo-Xを紹介する第3弾。
今回は個人的には一番気にっている機能。

「ドキュメントのように書く」機能です。

たいしたことではないんですが、コロンブスの卵と言うか、
あると便利と言う機能になります。

Collabo-Xの開発工程で、ワークフローや操作権限の実装を一番最後に持ってきたのは、
こうした仕様は最終段階までどう変更が掛かるかわからないからですが、
一方で、納品後にすら変更が掛かるかもしれないのがこれらの処理です。

そうした処理を、簡単に変更するためには、
「ドキュメントのように書かれている」ことが一番だと考えました。
ちょっとわかりにくいお話ですが、どうかお付き合い願います。

4.ドキュメントのように書く(関数マトリックスとテーブル作成機能)
業務システムなどを開発する場合、仕様書や設計書の多くは、表形式で記述されます。
例えばワークフローや、ユーザ権限などは表形式で記述することが多いものです。
表形式はフロー図などの図形に比べて、狭い紙面上に膨大な情報を記述できます。

ぱっと見のわかりやすさでは図形にはかないませんが、
面積あたりの情報量と、書く側の手軽さから言えば表の方が上を行くと思います。

もう一つ、特徴があります。表形式は例えばCSVと言った形式で、
その気になれば、単なるテキストファイルであっても、そのデータをそっくり記述できます。


つまり、うまくすればソースコードに、仕様書と同じような記述で実装させることができます。


いわゆる組込み系と言われる主にC言語を使った開発を行う分野で、
一般的なテクニックとして「関数マトリックス」といわれるものがあります。

関数マトリックスとは、「関数ポインタ」を多次元配列に並べることで、
実行する処理の場合わけを膨大なif文やswitch/case文を使わずに実装する方法です。

例えば、「ユーザ権限」と「操作ID」でそれぞれ実行したい処理が違う場合、
条件分岐を使うとif文やswitch/case文をネストして長大な処理を書くことになります。

これを関数マトリックスにするなら、分岐先の処理はすべて関数として作成しておき、
「ユーザ権限」と「操作ID」をキーとする二次元配列を作成し、
その値に各関数へのポインタを代入してやるようにします。

実際に処理を実行するときには、配列の添え字に「ユーザ権限」と「操作ID」を指定して、
関数ポインタを取り出し、ポインタが指し示す関数を実行するだけになるので、
処理の効率も著しく向上します。


表形式のデータと言うのは、先に述べたように仕様書や設計書に良く使われるものですから、
処理速度や可読性の向上だけでなく、仕様書に近い形でソースコードが書かれることにより、
開発時点での作業量を減らし、メンテナンスのしやすいプログラムにすることもできます。


Collabo-Xでは、この関数マトリックスと同じような処理を行うための機能を用意しています。
多次元配列に入った関数名を用い、添え字を指定するだけで、目的の関数を実行できます。


しかし、ここにPHPゆえの問題があります。

PHPでは、C言語のように簡単に、ソースコード上でも表らしく、2次元配列を記載することができません。
PHPの場合、2次元配列は次のように書きます。

$matrix = array(
array(1,2,3),
array(4,5,6),
array(7,8,9)
);

array()関数の中にarray()関数が入る感じです。
これならまだどうにかと言う気もするのですが、
この書き方だと添え字は数字しか使えません。

PHPでは連想配列をサポートしているのですから、
添え字には文字列を使いたくなったりします。

$matrix = array(
'guest' =>array(name=>'ゲスト',role=>'0',color=>'#000000'),
'menber'=>array(name=>'メンバー',role=>'1',color=>'#773333'),
'admin' =>array(name=>'管理者',role=>'2',color=>'#337777'),
);

これが長くなると、すっかりこんなものを書く気はなくなってしまいます。
これを、Collabo-Xでは次のように書けるようにしました。

$matrix = btable("
, name, role, color;
guest, ゲスト, 0, #000000;
menber, メンバー, 1, #773333;
admin, 管理者, 2, #337777;
");

文字列として、CSVモドキを書き込むと先に書いたような2次元連想配列を作成することが出来ます。
同様の方法で、「連想配列の配列」や「配列の配列」、「配列の連想配列」も書き出せるようになっています。

これらの関数は先に述べた関数マトリクスや、上記のような権限などの情報を記載するだけでなく、
データベースに変わってSmartyに引き渡すためのテストデータを記述することにも利用できます。

Excelで作成したデータを、エディタに貼り付けて、ちょっとした変換をするだけでこの書式のデータを作れます。
EXCELからエディタにコピペした場合は、[TAB]を[,]に、[\r\n]を[;\r\n]に変更してやれば出来上がります。
あとは、自分でTABやスペースを足して、表らしい形に整形してやればいいだけです。

逆もまたしかり、ソースコードから該当箇所をコピペして、
EXCELで取り扱える形に変換してやれば、ソースコードからドキュメントに変更を反映できます。
独自フレームワーク Collabo-Xを紹介する第2弾。
今回は核となる機能の一つである、テンプレート上にデータアクセスを書き込む機能について。

3.テンプレート上でのデータ読み込み
Collabo-XではHTMLの出力にSmartyを利用します。
ただし、$smarty->assgin()などを直接呼出しはせず、
連想配列としてデータを作成して引き渡せば、一発でデータを流し込める仕組みになっています。

ポイントは、「テンプレートを書くだけでも、とりあえず画面の動作を確認できる」状態にすることです。
Smartyのタグでもバグがあります。なので、書いたらすぐに動作を確認したいものです。
また、見た目を作るものですから、出力結果を見ながら確認が必要。お客様にも早く提示したい。

しかし、単にSmartyテンプレートを作っただけでは、テンプレートの動作確認はできないわけです。
最初、テストデータを流し込む処理を用意してというのもやっていたのですが、これはこれで面倒。
そこで、Smartyのユーザ定義タグとして、データをDBから読み込んでアサインするというものを用意。

また、DBからだけでなく、専用タグによって、定数としてテンプレート上でデータを用意できるようにしました。
これなら、モックアップを作成せずに、いきなり動的HTMLのテンプレートを用意しても、
すぐに動作確認ができます。


定数を使ったプロトタイプテンプレートの例

{define
NAME=DATA
btable="
, name, sex, age;
1,akira, 1, 21;
2,hanako,2,19;
"}
<ul>
{foreach from=$DATA item=person}
<li>{$person.name}
({print_constants_one NAME=sex value=$person.sex})
{$person.age}才</li>
{/foreach}
</ul>


DBにアクセスする動的テンプレートの例

{assign_select
NAME=DATA
TABLE=person
WHERE="sex=1"
}
<ul>
{foreach from=$DATA item=person}
<li>{$person.name}
({print_constants_one NAME=sex value=$person.sex})
{$person.age}才</li>
{/foreach}
</ul>
コラボロジックでは、LAMP環境での業務系Webシステムの開発を主な事業としています。

業務系Webシステムを効率的に開発するため、独自のWebアプリケーションフレームワーク、
「Collabo-X」を開発し、日々バージョンアップを行いながら、実際の案件に利用してきました。

ちょうど、ちょっとした機会があって、Collabo-Xを紹介するプレゼンを作ったりしたので、
その特徴をここでも紹介させて頂きます。長いので3回ぐらいに分けますね。

今回は、フレームワークそのものじゃなくて、フレームワークを作る際に考えた、
目的と方針について。

1.目的
コラボロジックで請け負う業務系Webシステム案件は、多くの場合1人月から10人月以下の、
小規模案件となっています。こうした小規模案件には共通した問題があります。

・納期が短いため仕様変更やトラブル発生に対応するための予備の日数を確保しづらい。
・要求が不明確な状態で開発が始まるので、予備の日数が少ないにもかかわらず、戻り工数が多い。
・エンドユーザ側に専任の担当者がいないため、システム開発へ積極的にかかわって頂くことが難しい。

多くの場合、納期前後の期間に集中的に担当者がシステムについての意見を述べ始める状態になるため、
納期を守れなかったり、トラブルになりやすい傾向があります。

結果として開発者と発注者の間に不信感が募り、
継続的なパートナーシップを築けないということになってしまいます。
実は、中規模、大規模のシステムの開発よりも困難が付きまとうのが、
小規模システムの開発なのです。

コラボロジックでは、こうした問題を解決するための開発工程を検討し、
それにあわせたアプリケーション開発を行うためのフレームワークを用意しました。

2.開発の工程
小規模システムを開発するのにふさわしい開発工程のあり方として、次の特徴が必要と考えました。

・早い段階で意識の違いや明確な仕様を発注者が考えられるよう、見た目から開発を進められること。
・仕様変更に柔軟に対応できること。
・仕様変更などの状況の変化に対応して、工程を動的に組み替えられること。
・システム開発の専門家ではない発注者にも理解できる明確でシンプルな開発工程であること。

これらの特徴を備えるために、次のような手順を考えました。

1.基本設計(システムの基本的な仕様、画面遷移、データベースの概念設計)
2.機能設計(基本的な画面項目の定義、データベースの定義、必要に応じてモックアップ、画面設計書)
3.開発環境の準備(フレームワークの基本構成を構築)
4.テンプレートプロトタイピング(Smartyタグを含むHTMLに入力データを定義する記述を加えて、動作確認可能な動的HTMLを作成)
5.動的テンプレート作成(プロトタイプテンプレートのデータ定義部をデータベース参照タグに変更、または画面表示に関する処理を記述したビュー関数を作成)
6.画面遷移実装(コントローラにアクションメソッドを作成し、テンプレート内のURLを変更)
7.データ変更処理を作成(オペレーションメソッドを作成し、データベースへの変更処理などを記述)
8.ワークフロー、操作権限などの処理を作成(テーブル定義関数を利用し、EXCELの表形式などで定義される仕様を、そのまま表形式データとして作成し、表形式データから実行する関数を決定する処理を利用して実行する形を作る)
9テスト

このうち5から8までの実装作業部分は、機能や業務単位で繰り返し実施することも可能です。
こうした工程で開発することを前提とした上で、フレームワークの機能を検討し、実装してきました。

大事なのは、仕様変更がしやすく、また、出来るだけ早く、仕様の勘違いや方針変更に気付けること。
特にワークフローなどは、画面が出来てこないと何が問題なのか、ユーザにはわかりにくいところなので、
一番最後に作る形式が必須と考えました。

次回以降、この方式で開発するためにフレームワークに実装した機能を紹介していきます。