Category Archives: Uncategorized

Apple IDの2要素認証をいつまでも求められる場合の対処

ちょっと話題的には古いのかもしれませんが、Apple DeveloperのApple IDは2要素認証が必須になり、そのような警告メッセージが出ました。で、ある時から、2要素認証を「しないといけない」状況になりました。

そこで、appleid.apple.comで、2要素認証をオンにしてみたのですが、XcodeやDeveloperサイトでの状況は変わりませんでした。Xcodeでは署名のたびにパスワードを求められるのですが、それでも認証が通らなくなってきてなんとかしないといけなくなりました。appleid.apple.comで設定すればいいだけではないというのがポイントです。

で、どうすればいいかといえば、macOSのシステム環境設定にあるiCloudで、そのApple IDを入力します。しばらくすると、警告アイコンが出てきて、更新するみたいな内容のボタンが出てくるので、それをクリックしてしばらくすると、アカウントの情報が更新された模様です。そこまでくると、Xcodeでの認証が通るようになります。

多分、何かの具合で、appleid.apple.comでは更新ができない状態なのでしょうけど、iCloudで普段使っていないアカウントの場合、入力し直しになり、データが消えるみたいなメッセージに対処しないといけないわけですが、データはクラウドにあるので原則問題ないと思います。しかしながら、システム環境設定を変えるのは色々面倒と後の影響がきになるところですが、appleid.apple.comでダメだったら仕方ないので、iCloudでセットアップして、更新処理をmacOS側からやってください。

composer.jsonファイル内でのスクリプトのパスをUNIX/Windows互換にする

 PHPでのモジュール管理ツールであるcomposerでは、通常「composer update」と入力することでインストール作業が始まるが、インストール後に実行するスクリプトを記載することもできる。INTER-Mediator Ver.6では、composerの仕組みによりnode.jsをインストールして、「composer update」に引き続いて「npm install」を自動的に動かすようにしている。composer.jsonファイルの主要部分はこんな感じだ。package.jsonはすでに用意されている。composerはvendorというディレクトリを作り、そこにモジュールをコピーし、加えてネームスペースを元にしたファイル検索の仕組みが組み込まれる。単にコマンドを入れてみれば、nodeやnpmコマンドがvendor/binにコピーされているので、相対パスの記述が適切だと考えた。

