FileMaker Cloud残念ながら稼働せず

昨夜というか未明にインスタンスを作りました。ヘルプによると、メールがきて、そこにセットアップするためのページを表示するリンクがあるのですが、昼過ぎてもメールは来ません。なるほど、そうやって、US/Canada以外には使わせないようにしているのか!というところです。多分、Amazonの顧客情報のリージョンによって、メールの発行をコントロールしているのでしょう。FileMaker CommunityではすでにCloudの話題が流れているので、USの利用者は使用を開始しています。ヘルプ画面を見るしかないので、FileMaker Cloud Supportのリンクを紹介しておきます。

ここからは想像です。セットアップの画面のヘルプを見ると、Amazonのアカウント番号、そして自分で決めるホスト名などを入力します。どうも、自分自身のインスタンスへのアクセスURLは「ホスト名」を含むURLとして決められるみたいです。Amazonのアカウントを知らせれば、背後でどのインスタンスが未セットアップなのかは分かります。ヘルプを見ると、「FileMaker Cloud」というシステムがAWS内で動いているようです。Cloud利用可能なユーザーに対して、そのユーザーのインスタンスとは別のセットアップシステムで入力すると、ターゲットとなるインスタンスに対して変更を行うような仕組みになっているのだと思われます。したがって、セットアップのURLをメールで知らせてもらわないと絶対にわからないし、知らせてもらったとしてもAmazonの顧客情報を付き合わせれば、未提供のリージョンであれば何もしないというどうさになるのかもしれません。

そんなわけで、残念ながら、日本のユーザーはインスタンスのセットアップまでしかできないということになります。

FileMaker Cloudまだ使えず

EC2にインスタンスを作ったら、メールが来て、最初のセットアップができるようにヘルプには書かれています。しかしながら、1時間ほど待った今、まだ来ません。ということで、もう少し追加情報や検討ポイントを書いておきます。ちなみに、英語のサイトでは、Cloudのマニュアルページがすでに用意されていました。

まず、インスタンスを作った時に自動的に作られるセキュリティグループにファイアウォールの設定がありますが、「インバウンド」を見ればわかりますけど、ちゃんとFileMakerのデータベースのポートである5003が開いています。80, 443はいいとして、SSHは開いていません。しかしながら、編集ボタンを押して、SSHを追加すれば、通常の手順でSSHに接続できます。接続方法はコンソールのインスタンスで「接続」ボタンをクリックして確認できますが、デフォルトのユーザー名は「centos」であってrootではありませんので注意しましょう。当然ながら、インスタンスを作った時にキーファイルが作られてダウンロードしていると思いますが、こちらもアクセス権をmacOSだと600にするなど、sshの作法に従って作業をします。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-28-1-01-16%ef%bc%882%ef%bc%89

SSHで接続してみて見ると、Apacheもnginxも上がっていません。しかも、TCPで1つもポートが開かれていない。この状態ではデータベースはもちろん、外部から接続のしようがないように思います。それにヘルプに書かれた「メール」がない状況を考えて、がっつり推測ではありますが、この状態でなんらかのアクティベーションをFileMaker側で行うのではないかと考えました。どうでしょう。従来のライセンスを使う場合だと、FileMaker Storeでアクティベーションするのだから、なんらかのアクティベーションがあるのは確実ではないかと思った次第です。とすれば、確かに日本の顧客であればアクティベーションをしないという対処も可能かもしれません。ですが、これは推測です。

さて、ライセンスです。作業中に見えた別のページを見ると、Amazonに対してAMIの利用料を年間で払うプランもあるようです。これだと、年間880ドルだから、FileMaker ServerのAVLAより高いけど、まあべらぼうに高いわけではありません。これまで通り、FileMaker社から購入したライセンスでも、Amazonに対して年間あるいは時間で課金した料金でも支払えるようになっています。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-28-1-13-00%ef%bc%882%ef%bc%89

ちなみに、FileMaker Server 15は当初は、Windows ServerかOS Xでの運用しかできなかったのです。Linuxで稼働するサーバーは皆が(特にSI関係者は)熱望していたと思います。FileMaker 5.5のサーバーではLinux版もあったものの、FileMaker 7でWindows/Macだけになって10数年経過して、Linux対応していたのも忘却の彼方です。

サーバーなのでLinuxで稼働させるのはそんなに難しい話ではないと思いますが、おそらくLinuxで稼働させるとなると無数のディストリビューションがあることから、サポートコストがかさむことを懸念したのだと思われます。しかしながら、Amazon EC2のAMIで提供すれば、プラットフォームはAmazonだけだし、課金のシステムも完備です。サポートは最小限になるし、きちんとライセンス料を取れる仕組みであることを考えれば、仕組み自体は非常にうまく考えられています。

FileMaker Cloudのバージョンは、「FileMaker Cloud 1.15.0」となっています。1.がついている。FileMaker Pro/GOは15.0.2を使えとなっています。FAQを読むと、書き込み権限があるのはDocumentsフォルダなど限られており、サーバーサイドのスクリプトには注意が必要でしょう。といいつ、これはMacOSでは同様でした。スケジュールスクリプトが組めないというのも注意が必要でしょう。今後、アップデートでできないこともできるようになって欲しいものではありますが、ともかく、カスタムWebが動くようにして欲しいです。新し目のXMLスキームだけでもいいですから。

FileMaker Cloudが出たぞ!

突然、FileMaker Cloudがリリースされました。FileMaker Server 15のクラウド版ですが、Amazon Web Serviceで稼働するFileMaker Serverです。CentOS 7ベースです。なんと、カスタムWebは動かないので、INTER-Mediatorでは利用できません。他に、LDAP/Active Directoryのアカウントでのログイン機能もありません。ESSはサポートはしますが、ドライバが非対応ということはちょっと簡単ではなさそう。その他諸々いろんなチェックポイントがあります。

