Youngさんが連名で公開しています。Youngさんの解説記事を紹介します。Young2015/2/24概要Selector-Connectorは、FileMakerのテーブルオカレンスを整理するためのデータモデルです。Geistとゆるい協業を続けてきました。「ゆるい」と言ったのは、モデルが進化する過程で我々はほとんどお互いの成果を見せ合うことなく、進捗について大まかな情報交換をする程度だったからです。結果的によく似た機能のものが出来上がったことで、我々が目指したものは正しかったのだと思いました。Toddのアプローチについては、ここから素晴らしい記事とビデオを見ることができます。Completeのデータモデルに採用しました。このことが、Completeがうまくいっている主な理由の一つだと感じています。Selector-Connectorを採用したことによって、ユーザがCompleteを拡張・修正できているという事実を見ても、このアプローチが正しかったことが証明されていると言えるでしょう。Selector-Connectorモデルでもっとも重要なのは、手法自体は新しいものではないということです。7の頃から標準で提供されている強力な機能であるグローバルキーやクロスジョインを使用していますが、それをパターンとして説明できる形に整理しました。それはちょうど我々がAnchor-Buoyをパターンとして簡単に説明できるのと同じです。Anchor-Buoyを拡張するSelector-Connectorは、現在もっともよく使われているデータモデルであるAnchor-Buoyの拡張版と見ることができます。Anchor-Buoyは、開発者コミュニティで間違いなくもっとも広く採用されているFileMakerの標準であり、その理由は以下の2つです。少ないルールでリレーションシップグラフをわかりやすく整理できる視覚的に理解しやすい優れたネーミングこのモデルに手を加えるのであれば、これらの特徴は失わないようにしたいと思いました。一般的な言い方で言うと、Selector-Connectorは現行のAnchor-Buoyモデルを保ったまま、その上に実装しています。そのときにルールを少しだけ曲げます。Anchor-Buoyのルールのもっとも基本的な解釈は以下のとおりです。レイアウトは必ずAnchorのテーブルオカレンスをベースにするBuoyへのアクセスは、そのAnchorのコンテキストからのみ行われるAnchorのテーブルオカレンス同志をリレーションで結合しないこれらのルールを守ることで、Anchor-Buoyモデルは我々にコンテキストを意識させ、そこから外れた操作(例えば、ポータルに間違ったテーブルオカレンスを選択する、など)を行ないにくくします。これはFileMakerではとても重要であり、多くの場合これらの利点はAnchor-Buoyの欠点よりも大きいため、このモデルが標準として広く採用されています。典型的なAnchor-Buoyモデルポップオーバーの登場すでに述べたように、Selector-Connectorモデルは技術的にはなんら新しいところはありません。13におけるポップオーバーの導入でした。それは、ポップアップウインドウとダイアログに代わる、便利な新しいオブジェクトでした。ポップオーバーは、ポータルからレコードを選択したりレコードを編集・作成するのに適しています。すべて一箇所で行うことができます。FileMaker社も同じことを考えていたようで、バージョン13に付属のデモファイルにはこの「すべて一箇所」で操作できる機能がついていました。ポータルをポップオーバーで表示し、目的のレコードを選択させるというものです。レコードが見つからなかった場合は、「新規」ボタンを押すと新規レコードの入力フォームに「スライド」するというスマートな操作方法になっています。Completeの新バージョンの開発を開始しようとするタイミングで、この優れたデザインパターンが実際に動作するのを見たのです。レコードを選択するためのシンプルなポップオーバーと、その次に表示される新規コンタクト先の入力パネルところがこの機能を詳しく調べ始めると、これらのポップオーバーは、目的ごとに個別のオブジェクトとして作らなくてはいけないということに気づきました。ProjectsからもInvoicesからも同じコンタクト先を探すのに、ProjectsかInvoicesのレイアウトのコンテキストに紐付いているという理由で、同じポップオーバーは使えないのです。コンタクト先選択パネルにバーチャルリストを使用していた場合、ポータルにはProjectsとInvoicesと結ばれた専用のBuoyがそれぞれ必要になります。これはいくらなんでもありえないと思いながらも、Anchor一つずつにポップオーバーをコピー&ペーストしながら少しずつ微修正していく方法を探していました。ユニバーサルコンテキストポップオーバーをどこでも動作するようにしたくても、コンテキストは必ず必要になり、それは回避する方法がありません。そこでユニバーサルコンテキストという考え方が生まれました。長い間、Toddと私はこの形式のモデルを使っていました。Selectorは存在していませんでした。以下が我々の最初の通過点の概要を表したものです。ユニバーサルコンテキストモデル)我々は、Anchor-Buoyのルールを一部崩して、Anchor同士が互いに関連を持つ形を認めることにしました。我々は今まで通り、Anchorを直接に関連付けたり、データのやり取りをするべきではないと考えています。ここでの我々の目的は、すべてのAnchorから、Homeとバーチャルリストのレコードのユニバーサルコンテキストのテーブルオカレンスにアクセスできるようにすることです。これにより、どのAnchorのレイアウトもポップオーバーセレクタの同じポータルを利用することができるようになります。同じポータルを共用できるというだけでなく、このポータルを参照するスクリプトも汎用的に利用できます。これにより、我々が求めているどこでも使えるポップオーバーに一歩近づきました。レコードのロックの問題は?上のリレーションシップグラフのポイントは、Home上でグローバルフィールドRowsToShowGlobを設定して、バーチャルリストの内容を制御できる(例えば、コンタクト先の候補リストを設定する、など)という点です。これはSessionモデルではないので、Homeで複数レコードを管理してレコードロックを回避するなどという複雑な管理はしたくありません。結果的には、Homeテーブルのフィールドがすべてグローバルフィールドであれば、そのテーブルは複数ユーザがロックなしで同時に使用できるグローバルテーブルであるといえます。この発見は検討プロセスの中でもとても重要な到達点になりました。中央に一つのテーブルオカレンスを置いて、それを介して連結することで、Anchor-Buoyに似ながらも、少しゆるいモデルを作ることができました。重要な点は、このモデルではAnchorの一つをコンテキストにして、Homeとバーチャルリストのレコードを操作しているということ、そしてそのときに中央のテーブルオカレンスはロックされないということです。Homeのコンテキストでレイアウトを作成してそこから関連レコードを開くと、それは中央のテーブルをロックしていることになり、他のユーザが同じことをするのをブロックします。Anchorから「ユニバーサルコンテキスト」テーブルを操作すれば、Homeのではなく、Anchorのレコードを開きます。これが我々の求める動きです。このモデルが機能するために、Anchor-Buoyから引き継がれた「すべてのレイアウトはAnchorのコンテキストになければいけない」というルールを守る必要があります。上のモデルは、コンタクト先を選択するポップオーバーをどのレイアウトからでも使えるようにするという課題を解決しました。それだけではなく、ポップオーバーから直接新規のコンタクト先を作成することもできるようにしたいと考えました。Anchor-Buoyモデルに、バーチャルリストを活用するための拡張を行いましたが、それをさらに進めてコンタクト先を作成するための専用のテーブルオカレンスを作りました。下の図で、HomeテーブルオカレンスからCreateContactsというテーブルオカレンスがぶら下がっています。コンタクト先を作成するためのテーブルオカレンスを追加するこのリレーションを介して新しいコンタクト先を作成することができます。HomeとCreateContactsの間のリレーションシップがレコードの新規作成を許可していて、HomeのContactIdGlobが空であれば、CreateContactsテーブルオカレンスのフィールドにデータを直接入力するだけで、新規のコンタクト先レコードを作成することができます。コンタクト先IDは自動生成フィールドで、新規レコードに入れたこの値がグローバルフィールドに入れ戻されます。この動作は少し奇妙に思えるかもしれませんが、FileMakerに以前からある機能で、「ポップバック」または「マジックキー」と呼ばれています。この方法によって、Homeに一時的な「親」を作ることで、どこからでも新しいコンタクト先を作成することができるようになります。コンタクト先のレイアウトに移動する必要はもうありません。ポップオーバーのコンタクト先選択パネルをどのレイアウトからでも呼び出して、コンタクト先の選択と新規作成の両方をおこなうことができます。これで問題は解決し、リレーションシップグラフが乱雑になることもありません。Selectorこの部分を機能させることができたすぐ後に、このモデルによってできることがさらにあるということに気づきました。どこからでもレコードを作成するためにこのユニバーサルコンテキストを使用しているのであれば、同じようにこのモデルでどこからでも簡単にレコードを参照したり編集することができるのです。PortalsはFileMakerで用いられる一般的な手法ですが、ユニバーサルコンテキストがそれらととても相性がいいということにほどなく気がつきました。Detailビューのために関連テーブルへのBuoyが2つ必要です。通常、1つ目のBuoyのポータル行をクリックしてレコードのIDを取得します。そのIDをグローバルフィールドに設定して、2つ目のBuoyへのリレーションを作ります。それによって選択されたレコードの詳細を見ることができます。Selector-Connectorでは、そのグローバルを中心となるHomeテーブルオカレンスに設定し、CreateContactへのリレーションを使って詳細を表示します。詳細表示のための2つ目のBuoyは不要になり、さらに重要な点として、コンタクト先の詳細を見たければどのAnchorからでも同じテーブルオカレンスを使えるようになります。これがSelectorの誕生の瞬間です。中央のテーブルはHomeではなく、「Selector」と名付けました。その右側にあるテーブルオカレンスは「Selected(選択されたもの)」であり、かつ新規レコードを作成するためのリレーションでもあります。これで、レコード選択パネル、レコード新規作成、master-detailを一部品にまとめることができ、Anchorごとに付いていた似たようなセットのBuoyがすべて不要になりました。Selectorモデルの完成Connectorこの新しいモデルで作業をするようになってから、以前のようにFileMakerと「戦っている」という感覚がなくなってとても楽になりました。コンテキストとレイアウトがAnchorに紐付いているのは昔のままなので、両方のいいところをとった、期待に沿ったものになっています。いくつかの追加の利点が見えてきました。一つ目は、グローバルキーのほとんどはSelectorに移動したため、実データが入っているテーブルにグローバルフィールドを持つ必要がなくなりました。Completeではデータテーブルからすべてのグローバルフィールドを取り除くことができました。これによって開発作業がかなり簡略化されます。外部データソースと統合したりデータインポートを行っている場合には、たくさんのグローバルを行ったり来たりせずにすみます。これがConnectorのコンセプトにつながりました。私にとってConnectorとは、どれがレイアウトでどれが違うかを表すだけの図ではなく、違う種類の論理部品の構成図をモデリングすることを意味します。当初、部品はAnchor-BuoyとSelectorの2つだけだと考えていましたが、一度このモデルを実際に適用してみると、さらにその先がありました。Selectorはバーチャルリストとは異なります。それを表現するようにグラフを修正することにしました。すべてのAnchorから利用できる、索引化された値を貯めておく場所も作りました。設定や画像データなども中央のConnectorにクロスジョインで接続し、どこからでもアクセスできます。これらの機能の全体がSelector-Connectorモデルになります。Selector-Connector締めくくりとして、ピカソの偉大な言葉を紹介します。物心がついた頃から母が繰り返し私に言っていた言葉で、今回の話にもよく当てはまると思います。パブロ・ピカソこの演習を終えた今思うことは、リレーションシップグラフの開発者が当初Anchor-Buoyをイメージしていたかどうかはわかりませんが、今回の我々の共同開発ではAnchor-Buoyの理解は絶対に避けて通ることはできない重要なステップだったということです。FileMakerのコンテキストの考え方を完全かつ徹底的に理解することなしに、Selector-Connectorのようなものに手を出すことは、非常に困難でおそらく効果がないと思います。今回のようなモデルを使用したり、あるいはそもそも議論したりできるのは、Anchor-Buoyの知見のおかげです。ここでも再度繰り返しますが、Selector-ConnectorはあくまでAnchor-Buoyの拡張であり続編です。そのルールを本当に深く学び尊重してきたおかげで、多少は独自の芸術性を出せたかもしれません。