{
"name": "inter-mediator/inter-mediator",
"version": "6-dev",
"time": "2019-03-07",
:
"require": {
"php": "^7",
:
"mouf/nodejs-installer": "*",
:
"scripts": {
:
"post-update-cmd": [
"./vendor/bin/npm --save-dev install"
],
:

 これで、macOS、Linuxでは正しくnpmコマンドが稼働するのではあるが、Windowsではエラーが出てnpmが動かない。PowerShellでは次のようにでる。最後の行は赤い背景になる。コマンドプロンプトでもほぼ同様だ。

> ./vendor/bin/npm --save-dev install
'.' is not recognized as an internal or external command,
operable program or batch file.
Script ./vendor/bin/npm --save-dev install handling the post-update-cmd event returned with error code 1

 やっぱり/だろうかと思ってディレクトリセパレータを¥にしてみた。もちろん、JSONなので¥¥とタイプするが、やはり同じだ。./を無くしても同じである。

 あれこれ調べて分かった。composerのドキュメントのNoteの所に書いてある。要するに、./vendor/bin(あるいは.¥vendor¥bin)へは、composerによってパスが通っているらしい。composerによってインストールされるコマンドの場合は、以下のように相対パスを書かなくても、npmコマンドの実行はできるということである。この記述だと、UNIXでもWindowsでも同一の記述でnpmコマンド実行ができる。

 :
"post-update-cmd": [
"npm --save-dev install"
],
:

要求は対話を通じて次第に明確化するもの

 ソフトウェア開発では、実際に動くようにする「実装」という作業が必要である。どのように実装するかは「要件定義」という記述を元にして検討され、その要件定義は顧客の「要求」を元に作られるというのが原則だ。本来は要求が先にあり、「〜をしたい」「〜を実現したい」という形式で記述できるものが基本である。「○秒以内で処理が完了する」と言った非機能要求も記述される。しかしながら、この要求による記述内容だけでは、その実現方法が多岐に渡る事になる。そこで、実装を円滑に進めるために「〜ができるようにする」という形式で記述できる要件を定義し、実装側は要件の実現に注力する。容易に分かるのはこうすれば実装の分業がやりやすいことだ。開発業務は元請けから下請けや複数の開発者に至る階層化された業務フローが一般的であり、要件定義は分業の基礎としてビジネス構造にもマッチする。この方法の是非はあるのだが、長年この流れをベースにやっているだけに、なかなか変えられれないというのが実情だとして、この枠内で開発における問題点を考える。

 うまく分業され開発が進むかと思うと、現実には顧客が望んでいたものと違ったものが開発されてしまうという問題がある。笑い話になりそうな、全く違うものができてしまうこともある。ちょっと意図的に強調した例として次のようなものがある(もちろん、かなり単純化している)。要求として「ポイントシステムを作りたい」として、要件としていくつか作られた項目の中に「ユーザー管理機能」というものがあるとして、その要件だけを知らされて実装したとしよう。すると、単に住所録みたいなものが出来上がり、管理番号がないとか、期限の管理はどうするのよ?みたいな実装が上がってくるかもしれない。もちろん、通常は自身が実装する要件以外も目を通すので、優秀なプログラマーたちの忖度機能が発動され、次第に顧客の要求に近づくということになる。なんだ、うまく行っているということではないのか?と思われるかもしれないが、うまくいく前提の1つとして、要求も要件も記述されている、つまりは文書化されているという前提がある。もちろん、100%文書化できるものではないのは確かだが、一定以上の割合の文書化がされていないとおそらく忖度ベースの開発は成り立たない。そして、経験上、一定以上の割合が満たされることはほとんどないと感じている。

 ソフトウェア開発の形態は実に様々あり、個別の事情も多いのだが、ここでは単純化して、顧客とコントラクターとデベロッパー(開発者)の3つの存在があるとして考えよう。下請け構造については「開発者」の一言で片付ける。ざっくりと言えば、SIerという人たちは「コントラクター」であるが、いわゆる「ゼネコン」の意味でのコントラクターであり、顧客から業務を請負、遂行する中心人物である。このような状況で開発をしている場合、開発者にとっては顧客の要求が極めてわかりにくいことが多々ある。好意的に見えればコントラクターが開発者にわかりやすいように解釈して作業に分割してくれている結果とも言えるのだが、コントラクターが顧客の要求を本当に理解しているのか疑問に持つような要件を投げてくることもある。たぶん、誰も悪意はない。それでも、比較的大きめの開発をしていると、要件に矛盾が目立つようになることが出てきて、疑問は急激に膨らむのである。要件は解釈がぶれる余地のない文章に一般的にはなっていることもあり、開発者は要件は書いてある通りに解釈できるものの要求が断片的にしか分からないと強く感じるようになる。コントラクターとの関係が悪くなると、責任の押し付け合いにもなる。

 何とかならないのだろうか? だからこそアジャイルなのだろうか? 手法に至る前にまず、問題の本質をどこに求めるかを特定したい。開発者が要件が分からないと感じる時、実はコントラクターも要件はよく分かっていないことが多い。開発者がコントラクターに問い合わせた場合、開き直って「私にもわかりません」と言われても困るのだが、もっと困るのは分かっているふりをすることで、顧客の要求と異なる回答をしてしまうこともある。実は、開発者と同じ程度にコントラクターも顧客の要求が分かっていないと考えるべきだ。そうなると、コントラクターがもっとしっかりすべきなのだろうか? それでは、よくある「営業 vs 実行部隊」の局面になってしまい責任の押し付け合いに等しく、ここから何か生み出されたことを見た事はない。開発者はコントラクターを責めてはいけない。その理由は、実際のところ、顧客自身が実はコントラクター以上に要求を理解していないからである。顧客に何か要求が明確にあるのかというとそうでもない事が普通にあるというのが現実だ。正直な顧客は「モヤモヤした話で恐縮ですが」と切り出して、構想を語る。不誠実な顧客は「お前らプロなのにそんなんことも分からないのか」と訝る。分からないから聞いているのである。私たちが超能力者でないことを説明する気力は普通は出ない。何れにしても、要求が文書化されているかと言えば、極めて限定的になってしまうのが通常である。

 そこで、顧客は要求を理解していないという前提に立つ必要がある。理解していないというのは色々な側面がある。何か構想はあるけど言語化されていない場合もあれば、上司に言われてシステム化の取りまとめをしており経営的な意味は全然説明されずに担当者になっているような場合もある。この点は掘り下げたいところだが、ここでは文書化あるいは言語化されていないという状況としてまとめておこう。このような状況は、次のように考えて見よう。顧客の頭の中はファンタジーであり、顧客の発する言葉はポエムなのである。ソフトウェア開発において、コントラクターはそのファンタジーを実現すべく奔走する人であり、開発者はポエムを開発言語に翻訳する人たちである。それじゃあやってられん!と言う前にこう考えよう。ソフトウェア開発者は、要するにスターウォーズのような素晴らしいSF作品を制作しているスタッフのような存在なのだと。若干無理やりかつ恣意的なポジティブ化ではあるが、ここで前を向かないとどうしようもないのである。

 ここであっさり「要求なんぞはないものだ、幻想だ」と言い切るのも無理がある。現在の多くの開発手法は要求が出発点にあるから。要求がないのではなく、開発者は要求を何らかの方法で明確化をする必要があるという前提に立ちたい。筆者は開発者として関わることがあるが、一人で全部行うコントラクター兼開発者の場合もある。後者の場合の問題点はかなり別のことが絡むので、ここでは顧客/コントラクター/開発者モデル場合だけに限定する。短絡的な考えとしては、開発者として関わっても、顧客と直接話をしたらなんとかなるのではないかとも考えた。だが、ビジネスライン的な意味で、普通はコントラクターは嫌がるのと、対顧客に対する原点的な意味での要求獲得は別の難しい問題があるので、開発者と顧客を会わせるというのはよほど限られた状況でしか成立しない。少なくとも、開発者が顧客対応可能なSE能力を持つような場合などである。ということで、顧客/コントラクター/開発者ラインを保って要求を明確化する方法はないかと試行錯誤をした結果、1つの方法がうまくやれば良い方向に行くのではないかという感触を得た。確証を得るほどの事例に当たった訳ではないが、提案はできる段階に来たと感じている。

 その方法は、コミュニケーションにおいて、要求の断片を話題に含めて、その要求あるいは会社が正しいかを検証することである。例えば、要件定義として「顧客管理番号は7桁である」と書かれているとしよう。これは少なくとも、「123」でいいのか、「0000123」のようにするか悩む定義である。単に「この要件は管理番号の頭を0で埋めるという意味でしょうか?」などと問い合わせるのが普通だと思われる。このコミュニケーションの中において、要求に近い文章を紛れ込ませる。例えば、「管理番号は、ポイントカードに印刷されるので、頭を0で埋める7桁なのでしょうか?」と聞いてみる。ここで「ポイントカードは印刷してお客様に渡したい」「ポイントカードには管理番号が印刷されていて、システム問い合わせで利用したい」と言った要求を言い換えて、質問に含ませている。このような問い合わせに対して、正解と言われるかもしれないが、違っているかもしれない。「管理番号はポイントカードには印刷しません。単にバックエンドのシステムが7桁で切られているから、それを気をつけて欲しいという意味です」のように答えが返るかもしれない。どっちにしても、ほんの少しだが、要求に近い情報が得られた。もちろん、それは小さな積み重ねだが、全くないより大きな進歩があるはずだ。なんとなくそうなのかなと思っていたことが明確になることも小さな進歩だろう。前記の例だと、「実は顧客情報はバックエンドのシステムにも入れられる」という新しい発見があったのかもしれない。仮にポイントカードに印刷するための0埋めだったとしたら、それをどこでやるのかという議論に発展するかもしれない。

 開発者からコントラクターに、要求が分からないから示して欲しいと言っても、コントラクターは開発者と同程度、下手をするとさらに下回るレベルでしか要求は理解していないと考えるべきだ。しかも、コントラクターはその点を意識しているかどうかも怪しい。無理やり文書化をお願いしたとしても、出てくるものには新しい情報はない。顧客に依頼するというのも同様だ。しかしながら、要件の中から要求を含めた、あるいは要求に至る内容を込めたコミュニケーションをすることで、不明瞭な要求群に対して逆算的に少しずつ隙間を埋めるような効果が期待できる。その結果、要求が次第に明確化し、気づいていない関連性が見えて来ることも期待できる。開発者にとって知る事も重要だが、コントラクターやさらには顧客に対しても気づく機会を作っていることも重要である。開発に関わる全ての人の意識を要求のさらなる明確化に向けるためのコミュニケーションが活発になることで、開発現場の様々な側面で要求が次第に固まるということを期待できるのではないかと考える。

 この手法で一番難しいのは作文である。コントラクターや顧客との関係上、どこまで言っていいのかなど、ドメインや個別の事情も絡む。要件に絡めるというのが1つの成立しやすい手法だが、普段の会話で投げてみるというのもあるかもしれない。しかしながら、同じようなことを何度も聞く、突拍子もない質問になってしまうといったようなことは避けたほうがいい。バカ者かと思われてしまうのは不利な状況を作りかねない。それでもうまい問いかけを繰り返し辛抱強く進め、成果物に対する着目点を顧客/コントラクター/開発者でなるべく多く共有できれば、より良い結果になることは十分に期待できる。

 実装する開発者が何人もいるような開発で、頼りになるように見える人は必ずいる。その人は、発言が多く、かつ、発言の中で、念の為にという意味合いで色々な角度で言葉を繰り出す発言が目立つ。そうしたやりとりが、開発の中で自身の実装部分に対しても非常に参考になったという経験もある。確認のために、条件を言い換えてみたり、その要件の目的をたずねてみると言った行動が、他の開発者の助けになるということもあった。そういう人はコミュニケーションスキルが高いという事で終わらせがちだが、スキルには細かなポイントがたくさんある。その1つが要求の明確化であり、それがコミュニケーションから可能ではないかということも、様々な人たちの行動や自身のプラクティスからの結論である。一方、この方法がうまく行かない事例として、コントラクターが開発者の発言を抱えてしまって顧客に流さないタイプの人である場合だ。コントラクターがしっかりしていればいいとも言えなくはないが、前記の通り、開発者が要求が分からないときは得てしてコントラクターも分かっていない。顧客に確認もしないというのは、単なる顧客に対するイエスマンかもしれないが、要求に対する問題意識がないのかもしれない。こういう現場では、とにかく時間がかかり、作業方針も立ちにくく、開発者の間で何かがぐるぐる回っているだけになる。このようにアンチパターンはある程度は見えている部分もあるが、まずはプラクティスとして問いたいと考える。

Ubuntu Server 18でINTER-Mediatorを動かすまで

Ubuntu Server 18.04.1 LTS上でINTER-Mediatorを動かす話です。とは言え、半分以上はLAMPサーバーセットアップの方法となるかと思います。なお、様々なコマンドがちょっとずつですが変わっているので、その辺りも含めてまとめておきます。

サーバーはVirtual Boxで稼働させました。このサーバーは単に実験するだけでなく、INTER-Mediatorのデモ用にも使いますので、外部からのアクセスが必要です。そこで、ネットワークは、NATとブリッジネットワークをこの順序に設定しておきました。そして、インストール途中で、ブリッジネットワーク側は、ローカルネットワーク側に存在できるような固定IPに設定します。この設定は後からでもできるのですが、最初からやっておくのが失敗がありません。NATが必要かどうかの問題もありますが、ブリッジネットワークを切っても外部に接続できるようにするために、こうしました。

さて、セットアップ後、apt-getなのですが、その前に、以下のように、レポジトリの設定ファイル/etc/apt/sources.listの3行いずれも末尾に「universe」という単語を入れておきます。こうしないと、PHPのいくつかのモジュールをインストールできませんでした。

$ cat /etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu bionic main universe
deb http://archive.ubuntu.com/ubuntu bionic-security main universe
deb http://archive.ubuntu.com/ubuntu bionic-updates main universe

(2019-01-03追記)ubuntu-18.04.1.0-live-server-amd64.isoというファイルでインストールしたところ、上記のuniverseを追加する作業は不要でした。最初から、レポジトリが読み込まれる状態になっています。

こうして、apt-getします。私はaptitudeでやる習慣ができてしまったので、aptitudeでやったのですが、試行錯誤しないのなら、apt-getでやることになるので、コマンドはapt-getで書きます。Apache、PHP7.2、MySQL、PostgreSQL、SQLiteまでを入れました。INTER-Mediatorを稼働するのに必要なPHP追加モジュールは、概ねこのようなあたりですが、追加が必要そうならこの文書を更新します。

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install -y apache2 php7.2 libapache2-mod-php7.2
sudo apt-get install -y php7.2-mbstring php7.2-bcmath php7.2-curl php7.2-xml
sudo apt-get install -y mysql-server-5.7 mysql-client-core-5.7 php7.2-pdo-mysql
sudo apt-get install -y postgresql php7.2-pdo-pgsql
sudo apt-get install -y sqlite3 php7.2-pdo-sqlite

ちなみに、PDOのライブラリは、「-PDO」の付いていないもののエイリアスらしく、そういうメッセージが出て、例えばMySQLなら「php7.2-mysql」がインストールされます。

なお、Apacheの再起動が必要になることがあるかと思われますが、こちらのコマンドを使います。serviceコマンドも従来通り使えますが、systemdベースになっていますので、今現在の状況に合わせたコマンドを使いましょう。

sudo systemctl restart apache2

INTER-Mediator Ver.6を試すなら、composerは必須です。ホームフォルダをカレントにして以下のようなコマンドを入れることでインストールされます。レポジトリのものもあるようなのですが、この方法だと最新版が入手できるので、こちらを紹介します。他のサイトもほとんどこちらの方法を紹介しています。これで、コマンドプロンプトに「composer」と入れればヘルプが表示できます。なお、実際のcomposerの動作では、PHPのzipモジュールとunzipコマンドのインストールも必要なので、そのコマンドも記載しておきます。それから、gitも必要ですね。

cd
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer

sudo apt-get install -y php7.2-zip unzip
sudo apt-get install -y git

ここまでで、LAMPサーバーセットアップができているということになります。WebサーバーのルートにINTER-Mediatorをインストールするとしたら、例えば、以下のコマンドで行えます。

cd /var/www/html
git clone https://github.com/INTER-Mediator/INTER-Mediator.git

ファイルのダウンロード後に、INTER-Mediatorフォルダをカレントにして、composerコマンドを稼働します。composerを稼働させないと、PHPのプログラムへのパスが通りません。composerを使ったいろんな作業はあるのですが、ここではダウンロードしたものをそのまま動かす方法をまずは説明しました。

cd INTER-Mediator
composer update

MySQLへのrootユーザーでのログインは次のように行います。なんとなくPostgreSQLのようになってきました。rootパスワードを設定してどうこうするという状況ではなくなったようで、この状況に適応しましょう。管理者ユーザーで、mysqlコマンドを打つのでjはなく、sudo mysqlということです。パスワードは、sudoの時のパスワードで、つまりはログインしている管理者のパスワードを入力します。MySQLのrootのパスワードはつまりは指定しません。

sudo mysql -uroot

INTER-Mediatorのサンプルファイルを読み込むとしたら、こんな感じになります。もちろん、必要に応じて、管理者のパスワードを入力します。サンプルは、INTER-Mediator/dist-docsにあります。

sudo mysql -uroot < sample_schema_mysql.txt

一方、PostgreSQLは、以前からpostgresユーザーでの接続を行うことで、データベース接続していましたが、その点は変わりません。sudoでpostgresユーザーになるので、現在のログインしている管理者ユーザーのパスワードを知っておく必要があり、postgresユーザーのパスワードは利用しません。コマンド接続と、INTER-Mediatorのサンプルの読み込み例を記載します。サンプルは、INTER-Mediator/dist-docsにあります。

sudo -u postgres -i

sudo -u postgres psql -c 'create database test_db;'
sudo -u postgres psql -f sample_schema_pgsql.txt test_db

SQLiteは特に違いはありません。サンプルは、INTER-Mediator/dist-docsにあります。

sudo mkdir -p /var/db/im
sudo sqlite3 /var/db/im/sample.sq3 < sample_schema_sqlite.txt
sudo chown www-data /var/db/im
sudo chown www-data /var/db/im/sample.sq3

開発の現場では「手法よりも問題解決」が現実

開発の現場で、「手法」を議論する機会が減ってきているように思う。もちろん、自分の身の回りのことが全てではないので、偶然かもしれないが、ブログ等での話題でも、あまり見られなくなっている気がする。以前だと、例えばMVCがどうとか言った話題が華やかだった記憶がある。そして、古くからのさまざまな手法のどれがいいのかと言った話題や、特定の手法をどのように理解すればいいのかといったことが議論された。サイエンス的に考えれば、原理原則があり、それに則った手法は、成功する確率が高くなるということから、以前は手法やアーキテクチャ中心的な考え方もあっただろうし、もちろん、今もそれはなくなってはいない。

現実はどうだろうか? 色々な手法や原理原則は、1人1人がしっかり学習して現場適用するということも必要なことかもしれないが、「良い手法」はそのものが、すっかりパッケージ化されている。ソフトウェア開発で言えば、フレームワークやライブラリ、あるいは開発ツールで、そうした過去の蓄積が完全にパッケージされており、手法を深く理解しなくても開発を進める上ではあまり問題はない。ともかく、ある「やり方」を採用すれば、難しい原理原則はもちろん、手法の適用までができてしまうのである。Webのサーバーサイドフレームワークは典型的な例だろう。ほとんどのフレームワークはMVC(正確にはJavaEEでのMVC2パターン)であり、よほど変なことしない限りはMVCに基づく役割分担が自然に作り込まれるし、レイヤー化についても気がついたらそうなっているのが一般的だ。もちろん、実装の良し悪しはあるとしても、現場で働く側としては「○○フレームワークでよろしく」の一言で済んでしまう。

そうなると、現場でもっとも注目されるのは何だろうか? システム開発の現場と、サービスアプリケーションでは色々違うとしても、結果的に、「問題点は何か」ということに注目することが常に行われているのではないだろうか。開発の枠組みは使用フレームワークをはじめとして、結果的に決まってしまうことが多い。要求工学では手段は後から決めるというのが基本ではあるが、現実にはそうでもない。そして、そこではどんな手法を採用するかも概ね決まっている。スタッフが持つ経験をベースに、進行の可能性を検討し、誰かが問題なく進められる部分は、特にフォーカスされない結果となる。一方、誰も作ったことがない仕組み、誰も経験したことがフレームワーク、ある領域で実現できそうにない非機能要求など、「できるかどうか分からない」所に開発タスクとしては目を向けることになる。

では、できないことを、原理原則からボトムアップして、手法を求めるかと言うと、そう言う側面が問題解決に集中しているときはあるかもしれないが、その結果、あるライブラリを使うことで十分に解決されるなら、「ライブラリを使います」と言うことで集約され、問題がさらに絞られる。「チーム全員で手法をまずは勉強します」という結果はかなりハードルが高い。結果的に、問題から始めて、パッケージ化された解決手段で概ね解決し、さらに違う問題にたどり着き、それを繰り返す。問題がほぼなくなれば、一定時間後に完成に進めるということだ。

問題点の解決が現場での主要な話題になり、系統的な手法が議論される素地はほぼない。もちろん、結局のところアジャイルということなのかもしれないが、小さなプロセスでも、大きなプロセスでも同様に言えることではないだろうか。良い悪いはあるとしても、そのように進んでいる。その中で、基本や原理を叫んでも、誰も耳を傾けない。問題を解決する糸口は、まさに原理原則に立ち返ることで手にできるとも言えるのだが、「良い素材はないだろうか」が糸口になってしまうのである。

普段は小規模な開発に関わる機会が多いので、仕様書が渡されないような発注は普通にある。もちろん、大きな会社の発注では仕様書があるものの、非常に高い割合で「仕様書書いている」と言う証拠のためだけの紙の塊でしかないようなことも感じる。設計に役に立たないわけではないが、中身が実装作業に遠いのである。わかり切ったことは簡単に書き、問題点を記述して共有すれば、仕様書はより役に立つのではないだろうか? サイエンスなので、原理原則があって、それを踏まえた手法があるのは間違い無いのだが、いっそうのこと現実に合わせて「問題解決」にフォーカスした手法に目を向けるべきだと考える。とはいえ、そう言う「手法」を作っても意味はない。手法を否定する手法というのは存在に無理がある。その意味では、アジャイル宣言のように、どんなマインドで対峙すべきなのかをうまく表現しないといけないだろう。ということで、表題のように「手法よりも問題解決」と言ってみた次第だ。今やそういうやり方が一般的というスタンスで、メリットと注意点を検討すべきではないだろうか。

2018年頭の近況報告

気がついたら全然記事を書いていませんでした。最後に書いたのは昨年の5月、ちょうどFileMaker 16がリリースされたのですが、新機能であるREAST APIのためのクラスを作るなど、そこそこコミットしたので、いくつか記事はありましたが、すっかりご無沙汰になりました。仕事を一生懸命していたのと、INTER-Mediatorの開発をがっつりやっていたのが理由です。

開発プロセスの話も、2017年2月で以降に記載がありません。かなり詳細化したのですが、詳細化し過ぎかもしれません。INTER-Mediatorでアプリケーションを作る話に持ち込みたかったのですが、むしろフレームワークを作る上での分析の方向に行ってしまった感があります。とは言え、報告はしませんでいたが、色々な角度での検討は断続的に続けていました。古い書籍ですが Object Modeling and User Interface Design あたりで、オブジェクト指向的にユーザーインタフェースを設計する方法があり、モデリングの方法として参考になるものでした。加えて、データベースをどう設計するかということも問題点としてはあるわけですが、こちらもオブジェクト指向の世界での解決策は2000年前後に一定の成果を出しており、久しぶりにそのあたりの書籍を調べて、10月にINTER-Mediatorの勉強会でワークショップをやってみたりしました。さらに、最近はプロジェクトマネジメントの世界でも注目されてきたアジャイルということもあり、現在の開発における問題点を解決に向かわせる手法として注目されており、そうしたことを全てひっくるめての「開発手法」に行きつきたいということもあって、次の方針を模索中だったりします。

2017年度から、大学の非常勤の仕事を多めに入れたのですが、初年度はやっぱり教材の仕込みが大変でした。NIIの仕事が2017年から週に3日になったので、開発の仕事は大きなことができなくなることが予想されたので、細切れな仕事が中心になりましたが、それでも、断続的には開発の仕事も続けました。ということで、余裕のない忙しさがずっと続いていたので、研究を進めるのがかなり困難でした。もっとも、研究員としてNIIで雇用されているのですが、実際の仕事はトップエスイーのシステムや運営関連のことなのでNIIの業務時間内で研究をする時間は全くありません。今年、2018年は、もう少し余裕を持って色々なことに当たれるようになりたいなとは思っていますが、今年はまあそういう状況に持ち込めない感じです。とは言え、INTER-Mediatorの方は、最優先で進めているので、進行は色々あると思います。今年もよろしくお願いします。

FileMakerデータベースをOAuth認証で利用する

一部に間違いがあり、修正しました。修正箇所は青字で記載してあります。(2017-06-17)

FileMaker 16の大きな機能アップの1つは、OAuth対応だ。GoogleのアカウントでFieMakerデータベースへのログイン認証ができるようになったのである。OAuthの大きな特徴は、1度パスワードを入れれば、その後に認証されたことが異なるサービスに対しても継続されることである。これは「パスワードを覚えていて、その都度送り出す」のではなく、認証した事実を別のサーバーにうまく伝達を行うことで、サービスをまたいだ認証の継続を実現している。パスワードのやりとりは最初のログイン時だけになるので、概してより安全な認証方法と言うべきだろう。FileMakerがOAuthにどのように対応したのかを、データベースログインをGoogleアカウントでログインできるようにするための設定を通じて説明する。

FileMakerデータベースへのログイン

FileMakerデータベースをFileMaker Serverで公開したとする。以下はINTER-MediatorのサンプルデータベースをプライベートネットワークにあるFileMaker Server 16で公開した結果を示す。上記のサンプルで改変した点は本文途中で示す。

公開したデータベースをFileMaker Pro/Advancedで開こうとすると、次のようなダイアログボックスが表示され、そして、アカウント名とパスワードを入力して、「サインイン」ボタンをクリックする。

ここで、FileMaker Server 16で、Googleを認証サーバーとして利用するような設定を行い、加えてデータベース側にそのGoogleのアカウントを追加設定すると、サインインのダイアログボックスがでは以下のように、「Google」のボタンが下部に追加される。このダイアログボックスが表示された時には、「Google」ボタンをクリックするだけでOKである。アカウント名やパスワードのテキストフィールドに、Googleのユーザー名やパスワードを入力することは不要である。

そうすると、デフォルトのブラウザが開き、Googleアカウントのログインの「アカウントの選択」の画面になる。ちなみに筆者が複数のGoogleアカウントでログインをしているのでアカウントの選択になるのだが、アカウントが単独の場合には何も出ないかもしれない。あるいはまだログインをしていないのなら、さらにパスワードの入力や場合によってはアカウントの入力も必要だろう。何れにしても、サインインのダイアログボックスで「Google」ボタンをクリックすると、Webブラウザを利用してGoogleでの認証結果を確認する。その時に、Googleのアカウントでログインしていなければログインをするが、ログインして入ればそのまま処理が継続される。

ログインが成功するか、ログインされて入れば、次の図のようなダイアログボックスが表示される。これは認証が成功したことを示しており、データベースを利用するには「FileMaker Pro Advancedを開く」(もちろん、Proの場合もある)ボタンをクリックする。なお、「開かない」にしたら、何もしないので、ここでは必ず「〜を開く」ボタンをクリックする必要がある。

そうすれば、データベースが開かれる。この時、Get(アカウント名)等の取得関数の結果もデータビューアで示したが、ログインしているGoogleアカウントのアカウント名がそのまま見えている。

以上のように全てがうまく設定された状態だと、ログインパネルで、Googleボタンをクリックすることで、パスワードをその場では入力することなく、自動的にデータベースを開き、データベースではGoogleアカウントで誰が使っているのかを識別できる状態になる。あらかじめGoogleアカウントでログインしていれば、何も追加作業は必要ないか、あるいはアカウントの選択の作業が必要になる。 ログインしていなければ、Webブラウザでログイン作業を行う。

OAuthで利用するためのデータベース

FileMakerのデータベースは、ProないしはAdvancedで管理者でログインをして、「ファイル」メニューの「管理」にある「セキュリティ」を選択する。認証を行なったのちに、アカウントの追加をまずは行う。「アカウントの認証方法」の部分には、「Amazon」「Google」「Microsoft Asure AD」の3つの選択肢が増えている。利用するOAuthサービスを選択した上で、ユーザー名は、そのサービスのユーザー名をそのまま指定する。このように、Googleであれば、Googleのユーザー名を指定したアカウントを作っておかなければならない。もし、作っていない場合は、たとえGoogle側のログインが成功していてもデータベースの利用はできなくなっている。一見すると、他のこの種のサービスのように自由にログインできないのは不便と思われるかもしれないが、登録しないと利用できないようにするのがセキュリティ確保の基本である。誰でもログインできる状態というのは、多くのFileMakerデータベースには望まれていない。

アカウントが実際に利用できるようになるには、「アクセス権セット」を選択する必要がある。ここでは既定の「データ入力のみ」を選択しているが、もちろん、このアクセス権セットに、fmappつまり「FileMakerネットワークによるデータベースアクセス」の拡張アクセス権が設定されている必要がある。これは従来からと同様で、FileMaker Serverで公開するデータベースでは必須の設定である。なお、INTER-Mediatorのサンプルデータベースでは、「データ入力のみ」のアクセス権セットには、fmappはチェックが入っていないので、サンプルをそのまま使う場合には注意していただきたい。

アカウントの一覧には、Googleがタイプの項目が増えており、アカウントの列ではGoogleのユーザー名がそのまま見えている。

FileMaker Serverでの設定

FileMakerのAdmin Consoleで作業をする。ログイン後、左側で「データベースサーバー」を選択し、右側で「セキュリティ」のタブを選択する。そこにあるポップアップメニューで「FileMakerと外部サーバーアカウント」を選択する。すると、Amazon、Google、Microsoftの3つの項目が表示されるので、右側のギアのアイコンをクリックして、作業を進める。ここでは、Googleを例にとって説明する。

Googleのギアアイコンをクリックすると、次のようなパネルが表示される。結果的には、ここでGoogle側で得られた2つのコードを入力することになるが、それは、この後に説明する。簡単なようで難しい問題もあるので、それも併せてこの後に説明する。ともかく、2つのコードが得られたら、「保存」ボタンをクリックする。

ちなみに、Microsoftを選択すると、少し違うダイアログボックスが表示される。これらはサービスごとに得られるデータが少しずつ違うと言うことだ。なお、これら3つ以外のサービスはプラグインとして追加は可能となっているが、基本的にはメジャーなサービスの場合はFileMaker社による機能追加を待つことになるだろう。自社でOAuthサーバーを立てているなら、プラグインの開発をしたくなるところだろうが、こちらはFileMaker社による情報待ちの状態だ。

設定終了後、次のようなメッセージがでかでかと表示される。つまり、FileMaker Serverのサービスを再起動すると言うことだ。もちろん、コンピューター自体を再起動してもいいが、macOS、Windowsでの作業方法が、こちらのページに記載されている。

Googleのコードの取得

Admin Consoleで設定をするには、Google側から与えられるコードを取得しなければならない。そのコードは、Google APIのところで取得を行う。以下の手順で「利用規約の更新」が出てくる場合には、もちろん、そこで対応をして進める。

Googleの場合、Admin Consoleの「データベース」のセキュリティ設定のところで出てきた「Google API Console」をクリックすると、以下のような英語のOAuth 2.0のページが出てくる。実際作業は、このページの本文の2パラグラフ目にある「Google API Console」をクリックして進める。

Google API Consoleをクリックすると、以下のページに移動する。こちらを直接開くには、Google Developer Consoleのページにジャンプすれば良い。なお、このページ内容は、それまでにこの機能を使ったかどうかによって大きく違っている。全く初めて使う場合の作業手順も併せて説明しよう。ポイントは、上部に「Google APIs」というバーが出ている点である。

Google APIsと書かれた右側の部分では、初めて使う場合には「プロジェクトを選択」と表示されるので、それをクリックする。すでに何かで利用してプロジェクトが存在する場合には、とにかくプロジェクト名が見えているのでそれをクリックする。すると、以下のように、プロジェクトの一覧パネルが表示される。パネル右上の「+」をクリックすると、プロジェクトが新たに作成される。ここで、FileMaker Server向けにプロジェクトを1つ作っておく。

プロジェクトの作成時に必要なことは、プロジェクトの名前を設定することである。名前は適当に設定する。なお、プロジェクトIDはこの後は特には使用しない。

プロジェクトを作成すると、そのプロジェクト名がGoogle APIsの右に見えていることを確認して、左側で「認証情報」を選択する。すると、「認証情報を作成」というボタンが見える。ここで、ボタンをクリックして「OAuthクライアントID」という項目を選択する。

なお、ここで以下のようにメッセージが見えているGoogleアカウントでは、必要なコードを生成する権限が与えられていない。例えば、組織で作成されたアカウントではコード生成が許可されていない場合があるので、その場合は個人でアカウントをするなどして、コード発行を行う必要がある。組織のアカウントの場合は、その組織の管理者が、クライアントIDの発行を制限していることが一般的な原因だろう。

 「OAuthクライアントID」を選択した後、同意画面の作成を促す表示が出てくれば、それに従って以下のページで必要な情報を入力する。本来はこの「同意画面」がユーザーに示されて、そしてサービスを利用できるようにするという流れをOAuthでは採用している。しかしながら、FileMakerではこの同意画面を利用していないようで、「ユーザーに表示するサービス名」だけを設定して「保存」ボタンで保存すれば良い。

その後にアプリケーションの種類を選択するページが表示される。ここでは、「ウェブアプリケーション」を選択する。すると、名前などを入力する項目が表示される。ここで、名前は適当に設定するとして、もう1つは「承認済みのリダイレクトURI」を入力しなければならない。このURLは、例えば、FileMaker Serverに接続するためのホスト名が「fmstest.msyk.net」ならば、「https://fmstest.msyk.net/oauth/redirect」を指定する。ホスト名の部分だけがサーバーによって違い、他の部分はどのサーバーでも同様だ。なお、:443はあってもなくても良い。ちなみに、ここにmacOSの共有名(Macintosh.local)や、IPアドレスではうまく動作しない。ドメインを含む利用可能なホスト名をきちんと設定し、そのホスト名でサーバーに接続できる環境になっていなければならない。

「作成」ボタンをクリックすると、生成されたコードがパネルに表示される。こちらからコピーして、Admin Consoleの該当するフィールドにペーストすれば良い。なお、コードは後からでも参照は可能である。

うまくいかない場合の対処

手順は以上の通りだが、FileMakerのドキュメントにも書いてある通り、FileMaker Serverを、きちんとしたドメイン名のURLのホストで公開する必要がある。macOSの共有名の場合、ブラウザからのアクセスが正しくできない場合もある。IPアドレスだけではhttpsでアクセスしているはずはないので、Googleの側で登録が進まない。自分でドメインを持っている方は、何らかのテスト項目を作るなどしてともかくドメイン名を含むホスト名を用意する。

例えば、サインインのダイアログボックスで、Googleボタンをクリックした場合に次のようなページが出たとする。ここで詳細を表示すると、redirect_uriに見えるように、https://MacBookPro.localというホストにアクセスしようとしている。もちろん、この名前は共有名である。ブラウザでは共有名でもOKのはずなのにと思うかもしれないが、単にそのURLにブラウザからアクセスするのではなく、裏ではもっと色々複雑なことを行なっている。筆者の場合には、msyk.netというドメインを所有しているので、fmstest.msyk.netが利用できるようして、検証を行なった。IPアドレスは、実は10.0.1.102というプライベートアドレスだが、自宅環境ではそれで運用可能なので問題はない。

ここで、上記のrequest_uriのURIがどのように自動生成されるのか分からず、対処がなかなかできなかった。実際には、FileMaker Pro/Advancedがrequest_uriを「サーバーへ接続した時に使うホスト名」から生成しているようだ。macOSの場合、自動的にBonjour名が左側に出てきてアクセスをしがちであるが、それだと、上記のrequest_uriには共有名が含まれてしまう。サーバーのドメイン名(つまりFQDN)で接続するサーバーを選択できるように、例えば、お気に入りのホストにドメイン名を登録して、そこからデータベースを選択して開くようにすれば良い。以下の図のように、fmstest.msyk.netでデータベース選択ができるように、お気に入りのホストの登録を行なった。もちろん、自動的に識別される名前がホスト名であれば、それを選択すればOKである。

OAuth対応をどう考えるか

以上のように、Google側の使いこなしが必要になるものの、OAuth対応は確かに便利だろう。アカウントそのものの管理を外部に任せることができるのである。ただし、社員全員がGoogle Appsなどでアカウントを持っていれば便利は便利なのだが、データベース個別にそれぞれのアカウントを登録しなければならない。これは、テキストファイルで読み込みはできないため、自動化のスクリプトなどを使用することになると思われる。ともかく、Googleにアカウントを作ればデータベース側を変更しなくても新しいアカウントから使えるようになる…と言う状況は作れない。機能としては素晴らしいが、運用を考えた時に、手間になる部分も見えてくる。ログインしたアカウントのドメイン名がある名前であれば、自動的に登録されて定義されたアクセス権セットを利用するような仕組みがあることで、管理負荷を軽減できると考えられる。

FileMaker Data APIもOAuth対応している。その意味ではWeb対応しているのだが、WebDirect経由ではOAuth対応はなされていないこれは先のバージョンを待つしかないだろう。WebDirectについては当初は対応していないと記載していたが、GOからのアクセスも含めて対応はしている。エミックの松尾さんに指摘をいただいたが、恐らく正しい証明書であればHTTPSであればOAuth認証ができ、自己署名の証明書であればできないということではないかと思われる。なお、http://…だと、Googleで登録ができなかった。この件、簡単に検証ができないのではあるが、手元で検証した時の違いとなると署名書の違いしか考えられない。

[開発プロセス#8] 画面要素に関するモデル記述の試案

前回より少し間が空いてしまった。また、タグをきちんとつけていなかったのを直した。

ロバストネス図やコラボレーション図を作るとき、バウンダリー、コントロール、エンティティの3種類に分類することは、図の中の各要素の役割を考える上で必要かつ多すぎない点から、やりやすい方法ではある。しかしながら、1つの問題は、バウンダリーの表現力が低いことである。「一覧画面」や「何か操作をする」という大まかな1つのアイコンがあるのがよく見られる作図結果である。この記述をまずは詳細化できないかを考えてみる。ここでは、モデルとして、クエリー結果の一覧があり、その一覧の中に各行に対するボタンがあり、その一覧とは別にテキストフィールドやボタンなどのフォーム要素が並んでいるような状況を考える。フォーム要素は、一覧に対する検索条件を当たるものや、あるいは一覧にレコードを追加するものなのが考えられるが、動作は違うものの要素としての構成は同じようなものと見ることができる。

まず、これらのすべての要素を含むWebページが、コントロールから生成されたことを明確に示す必要がある。一方、ページ内部のコンポーネントのうち、単に表示するようなものについては、そこからコントロールを呼び出されることはないので、図の中で特別な記述は不要である。一方、ボタンなどのフォーム要素や、あるいはイベントを受け付ける要素については、それぞれが別々の動きをするので、その点が記述できなければならない。ICONIXの手法を解説したダグ・ローゼンバーグらの書籍『ユースケース入門 ユーザマニュアルからプログラムを作る』では、次の図のような記述を行なっている。つまり、バウンダリーの中で、特別な動作を行うような要素もやはりバウンダリーであるが、画面全体は画面の一部の集約(コンポジション)としている。図中の点線枠に入っている部分が、1つの画面を構成するバウンダリー群となる。なお、一覧表示の各行に「詳細表示」ボタンがあるとすれば、UML的記述をするには多重度の記述を行うことで、複数存在することが示すことができる。この点は書籍には明示されていない。

画面要素を分離

ここで、実際に開発をする場合に必要な情報が込められているかどうかを検討する。この図にない要素としては、ページが一覧と検索領域に分かれていることや、一覧にどんなフィールドが表示されるのかといったような内容である。これらを含めて記述するとしたら、次の図が得られる。画面の領域を、「一覧表示」と「検索条件入力領域」の2つのサブシステムで表現し、それらのサブシステムは「一覧表示画面」の集約であるとした。一覧表示は、通常は「ヘッダ」「内容」「フッタ」の3つの領域を持つのは、HTMLの定義からも明確である。一覧表示のサブシステムはこの3つの要素が常にあるものとして最初から配置されているとする。「内容」については、繰り返されるのであるが、UML上での一般的な表現はないので、repatingというステレオタイプを付与することにする。この場合は、一覧のないように「名前」と「住所」フィールドが配置され、それぞれの行には該当するレコードに対応する「詳細表示」ボタンが組み込まれることを意味する。

画面要素を分離_0

このようにUMLの記述を拡張することで、画面構成も含めたモデルの記述ができるようになる。しかしながら、画面を構成する要素については、その実物を想像しやすいようなアイコンにすべきと考える。

[開発プロセス#7] 開発対象システムのモデル記述

システム開発でモデルを作成することにより、これから作るシステムが要求に合致したものであるのかといった側面の検討だけではなく、効率の良い実装が可能であるのかといった側面や、予想される改変や拡張に対して実現可能性やその効率性、テストのしやすさなど、実装に直結すること以上に利用できる。しかしながら、その作成するモデルは、様々な手法がある。要求の記述という点ではユースケース図とユースケース記述が出発点にはなるが、データベース主体の開発だと、ここでER図の作成を主体にすることが多い。データベースの構造は対象ドメインの状況を記述できるようになっている必要があるのだが、その結果、全てがデータベースの設計結果であるスキーマに集約されているという見方をしてしまいがちである。ある作業を、スキーマで解決するか、あるいは実装するプログラムで解決するかはもちろん考えるのではあるが、では「ここの処理はプログラムで」というアイデアはER図やクラス図では不明確である。メモを残すなどの工夫が必要になる。

一方、Webシステムではワイアフレームといったざっくりとした画面のデザインをもとに、画面遷移を定義することで、システムの全体像を示そうとする。しかしながら、画面デザインが反映するのは、システムへの実装以前にドメインに対して実施される分析をもとにして作成されるビジネスモデルであり、実装に直結したER図等のモデルからのズレが生じする場合もある。しかしながら、HTMLでの動的なユーザーインタフェース作成機能は限られていたので、例えばチェックボックスであればどういう動作をすべきかということを逐一記述しなくても、半ば「常識的な判断」で進めることであまり大きなブレは発生しなかった。さらに、結果的にビジネスモデルとER図で記述されるスキーマとはあまり変わらないことお多いので、HTMLのモックアップが「設計」として扱うのは、デザイン主体の開発会社では頻繁に見られる方法である。

このように、ある程度のスキルや、ワークフローができてくると、途中を省略する傾向は強く、単一の会社でそれが回っている間は特に問題視はされないだろう。しかしながら、Webの世界は変化が激しい。特にここ5年くらいの時期はクライアントサイドの作り込みの度合いが高くなり、ユーザーインタフェースは複雑化している。その結果、Webのクライアントサイドは多階層的な機能分離を図る必要が出るなど、スマホのクライアントのネイティブアプリケーションに近い構造になっている。

こうした状況が変わってきた時、ワークフローを見直す必要があると考える。今までの知見や常識として暗黙知的に取り扱っていた知識だけでは、新しい問題に対する解法がない可能性が高く、最適な設計ができなかったり、チーム内での意識の疎通が悪くなる。そのために、本来的な詳細なモデルを記述するということが必要なのである。そこを出発点にして、省略やあるいは詳細化をするとしても、Webシステムのモデル記述の手法を一定のレベルで確立する必要があると考える。

UML自体の汎用性は高く、その点では有用性も高いのは事実である。しかしながら、UMLやその周辺手法を使ってWebシステムの記述をするにあたり、次の点に対して何らかの解決策が必要と考える。

  1. 詳細化するとき、明確なルールは特にない
  2. クラス図を主体にすると、オブジェクト指向が前提となる
  3. ボックスがクラスやオブジェクトで、呼び出しが矢印線的な切り分けによる分かりやすさはあるが、処理の記述では呼び出し線に名称を書くことになり、図を見やすく作ることが困難になりがちである

まず、1の詳細化についてである。作成したモデルと、使用するフレームワークの提供機能を比較検討して、実装箇所を特定するには、極端に言えば、プログラムの1行レベルまでを、モデル内の1つの要素として記述することも必要とされる。また、ロバストネス図やシーケンス図では「画面」を1つの要素として扱うが、実際に処理の流れを追う場合、ボタン1つ1つは原則として異なる動作をするので、ボタン1つ1つを要素として表したいということになる。このための指針が費用である。

2つ目のオブジェクト指向である点は、Javaのプログラムだけを作るような場合には確かに有効ではあるが、HTML、CSS、JavaScriptが絡む世界では必ずしもオブジェクト指向ではない。つまり、クラスやオブジェクトを1つの単位として考える場面は実装時にはあるかもしれないが、分析時にはどちらかと言えば、より細かい単位での要素を記述したい。最終的にはメソッドが集まってクラスになるとしても、対象としたのはメソッドであり、その中でどんな処理をしたいかということである。

3つ目は、コミュニケーション図でオブジェクトからオブジェクトに線を引き、線に添えてメッセージ呼び出しを記述する。この方法は実体あるいは実体化可能なものはボックスであり、メッセージは矢印線であるという明確な分類があるものの、簡単なモデルでも、オブジェクトとメッセージを見やすく配置するのはかなり大変である。ましてや、複雑なモデルだとなおさらである。ここではメッセージの記述が作図作業を煩雑にしている点は明白であり、それに代わる表記方法を検討すべきであると考える。

これらの懸案をまずは見える範囲での解決を行った上で、Webシステムのモデルを記述することにする。まず、1〜3に対する提案を次回より行う。

 

[IM] クロステーブルの作成

INTER-Mediator Ver.5.4-devでは、クロステーブルの作成ができるようになっています。ここでのクロステーブルは、表があって、いちばん上の列と、いちばん左の列がラベルとなっており、そのラベルの交差するセルには、ラベルに関連するデータが表示されるというものです。例えば、いちばん上の列には自社の「支店」が並び、いちばん左の列には年月が並ぶとすると、その交差するセルには、特定の支店の特定の年月の売り上げが見えるというものです。サンプルファイルはSamples/Practice/crosstable.htmlおよびcrosstable.phpにあります。

まず、クロステーブルを作るには、3つの異なるコンテキストを定義します。1つは列見出し(以下のコードではitem)、1つは行見出し(以下のコードではcustomer)、そして交差するセルに設定されるデータのコンテキスト(同じくsalessummary)です。列見出し、行見出しのコンテキストについては通常と変わりありません。また、列か行かの区別も、定義ファイル内では設定しなくても構いません。行列の見出しのコンテキストでは、検索条件や並べ替えフィールドの指定などももちろん可能です。以下の例では、元のデータが多いこともあるので、意図的に絞り込んでいます。交差するセルのコンテキスト「salessummary」では、relationキーの指定を必ず2項目行います。1項目は列見出し、2項目目は行見出しとの関連付けになります。item、customerともに、主キーはidフィールドです。これに対応するsalessumarryコンテキストのフィールドはitem_idとcustomer_idです。すなわち、列見出し、行見出しの対応するレコードとのリレーションシップを利用して、交差するデータの配置を決めています。

 array(
   'name' => 'item',
   'table' => 'dummy',
   'view' => 'item_master',
   'records' => 100000,
   'maxrecords' => 100000,
   'key' => 'id',
   'query' => array(
     array('field' => 'id', 'value' => 25, 'operator' => '>='),
     array('field' => 'id', 'value' => 35, 'operator' => '<='),
 ),
 'sort' => array(array('field' => 'id', 'direction' => 'asc')),
 ),
 array(
   'name' => 'customer',
   'table' => 'dummy',
   'view' => 'customer',
   'records' => 100000,
   'maxrecords' => 100000,
   'key' => 'id',
   'query' => array(
     array('field' => 'id', 'value' => 250, 'operator' => '>='),
     array('field' => 'id', 'value' => 259, 'operator' => '<='),
   ),
   'sort' => array(array('field' => 'id', 'direction' => 'asc')),
 ),
 array(
   'name' => 'salessummary',
   'table' => 'dummy',
   'view' => 'saleslog',
   'records' => 100000,
   'key' => 'id',
   'relation' => array(
     array('foreign-key' => 'item_id', 'join-field' => 'id', 'operator' => '=',),
     array('foreign-key' => 'customer_id', 'join-field' => 'id', 'operator' => '=',),
   ),
 ),

ページファイルのクロステーブルの部分は、2セルずつの2行の表として作ります。それよりも多い場合や少ない場合はダメで、要するに2行2列のテーブルを必ず用意します。そして、エンクロージャーになるtbodyタグのdata-im-control属性を「cross-table」とします。これら4つのセルと2つの行は取り除かれ、初期状態として、TRタグに左上のセルを入れた状態にします。この左上のセル内部は、ページファイル側での定義通りにレイアウトされます。

fig16

 <table>
 <tbody data-im-control="cross-table">
 <tr>
   <th></th>
   <th>
     <div data-im="item@id"></div>
     <div data-im="item@name"></div>
   </th>
 </tr>
 <tr>
   <th>
     <div data-im="customer@id"></div>
     <div data-im="customer@name"></div>
   </th>
   <td>
     <div data-im="salessummary@qty"></div>
     <div data-im="salessummary@total"></div>
   </td>
 </tr>
 </tbody>
 </table>

続いて、1行目のTRタグをエンクロージャーに、そしてページファイルにあった右上のセルをリピーターとして、ページ合成を行います。つまり、このBのセルには、列見出しになるコンテキストの名前と、データベースから得られるフィールド名をdata-im属性として持つターゲットノードを記述しておきます。その結果、データベースアクセスが発生し、この場合はitemテーブルから一部のレコードを取り出して、それらを列見出しとして並べます。

fig17

さらに行見出しの処理になります。今度は、TBODYタグをエンクロージャー、そしてTRタグにページファイルの左下のセルを入れたものをリピーターとして、ページ合成を行います。つまり、行見出しだけをまずは作成します。

fig18

ここまでは、エンクロージャーとリピーターの違いはありますが、通常のページ合成と同じです。クロステーブルでは、ここで、次の図のように、交差する部分のセルに、一旦、ページファイルのテーブルの右下のセルを全て並べます。そして、コンテキストに応じたデータベースアクセスを行い、交差する部分に入るデータがあれば、対応するセルに値を設定します。列見出しあるいは行見出しに登場しないレコードと対応するものは無視されます。

fig19

サンプルの出力結果は以下のようなものです。2つのセルにしかデータは入っていません。なお、ここでの交差するセルに対応したコンテキスト内に、同一のセルに対応するものが複数ある場合には、中途半端にマージされます。コンテキスト内は、例えばSQLのビュー等を使うなどして、1つのセルに対応するレコードは0ないしは1個になるようにしてください。

shot3220