しかし、よく見ると、「FileMaker Cloud is currently only available in the United States and Canada.」と書かれている。日本のお客様はお預け〜!? ってことではいさようならとは行きません。AWSでどうやって日本からのアクセスを切るのかいなと思いつつ、AWSにログインして、リージョンを「バージニア北部」にします。そして、EC2のインスタンスを作って見るわけですが、ここで、AWS Marcketplaceを選択してFileMakerで検索すれば、あらあらちゃんと出て来ますね。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-28-0-29-05%ef%bc%882%ef%bc%89

一番規模の小さいのを選ぶと、ちゃんと値段もわかります。この「時間課金」というのはAWSでの一般的な課金方法です。FileMaker社からライセンスを買わなくても、時間課金ができるとは言え、よく見てください。最低の構成でも1時間が1ドル強、上がっても1.229ドル/時間。要するにアマゾンの費用に比べてFileMakerのライセンス料が異様に高いのです。月間30×24=720時間として、732ドル、ということで、月間7〜8万ほどかかります。まあ、こちらを選ぶ人は少ないでしょう。FileMakerからライセンスを買って使ってください。なお、その場合、AMIの選択肢が違います。ライセンスを自分で持っている(BYOL)人向けのAMIがあったりします。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-28-0-33-22%ef%bc%882%ef%bc%89

ここで、「お金を払っても試して見るか」と腹をくくったのですが、よく見ると、15日はフリーライセンスということで、Amazon側のEC2使用料のみで、15日は使えます。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-28-0-35-36%ef%bc%882%ef%bc%89

そういうわけで、なぜ日本では「入手できない」となっているのか?AWSは全世界に共通のサービスをしているのだから、昔の代理店ビジネスのようなことは最初からできるわけがないことは明白なのにどういうことでしょうね。

ということで、操作等より詳細を知りたい方は、インストール後に出て来たヘルプのページをご覧いただくと早いでしょう。

第1弾は以上!

Server.appとFileMaker Server 14を共存させる

FileMaker Serverのアップデータが途中で止まる件は、こちらのページにまとめました。FileMaker Serverは、自身でhttpdコマンドのプロセスを起動するため、アップデータを適用するためにプロセスを止めた状態でないと処理しないのはいいとしても、FileMaker Server以外のサービスがhttpdを起動していても、やはりアップデートは進まず、そこで単なるシェルスクリプトによる繰り返しでhttpdのプロセスがなくなるまで待ってしまい、フリーズのようになってしまうという状況です。

OS X 10.11にServer.app Ver.5を入れた状態で、一度Webサービスを起動し、その後停止した状態を見ることができたので、記録しておきます。FileMaker Serverのプロセスを完全に落としても、以下のような2種類のhttpdのプロセスが残っています。-fオプションで指定されている設定ファイルを見れば、だいたいどんな機能のものなのかはわかります。

$ ps -ef|grep httpd
0 235 1 0 4:14PM ?? 0:00.47 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
70 358 235 0 4:14PM ?? 0:00.02 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
70 359 235 0 4:14PM ?? 0:00.06 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
70 360 235 0 4:14PM ?? 0:00.11 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
70 361 235 0 4:14PM ?? 0:00.06 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
70 362 235 0 4:14PM ?? 0:00.02 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
0 472 1 0 4:14PM ?? 0:00.35 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/apache2/services/ACSServer.conf -E /var/log/apache2/services/ACSServer_error_log
70 476 472 0 4:14PM ?? 0:00.02 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/apache2/services/ACSServer.conf -E /var/log/apache2/services/ACSServer_error_log
70 20919 235 0 5:36PM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND -f /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf -E /private/var/log/apache2/service_proxy_error.log
1026 28116 27955 0 5:57PM ttys001 0:00.00 grep httpd

apache_serviceproxy.confは文字通りプロキシで、通常のWebサービスやWikiなどのサービスを受け付けてプロセスに流すような設定になっています。つまり、リバースプロキシでしょうか。

ACSServer.confの方は、いろいろ見ていると、/AccountsConfigService/api/とかいったパスが出てくるので、ACSはAccounts Config Serviceだと思われます。いろいろな設定を追いかけると、/Applications/Server.app/Contents/ServerRoot/usr/libexec/scsdのプロセスがデーモンとして起動しているようで、それに対するWebインタフェースをApacheを使って稼働させている模様です。man scsdはきちんとドキュメントが表示され、「Accounts Config Service Daemon」とタイトルにあります。細かなことはわかりませんが、Webアプリケーションとして動くサービスとなっています。

何れにしても、これらのサービスが稼働していれば、FileMaker Serverのプロセスは起動しません。httpdを利用するサービスを全てなくすには、次のようなコマンドを打ち込みました。

$ cd /Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons/
$ sudo launchctl unload -w com.apple.serviceproxy.plist
$ sudo launchctl unload -w com.apple.service.ACSServer.plist

Server.appはいろいろな機能がありますが、Webサービスはもちろん、事実上はWebアプリケーションであるカレンダーやWikiなどの機能を一切使わないのなら、上記のようにしてリバースプロキシとACSServerはなくてもおそらくは問題ないと思われます。Server.appを、AFP/SMBのファイルサーバーとして、そしてTime Machineのサービスとして、さらにOpen DirectoryのMasterとして使う限りでは、上記のサービスを落とした状態でも利用できています。

ただ、これらのサービスは単純に「落としても構わない」とは言い切れないですし、皆さん自身が判断してください。ともかく、Server.appとFileMaker Serverを同時に使う場合には、Server.appのWebあるいはApacheを使っている一切の機能を使わないでおくようにするしかないと思います。ちなみに、聞くところによると、FileMaker社のサポートに問い合わせると「Server.appはアンインストールしろ」と言われるらしいです。それもどうかと思います。事実上、同じ会社の製品なんですけどね。

