INTER-Mediatorのことをブログで書くのが久しぶりな気がしているが、以前のように、設計書代わりにブログを書いておく。INTER-Mediatorのコードにタッチしていない方はなんのことか分からないと思うので、最初にその点を指摘しておく。
INTER-Mediatorでは、ページネーションコントロールを自動的に生成して、例えば30レコードずつ表示するような仕組みを設定だけで実現している。しかしながら、その後に、ポップアップメニューからレコード数制限をできるようにしたり、Master/Detail形式のUIを実現したりと、1度に表示するレコード数に絡む機能を追加してきた。3年ほど前に、かなり混乱した感じになったのでリファクタリングをしたが、バグレポートをもらい、相変わらず怪しい部分があることに気づいた。ここで、根本的に直したいと思うのだが、今までの方法で欠けていたのは「ルールの明確化」だった。そこで、ルールを作って実装というか、リファクタリングをしたいと考える。
まず、現状(5.7+α)で、どんな要素が関連しているのかをまとめて見たい。レコード数に影響するUI要素は次のものである。
- ページネーション
- ポップアップメニュー(data-im=”_@limitnumber:コンテキスト名” の属性があるSELECT)
- Master/DetailのDetail側(navi-control=”detail”、詳細側なので常に1レコードにしたい)
コンテキスト定義のキーで、関連するものは次のとおりである。
- records
- maxrecords
- paging
- relation
- navi-control
さらに、関連するプロパティを挙げると次のとおりである。プロパティと言いつつ、オブジェクトは1つなので、事実上のグローバル変数である。なお、以下のプロパティの3, 4, 5は、getter/setter実装している。ローカルストレージ等を利用してページ移動してもパラメータの記憶をしたいためだ。
- INTERMediator.pagedAllCount
- INTERMediator.totalRecordCount
- INTERMediator.startFrom
- INTERMediator.pagedSize
- INTERMediator.pagination
これれらの仕組みをどのように解釈するかという問題である。
まず、INTERMediatorオブジェクトのプロパティについては、paging=trueのコンテキストに対してページネーションを動作させるためのものであるので、ここでは「ページングを特定のコンテキストに対して実施する」という決定がなされた後のものである。したがって、UIとコンテキスト定義の内容について、どのように解釈をすべきなのかを、まずは決めなければならない。ここを曖昧にしていたのが、バグが常に治らない原因と考える。しかし、基準も何もない。よって、「UIが自然かどうか」という観点で推測しながら決め事をしなければならない。
前提条件1:
ページネーション処理は単一のコンテキストのみ
この点は、異論はあるかもしれないが、複数のコンテキストにページングを配置すると、画面に複数のページネーションコントロールが登場して、混乱をしかねないUIとなる。適切なUI設計では複数のページネーションは不要と考える。これを前提とする。また、1コンテキストに複数のページネーションコントロールを用意するということも同様にやらないことを前提とする。
前提条件2:
Master/Detail形式のUIでは、ページネーションはMaster側にだけ適用される
MasterにもDetailにもページネーションが欲しいという声が聞こえてきそうであるが、それぞれを同時に表示することも仕組みとしては持っているため、ページネーションはMasterだけに適用させたい。Detail側にレコード移動の機能を組み込めないようにしたいのである。なお、どうしてもそうしたいと思う場合には、Master/Detailの機能を使わないで、Detailと同一内容のページファイルを用意して、普通にページネーションを利用できる。適切な対応策があるので、この前提条件はデグレードには当たらないと考える。
優先順位1:
そのコンテキストで取り出されるレコード総数はmaxrecordsを上回ることは絶対にない
この仕様の優先順位が高いとしたら、サーバー側での検証とレコード数の修正は必要であるし、通信直前に処理するなど、UIから遠いところで処理をしないといけない。
優先順位2:
navi-control=detailのコンテキスト場合、レコード数は常に1以下とする
ある時点でこの設定を入れた。優先順位を高めにして、他の設定より優先される方が、矛盾するコンテキスト設定してもうまく動く模様であるが、一方、間違いに気づきにくいということにもなる。
優先順位3:
ポップアップメニューがあればそれに従う
ポップアップメニューは、ローカルコンテキストに記録するのであるが、ローカルコンテキストのバインド処理は、ページ合成処理の最後の方にやっている。少なくとも、limitnumber:*の値の処理を、ページ合成前にもしなければならないし、本当に初めてページを開くときはローカルコンテキストがセッションに残されていないので、ノードを探る処理も結果的に入れておく必要がある。ここの改造は、コードの追加を伴う。
優先順位4:
recordsキーの値に従う
これは順当なルール。なお、relationがあるとレコード数の制限はなくすということを一瞬考えたが、関係レコードの上位3件だけ表示したいということもあると思う。結果的にrelationキーは考慮しなくてもいいのではないかと思う。
これらのルールで得られた「レコード数」を元にしてレコードを取得する。ページネーションを利用するコンテキストなら、ページネーションとの連動が必要になる。このページネーションとの連動部分が、コードとしてはうまく分離されていないのが現状である。上記のルールで決まれば、それに応じてページネーションを設定するという風に、レコード数とページネーションの処理順序を決めて、依存関係をシンプルにするようにリファクタリングを進める必要があると考えられる。すなわち、
方針:
レコード数決定プロセスとページネーション処理を分離し、レコード数の決定を先に行って結果を必要ならページネーション処理に渡す
ということになる。この方針で行ってみようと思う。