FileMaker Serverのアンインストール

FileMaker Serverをどうしてもアンインストールしたい場合があります。インストーラが「先にアンインストールしないといけません」とメッセージを表示して、それ以上進めないとなると、仕方ありません。インストーラのExtraフォルダに前のバージョンのアンインストーラがありますが、こんな場所にも、現在インストールされているFileMaker Serverのアンインストーラがあることを知っていれば、便利かもしれません。

shot3216

ディスクのルートから、ライブラリ>Application Support>FileMaker>FileMaker Serverという場所にも、アンインストーラがあります。ご参考までに。

FileMaker Serverのアップデータがフリーズする理由

FileMaker Server 14.0.4bのアップデータがリリースされました。このところ、アップデートが頻繁にありますが、いざアップデートしようとすると、最初の部分でフリーズしてしまうことがあります。フリーズと言っても、マウスカーソルがレインボーになってしまう現象です(画面ショットではレインボー状態は撮影できないので、以下の図は普通のポインタになっています)。

shot3215

ちなみに、この現象は、14.0.4bのアップデータに限らず、13のアップデータでも発生することがあります。もちろん、いつまで経ってもこのまま進みません。さて、なんででしょうか? アクティビティモニタを見ると、パッチアプリケーションのCPU稼働率が100%近くになっています。ということは、本当にフリーズか、適切でない処理待ちをしていることが考えられます。

そこで、ターミナルを起動して、プロセスを見てみます。パッチアプリケーションのプロセスには「Patch」という特徴的な文字があります。以下のコマンドで、プロセスIDは27530だとわかります。(以下、コマンドラインの出力が長いので折り返して見えるようにしておきますが、見づらい点はご容赦ください。)

$ ps jax|grep Patch
root 27530 1 27523 0 0 S ?? 0:15.60 /Volumes/FileMaker Server 14.0.4b Patch 1/FileMaker Server 14.0.4b Patch.app/Contents/MacOS/FileMaker Server 14.0.4b Patch

次に、このプロセスが別のプロセスを起動していないかをチェックします。すると、以下のように、「/bin/sh /Users/msyk/Library/Application Support/1358455 0」なるプロセスがあります。最後の方の数値は起動ごとに違うものがつけられ、正常終了すると消されているファイルです。

$ ps jax|grep 27530
root 27530 1 27523 0 0 S ?? 0:15.60 /Volumes/FileMaker Server 14.0.4b Patch 1/FileMaker Server 14.0.4b Patch.app/Contents/MacOS/FileMaker Server 14.0.4b Patch
root 27545 27530 27523 0 0 S ?? 0:00.05 /bin/sh /Users/msyk/Library/Application Support/1358455 0

これは/bin/shつまり引数をシェルスクリプトとして実行しているということです。catコマンドで、ファイルパスにスペースがあるのでダブルクォートで囲むなどの対処をして、中身を読んでみます。パッチアプリケーションは、このプロセスが終了するのを、おそらく単なるループで待っているためにフリーズするのでしょう。psコマンドである種のプロセスが存在するかどうかを2秒ごとにチェックし、調べているプロセスがなくなれば、スクリプトを終了します。

$ cat “/Users/msyk/Library/Application Support/1358455”
#!/bin/sh

cd /Library/Application\ Support/FileMaker/FileMaker\ Server
./launcher -stop

while [ “`ps auwwx | grep -e fmserver_helperd -e fmsib -e fmslogtrimmer -e fmxdbc_listener -e fmsased -e httpd | grep -v grep`” ] ; do
sleep 2
done

whileの行を見ると、psコマンドの結果に、fmserver_helperd、fmsib、fmslogtrimmer、fmxdbc_listener、fmsasedという文字列があるかを調べています。つまり、FileMaker Serverの様々なプロセスが起動した状態なのかを調べています。さらに、httpdというプロセスまで存在するかを調べています。アップデートは、FileMaker Serverを停止させて行うようにということで、FileMaker関連のプロセスがなくなっているという条件はまあいいでしょう。ちなみに、FileMaker Serverのプロセスを事前に全部止めておくには、以下のコマンドでできます。

sudo launchctl unload /Library/LaunchDaemons/com.filemaker.fms.plist

しかし、httpdとなると、何らかのきっかけで動かしてしまっているかもしれません。あ!そういえば、Server.appで色々試したぞと思ってチェックすると、Server.appのソフトウエアアップデート、キャッシュ、Xcode Serverあたりがhttpを使っていました。しかし、Server.appは、それらのプロセスをオフにしても、httpdの稼働を止めません。仕方ないので、sudo launchctl unload <plistファイル>で順次落として、やっとFileMaker Serverのアップデータが動くようになりました。ちなみに、こうしたデーモンは、launchctlで起動しているので、killしてもすぐに再起動されます。そこで、/System/Library/LaunchDaemonsや、/Library/LaunchDaemonsに該当するファイルを探すわけですが、Server.appについては、/Applications/Server.app/Contents/ServerRoot以下の、/System/Library/LaunchDaemonsや、/Library/LaunchDaemonsにあるplistファイルを利用してデーモンを起動しています。これらのファイルから該当するhttpdを起動しているものを探して落とさないといけません。チェックすべきplistファイルのある場所は文中に記載しましたが、見づらいでしょうから以下に列挙します。

/System/Library/LaunchDaemons
/Library/LaunchDaemons
/Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons
/Applications/Server.app/Contents/ServerRoot/Library/LaunchDaemons

しかし、一番の問題は、「httpdが起動していたらアップデートをしない」という仕様です。つまり、結果的にFileMaker Server以外のhttpdの起動を許さないという仕様に問題があります。Server.app自体が色々なサービスでhttpdを使うのですが、80番ポートの取り合いになるのは確かにまずいでしょう。しかしながら、FileMaker Serverのインストーラーは、自分自身のhttpdのポート番号を指定することで、他のサービスとの同居の可能性を探っています。しかし、このスクリプトを見る限りは、「FileMaker Serverが起動したhttpd」ではなく、単に「名前がhttpd」のプロセスを探しているにすぎません。つまり、FileMaker Server以外でhttpdを使いっていればトラブルが発生する仕様なのです。これでは仕様の上で矛盾があると言えるでしょう。

もちろん、特定のサーバーではFileMaker Serverしか動かさないという前提でもそれはそれで構わないと思いますが、だったら、LinuxのVMで動かすようにして欲しいというのが総意ではないでしょうか。OS XとWindowsで、アプリケーションみたいなインストーラでセットアップするサーバーはもはや古さを感じます。現在のシステム構築環境にマッチしない仕様を早く改善しないと、先頭集団からさらに引き離されるでしょう。

FileMakerのWebビューアが、WebDirectで文字化け

最近ブログ更新していないので、小さなネタですが書いておきます。私がWebDirectの話をするのは予想外かもしれませんが、ちょっとハマったことがあったので書いておきます。FileMakerでのソリューション内で、複数の文書を並べるような機能が必要だったので、Webビューアを使いました。全文字を平面上に成り行きでレイアウト出来るので便利です。Webビューアには、dataスキームを利用して、フィールドの値などを合成したHTMLを与えてWebビューアに表示しました。FileMaker Pro上ではもちろん問題ありません。しかし、WebDirectでWebビューア部分が文字化けしました。理由はフォントではなく、文字セット指定がなかったからです。そこで、

data:text/html;charset=utf8,<!DOCTYPE html><html><head>
<meta http-equiv='X-UA-Compatible' content='IE=Edge,chrome=1'/>....

のように、charsetを入れればブラウザ上では文字化けは無くなりました。charsetを省略すると、us-asciiと同じになるそうですが、それはブラウザ上だからかと思われます。FileMaker Proでは指定なしでも文字化けないようにしているということでしょうね。

FileMakerのスクリプトで実現するインジェクションもしくはアスペクト指向

アスペクト指向プログラミング(AOP)はオブジェクト指向の世界での手法の1つですが、FileMakerでのスクリプトでそれを実現する方法が見つかったので、記事で残しておきます。AOPについては後ろの方でまとめて、まず、何を実現したかを具体的に説明しましょう。

マスターテーブルからの選択結果を記録する

データベースに次のようなリレーションシップを定義しています。フィールドmemoとtermはテキストで、後のフィールドは数値型です。_idの付くフィールドは連番数値を自動入力して、主キーフィールドととします。

shot3094

あるレイアウト(User Inteface)は、テーブルオカレンスのUI_Mainのレコードを表示させるように定義しました。そして、リレーションシップの先の2つのテーブルオカレンスを、3つのポータルに表示しています。このデカルト積を使うリレーションシップにより、Selectionsテーブルのすべてのレコードがポータルに表示されます。FileMaker 13からサポートされたポップオーバーボタンで選択入力をするときに、このようなリレーションシップを利用するのが1つの典型的なパターンではないでしょうか? ポータルには3つのボタンがありますが、それぞれ概ね同じ目的です。例えば、最初のポータルでは、ポータル内でのボタンを押したレコードに対応するselection_idフィールドの値が、select1フィールドに入力されます。その動作を3通り考えることで、AOPに迫るというのが概要です。当然、実際のソリューションでは主キー値となる連番はユーザーに見せないように作りますが、ここでは動作が一目瞭然となるように意識的に通常のソリューションでは見せない内容をレイアウトに表示して動作をチェックします。Memoフィールドの左側のClearボタンにより、Memoフィールドの文字列を消去します。

shot3123

ここでSelectAボタンがどうなっているのかを説明しましょう。SelectAボタンは一番簡単なというか、理解しやすい方法です。以下のように、ボタンをクリックすると、「Select Button 1」というスクリプトが実行されます。2つ目のポータルのボタンは「Select Button 2」、3つ目のポータルでは「Select Button 3」というスクリプトが動くように指定をします。ボタン名の番号と、スクリプト名の番号は対応していません。ちょっとわかりにくいことをやってしまってごめんなさい。

shot3124

3つのスクリプトは以下のようになります。つまり、ポータル内で選択したレコードのselection_idの値を、UI_Mainテーブルオカレンスのselect*フィールドに代入をしています。それぞれ、自分自身のポータルと、対応するUI_Mailのフィールドがスクリプトの設定に見えています。

shot3129

shot3130

shot3131

スクリプトの共通化

このような「同じようなスクリプト」は、共通化したいですね。昔のFileMakerなら、共通化は難しい上に、個別に記述できるから分かりやすいといった議論もあったわけですが、今時の複雑なソリューションでは、スクリプトの数が爆発する傾向にあり、1つのスクリプトにまとめる意義は高まっていると言えるでしょう。そういうわけで、「SelectB」ボタンでは、SelectAボタンの手法を1つのスクリプトにまとめてみました。3つのポータルにある各SelectBボタンは、「Select Button B」という共通のスクリプトを呼び出しています。

shot3125

この時、最初のポータルのSelectBボタンは、スクリプト引数として、次のような設定を行います。つまり、値を入力するフィールド名と、値を取り出すフィールド名を、改行で区切って指定をしておきます。それぞれのポータルのSelectBボタンは同一のスクリプトを呼び出すものの、スクリプト引数を異なるものにするということです。

shot3127

Select Button Bスクリプトは、次のようなものです。引数から値を取り出したものは、フィールド名の文字列です。その文字列のフィールド名で指定したフィールドに値を設定するには「フィールドを名前で設定」スクリプトを利用します。そして、文字列で与えたフィールドから値を取り出すのは、GetField関数を使います。引数を変数に入れると同時に、スクリプトステップは異なるものとなり、関数の利用も行わないといけません。

shot3132

共通化したことによるデメリット

ここまでのような単純なスクリプトで済ませられるのであれば、それはそれでいいのですが、実際の開発では複雑な要求が発生します。ここまでは、選択ボタンは同じ動作をするという前提でしたが、現実にはそういうことはあまりありません。ボタンごとに固有の要求が出てくることがあります。具体例としては次のようなことです。

  • あるポータルでのボタン選択をするときにだけ、別の選択肢は空欄にしたり、場合によっては初期値的な設定を強制的に行う必要がある
  • ある選択の場合に、ある条件が成り立つ場合にだけ、選択していいかどうかをダイアログで問い合わせる
  • ある選択肢の選択後に、テーブルの更新など、その選択肢に固有の処理を追加しないと要求が実現できない

こうなってくると、「そら見たことか、スクリプトはボタンごとに設定するのが王道だ」と思わず口走ってしまうかもしれませんが、未だに1ファイルに1データベースみたいな作り方をする発想が抜けきれないとしか言いようがありません。ここの例では、共通なステップは1つだけですが、複雑な処理は共通化しておかないとデバッグやメンテナンスコストが増大するのは言うまでもなく、システム構築の常識です。

もちろん、FileMakerでは、プログラミング言語的な柔軟性を犠牲にする分、ツールを使った開発がやりやすいとか、学習コストが低いという長所を得ています。しかし、なんとかならないかとも考えるわけです。

以前だと、「共通部分があるものの、違う部分もある」という場合にどういった手法をやっていたかといえば、まずは、スクリプトが分かれてしまうのは仕方ないとして、共通部分を「スクリプトの実行」ステップで呼び出すということです。もちろん、この方法は汎用的かつ共通部分の抽出ができるという面ではメリットですが、「違う部分」が発生するごとにスクリプトが増えることになります。また、ありがちですが、「違う部分がない」にもかかわらずスクリプトが別々とか、「違う部分がある」のにシステムの全然違う箇所からスクリプトを共通に使うなどの、後からの不具合発見を阻害する作りに往往にしてなりがちです。

1つの苦肉の索は、共通のスクリプト内に、IF〜ELSE IF〜END IFを利用して、例えば、押したボタンごとに分岐を作り、ボタンごとに違う処理を組み込む方法です。これだと、1つのスクリプトで共通に使えますが、一方で、ボタンが増えればIFの分岐が増えてしまいます。もちろん、ちゃんと作れば動作しますが、あるボタンの動作を追う時には無視するスクリプトが大量になってしまうなど、可読性が低くなります。また、自分が関係してるところだけをちゃんと書けばいいということは理屈の上では成り立つことですが、現実には変数を共通に使ったことでのバグの発生などが懸念されます。分離されていないことでの気づかない悪影響は、当然ながら気づくののコストがかかります。したがって、IFで分岐を入れるのはいいような悪いようなということになります。

共通スクリプトと個別スクリプトの分離

そこで、オブジェクト指向の世界でのDI(Dependency Injection)の手法により、関心ごとを分離して実装することができないかと考えました。例えば、ボタンごとにニーズが違うのであれば、ボタンごとに関心ごとが異なると位置づければ、これはAOPの実現でもあります。

まず、レイアウト上にある「SelectC」ボタンは、いずれも、「Select Button C」スクリプトを呼び出すようにしています。3つのポータル上のいずれも同様な設定になっています。

shot3126

以下のスクリプト指定は、1つ目のポータルのSelectCボタンのものです。スクリプト引数はSelectBボタンと同様な指定です。スクリプトは同一でも、ポータルごとに、設定するフィールドやポータルが参照するテーブルオカレンスが違うので、それらをスクリプト引数で指定をします。

shot3128

そして、「Select Button C」スクリプトは次のようなものです。コメントの「前処理スクリプトの呼び出し」部分が追加されています。「URLを開く」ステップと併せて示します。

shot3133

shot3108

ここで、このボタンをクリックしたスクリプトの関心ごとを、選択した結果を保存するフィールドで区別するということを考えます。この前提が上記のスクリプトの動作に必要となります。

ここで、例えば、1つ目のSelect3ボタンをクリックしたとします。すると、「Select Button C」スクリプトの最初の2つのステップで、次のように変数が設定されます。

  • $destField ← UI_Main::select1
  • $srcField ← UI_First_Selections::selection_id

そして、「URLを開く」オプションで、次の方なURLが生成されて、そのURLを開こうとします。FileMakerのURLスキーマは、ご存知ない場合には、どこかのサイト等で調べてください。

fmp://$/AOScriptTest?script=SelectButton_UI_Main_select1&param=any_parameters&$srcField=UI_First_Selections::selection_id&$destField=UI_Main::select1

最初の$で自分自身を参照します。URLのscriptパラメータは、その直前のscriptName変数の計算式をみてください。スクリプト名は、「SelectButton_<値を設定するフィールド名>」となります。値を設定するフィールド名は、ボタンのスクリプト呼び出しのスクリプト引数で指定されています。なお、コロンがフィールド名に含まれますが、無難にするためにアンダーラインに置き換えます。つまり、1つ目のポータルのSelectCボタンをクリックすると、自分自身の「SelectButton_UI_Main_select1」スクリプトを呼び出すということになります。ここで、「スクリプトの実行」ステップが使えない理由は、そのステップではスクリプトの選択はできても、変数等でのスクリプト名の指定ができないからです。なので、ここではURLスキームの利用を行います。「SelectButton_UI_Main_select1」スクリプトは例えば、以下のようなものを作成しました。select2とselect3フィールドを空白にします。ここで、レイアウトを指定する必要がない点は注目点の1つです。

shot3114

2つ目のポータルのSelectCボタンを押した時に呼び出されるURLでは、スクリプト名は「SelectButton_UI_Main_select2」となりますが、このためのスクリプトは作っていません。つまり、2つ目のポータルのSelect3ボタンをクリックした時、「URLを開く」では存在しないスクリプトをパラメーターに指定します。しかしながら、エラーとして出ないように「エラー処理」ステップを入れているので、要するに、存在しないスクリプトを実行しようとしても、スルーするだけです。

「SelectButton_UI_Main_select3」スクリプトは次のようなものです。SelectButton_UI_Main_select1スクリプトとSelectButton_UI_Main_select3スクリプトの最初の1行は同じで、パラメーターに指定した内容をmemoフィールドに入力することです。式が途中で切れていますが、結果を見れば明白だと思うので、式はここには記述していません。

shot3134

選択した時の動作を確認する

実際に動かしてみます。まず、Clearボタンを押してmemoフィールドを空白にして、3つ目のポータルのSelectCボタンをクリックしてください。すると、選択結果がselect3フィールドに入り、memoには何かの表示が見えています。つまり、Select Button Cスクリプトがボタンクリックにより呼び出され、その中で、SelectButton_UI_Main_select3スクリプトが呼び出されたということです。

shot3136

Clearボタンを押してmemoフィールドを空白にして、2つ目のポータルのSelectCボタンをクリックしてください。すると、選択結果がselect2フィールドに入りますが、memoは空白のままです。つまり、Select Button Cスクリプトがボタンクリックにより呼び出されただけの結果になります。

shot3137

Clearボタンを押してmemoフィールドを空白にして、1つ目のポータルのSelectCボタンをクリックしてください。すると、選択結果がselect1フィールドに入り、select2とselect3は空白となり、memoには何かの表示が見えています。つまり、Select Button Cスクリプトがボタンクリックにより呼び出され、その中で、SelectButton_UI_Main_select1スクリプトが呼び出されたということです。

shot3138

Select Button Cスクリプトでは、IF〜Else IFを使うことなく、クリックしたボタンに応じて処理を分岐させています。ここで、もし、新しくselect4フィールドを用意して、同様にポータルから選択できるようにしたとします。もちろん、ボタン等にSelect Button Cスクリプトを設定して、引数にフィールド名を指定します。そして、select4フィールドに特有の処理を、「SelectButton_UI_Main_select4」を記述して追加します。ここに、選択肢を設定する前に行いたい処理を記述します。こうして、フィールドが増えてスクリプトの利用元が増えたとしても、Select Button Cスクリプト自体に一切の変更を加えることなく、select4フィールド特有の処理を追加できることになります。実装のパタンとしては、GoFのパターンのStateに近いことをやっていると考えていいかと思います。

実開発への展開に向けて

まず、FileMaker的な考慮点を考えましょう。ポイントとなるのは、fmp://$/… スキームにより、変数で与えたスクリプト名で実行できる点です。この時、本当に通信するのではなく、同一のスクリプト実行環境で実行を行っているようです。その証拠として、「URLを開く」ステップの先で、「全スクリプトの終了」ステップを実行すると、呼び出した元のスクリプトも途中で中止してしまいます。また、このことは、「URLを開く」ステップの先で呼び出したスクリプトで、状況を判定して、これ以上の処理はキャンセルするという動作を組み込むことができることも言えるのです。また、グローバル変数を「URLを開く」ステップの先で設定して、それを呼び出し元でも参照できます。つまり、同一のグローバル変数が使えるので、「URLを開く」ステップは同一のユーザーセッション上で稼働していると言えるのです。この辺りの検証スクリプトの残骸が、コメントで残っているので、参考にしてください。

ここのスクリプトでは、前処理だけを実装しましたが、後処理、あるいはある特定の「中処理」を必要に応じて組み込むことも可能です。これは、呼び出すスクリプトの性質上、自由に決めることができるでしょう。一方、FileMakerの場合、その「仕様記述」に困難さんがある点も見逃せません。コメントに書くというのは曖昧かつ、記述者により違いや間違いの混入など、問題点は多いでしょう。開発のマネージメント上、状況に応じたベターな方法を見つける必要があります。

アスペクト指向スクリプトプログラミング

アスペクト指向とは、オブジェクト指向でのクラスの考え方では解決しにくい問題を扱います。クラスは単一の仕組みを持つのが理想ではありますが、いろいろな機能を組み込んだ結果、幾つかのクラスに共通の処理を実装してしまったというようなことがあるかもしれません。機能の実装においては、ある基準でまとめた結果、別の基準で見た時にはまとまってないということがあります。よくあるのがログ記録機能です。いくつかのクラスの実装ではログの記録があるものの、そのログの処理はクラスが違っても共通のことです。そうであれば、ログの記録ということ自体をその他のクラスとは別の独立したことと考える方が、明確にその機能だけに集中して検討が可能です。つまり、物事のある側面(Aspect)に注目すると、その側面は必ずしもクラスとしての分解に馴染まないことが出てきます。しかしながら、側面として検討した昨日をうまく実装する方法が必要になります。それがアスペクト指向プログラミングです。

一方で、アスペクト指向はオブジェクト指向を否定するものではなく、オブジェクト指向プログラミングの拡張の1つとして捉えるべきです。ただし、オブジェクト指向ではないプログラミングでも適用できる手法です。その代表的な実装方法がDIであり、DI(Dependency Injection)はプログラムのあるポイントに別のプログラムを挿入することです。ただし、オブジェクト指向の世界においては、インタフェースや抽象化クラスなどのいろいろなテクニックを使って、実装上の振る舞いや制約をきちんとしたルールに落とし込んでいると言えます。ある側面を定義したものをDIによって別のクラスに埋め込みをするということでの、アスペクト指向の実現できているということになります。アスペクト指向とDIは同一のものではありませんが、結果的には表裏一体な関係であると言えるでしょう。FileMakerでのInjection、つまり処理の注入は、若干明示的にはなってしまいますが、「URLを開く」でできることが以上のようにわかりました。しかしながら、あえてタイトルにインジェクトションだけを書いたのかというと、依存性つまりDependencyのコントロールが事実上できないという点があります。1つの分かりやすい側面は、名前さえ一致すればどんなスクリプトも呼び出せてしまうという点は、依存を無視しているともいえるわけです。

ここで示した例は、スクリプトにより選択肢の選択ができるという共通点があります。その意味では、Select Button Cスクリプトが1つのクラスだと思っていいかと思います。一方で、選択する先によって関心事が違うという状況を想定しました。つまり、あるボタンは「別のフィールドも更新する」という側面を持ち、別のボタンは「他には何もしない」という共通点の薄い別の側面があったわけです。しかしながら、「URLを開く」を応用した手法により、ボタンごとに異なる側面の実装を独立したスクリプトできるようになりました。したがって、この手法は、FileMakerのスクリプト実装におけるアスペクト指向プログラミングであると言えます。

FileMaker Server 14をOS Xで稼働するときのWebのカスタマイズ

以前に、FileMaker Server 13とOS X ServerのWebという文書で、FileMaker ServerのWebを動かすための方法を書きましたが、そこで、.htaccessファイルなどを有効にする方法記述しました。しかしながら、FileMaker Server 14.0.4を新たにインストールした場合、前記の文書の記述だとエラーが出ることがわかりました。この点は、FileMaker Server 14のどのバージョンでも当てはまるようです。

ということで、設定ファイルはHTTPServer/conf/httpd.confは以下のように変更すれば良いでしょう。

<Directory "${HTTP_ROOT}/htdocs">
    AllowOverride All
    Options All -Indexes -ExecCGI -Includes
    Require all granted
</Directory>

FileMaker Server 13のとき、「Order allow,deny」「Allow from all」も、Directoryタグ内に書いていたのですが、これを書くと、こんなエラーが出ました。最初のエラーにより、ステータスは403が返り、もちろん、ブラウザでは何も出てきません。後半の「an unknown filter was not added: includes」のエラーは派生的なもの、あるいは副作用的なもののようです。

[Sun Nov 29 01:00:40.179248 2015] [authz_core:error] [pid 1534] [client 219.121.7.182:38310] AH01630: client denied by server configuration: /Library/FileMaker Server/HTTPServer/htdocs/index.php
[Sun Nov 29 01:00:40.179642 2015] [core:error] [pid 1534] [client 219.121.7.182:38310] AH00082: an unknown filter was not added: includes

それから、ディレクトリへのアクセスで、index.htmlよりも先にindex.phpを開きたい場合のDirectoryIndexディレクティブの設定は、上記のDirectoryタグのすぐ下にあるdir_moduleが組み込まれた場合の設定にあります。しかしながら、ここを変えても意図通りに動かないなと思ったら、/Library/FileMaker Server/Web Publishing/publishing-engine/php/yosemite/httpd.fmi.conf.phpの最後の行にあるDirectoryIndexディレクティブを修正しないといけないことが分りました。

Apacheの設定ファイルは、バージョンが違うとそこそこ違ったりしますし、管理手法も比較的変動が大きく、「以前使えた設定や手法が通用しない」ということはこのところ頻繁に経験します。注意しましょう。

実は深刻な“カミFileMaker問題”

(2015/2/12 0:28更新:Facebookでの杉原さんの意見も反映させました。2015/2/13 17:00更新:Facebookでの日高さんの意見も反映させました。ありがとうございます。)

ネ申ExcelはExcelだけの問題か?

Excel方眼紙や罫線優先のワークシートなどなど、Excelで作った文書のうち、見栄えを整えることを主眼として作ってしまったことにより後からデータの活用ができなくなってしまった文書などを「ネ申Excel」と総称されています。三重大学の奥村先生の論文にまとめられています。良し悪しの問題は難しいのですが、例えばネ申Excelな記入用紙はWebフォームにすれば、即座に一覧が作られるなど、より利便性が高い代替え手法が明らかに存在するような場合があります。そのようにExcelにこだわる余り、自身の効率化を損なうのはもちろん、入力をするなどの利用者の利便性を著しく損なう状態になるのは避けるべきだと言えるかと思います。

同じような問題は他のソフトウエアにも、サービスにも存在します。ここで、データベースソフトの話をしたいのですが、そうなると、AccessかFileMakerかということになります。自分自身の問題でもあるので、馴染みの深いFileMakerを取り上げ、「カミFileMaker問題」として扱います。あえて、カタカナの「カミ」にしたのは、大昔「ファイルメーカー」と呼んでいたFileMakerへのトリビュートです。FileMakerのレイアウト機能は、帳票を高い自由度で作成できることから、従来の紙ベースで行われてきた業務をそのままデータベース化できる強い動機付けになっています。同じような仕様がAccessにもあることはありますが、プロの開発者からデータベース利用者までがみんなしてテーブルを定義してレイアウトをいじるというのはFileMaker市場の大きな特徴だけに、「カミFileMaker問題」が浮き彫りになると考えられます。

「カミFileMaker問題」とは?

ここで問題の定義として、紙の帳票類をそのままデータベース化してしまうことで発生する問題とします。もちろん、帳票をそのままデータベース化するだけでも、例えば、共有ができることや、印刷を省きパソコンやタブレットで閲覧することでの即時性などのメリットは発生します。最初の帳票ができたとき、「これはいい!」と誰もが思います。だけど、いくつも帳票を作るに従って問題が顕在化します。

紙が画面に変わっただけ?

帳票をデータベース化すると、どうしても従来のワークフローが結果的に踏襲されることになります。むしろ、ワークフローは出来上がっているのだから、それを電子化すればよりスムーズという、あまり根拠のない理屈を信じて突き進みます。その結果、まず、電子化されているのに「転記」という作業や、帳票の生成や破棄、あるいはステータス更新という動作に「手作業」が入ってしまいます。今までは紙だったので、それはやって当たり前でした。しかしながら、電子化するときに、そこでの自動化を深く考えなかったとしたら、同じことを端末を操作してやらないといけません。パソコンを扱うのが弱いとか、ストレスが高い人は、そこでまずはつまずくことになります。

紙にはなかったリンク情報はどうなった?

それでも仕事をみんなでがんばってこなしたとします。そして、さまざまな帳票レコードが、1つのエンティティに対して複数積み重なることにより、新たな問題が発生します。ある帳票と別の帳票が結びついている場合はよくあります。1対1や1対多ということもあるでしょうし、多対多もあります。紙で作業していると、その結びつきを人間がやっていることがあります。業務上の常識から、誰もが自動的に異なる2枚の帳票に関係がある、関係ないということを判定できるのです。この作業をパソコンの画面上で人間が行うのは非常に面倒です。紙のファイルを何冊か机に並べて対応するものを開けて突き合せるような手軽さは、今のパソコンやタブレットではまだまだ無理です。

もちろん、相手の文書IDを記録するなどすればいいのは当然ですが、気付いた時には遅かったということもあります。また、そのような「リンク」の重要性が、問題が発生しても気付かない、あるいは気付かないふりをするということあるでしょう。かくして、対応する文書の手がかりをかなり強引に引っ張り出すことになります。「同一顧客で、この帳票より前のもののうち、最新のもの」などといったリレーションシップを組むなどします。それでも、運用は可能かもしれませんが、対応が取れなくなる可能性が0ではなく、小さいながらも0%よりも大きくなります。また、業務で発生するイレギュラーなケースを忘れていると、ミスにつながります。ビジネスロジックでほぼ解決できるものでも、より単純な解決法があるのなら、単純な方が安定しているのは言うまでもありません。

矛盾する2つのフィールドの関係

さらにこんな例もあります。紙の帳票から、別の帳票に転記するとき、人間が転記するといいように解釈していたのですが、それを電子化すると、機械的に転記できないような場合が発生します。つまり、それぞれの帳票のスキーマに、論理的な不一致が発生してしまうのです。もっとも身近な例では、入力帳票が「氏名」で、それに対応する別の帳票が、姓名別々のフィールドのような場合です。こうしたスキーマの不一致は、紙の帳票をそのままデータベース化すると、気が付いたら行っていたということになります。また、転記なのか参照なのか、ここの考え所を全部転記することにしてしまったことで、かえって手作業が増えることもあります。

この問題は、突き詰めると、データベースのスキーマを検討するときに必ず必要となるその業務ドメインのモデル化が不正確なのです。フィールドとテーブルを定義すれば良いというのはFileMakerの機能のことで、設計者は他に考えないといけないことはたくさんあります。データ間の連携はもちろんだし、これについてはリレーションシップで定義することになります。しかしながら、FileMakerの機能に見えないこととして、あるデータは転記して見えるようにするのか、参照して見えるようにするのかということを考える必要があります。これは、FileMakerのテーブル設計のダイアログボックスでは明示化されていないものの、極めて重要な設計上の決まりごとになります。

データベースには、データベースに合った設計を

こうした問題は、昔からありますが、FileMakerは手軽だからこそ、陥る罠でもあるといえます。あえて、「カミFileMaker問題」として、問題を浮き彫りにすることで、より多くの方が意識できるようになればと考えました。もちろん、プロの方々もこうした失敗を重ねてきていて、いろいろなノウハウをお持ちでしょうし、長年使ってきた人も同様です。例えば、受託開発のとき、導入経験がないお客さんの要望をそのまま構築すると、「カミFileMaker問題」の宝庫です。プロや熟練者は、そこでしっかりとお客さんの要望を受け入れつつ、問題の発生を抑える手立てを考えないといけません。言われた通りにやればいいというのは間違いで、そのようなやり方を続けてきた結果使われないシステムを納品することになり、信用を落とすことになるのです。この問題を認識し、きちんと説明して方向付けをする必要があるのは、プロや熟練者の皆さんなのです。決して、素人を茶化すための問題定義ではないことは最後に強調したいと思います。

以下にまとめておきます。もちろん、みなさんの意見や表現の向上も大歓迎です。

「カミFileMaker問題」の発生

  • 帳票類をそのままFileMakerのデータベースで再現する電子化

「カミFileMaker問題」による起こりがちな結果

  • 一見すると効率化されたように見えるが、帳票作業とは異なる事務作業等が増えているなど、実は効率化されていない
  • 機械的に行えるデータの連携や解釈などが、データベースの仕様に含まれず、そうした作業も人間が行う必要がある
  • 2種類の帳票でスキーマが異なり、論理的には転記ができず、人間が解釈してつどつど修正しないといけなくなる
  • 紙が減ることの効率性だけに注目した結果、システム運用コストに気が回らず、気が付いたらかえってコスト高になってしまっていた
  • データベーススキーマの設計において正規化という点が考慮されず、データ解析に支障をきたしたり、あるいは解析自体が不可能な、品質の低いデータを蓄積してしまう。

「カミFileMaker問題」の本質

  • コンピュータ作業に最適なワークフローを検討し、転換しないために、結果的にさほどの効率化もされない
  • データ間のリンク構造を記録できないスキーマ上で、ビジネスデータが蓄積され、どうしようもなくなり、最悪はデータ活用に制限が出てきてしまう
  • データベースのスキーマを単に「紙にあった項目」のみで認識することで、ドメイン自体を表現するモデルの精度が低くなってしまう