2015年4月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
無料ブログはココログ

« enchantMOON : 双方向リンクシールを作りました(解説&言い訳) | トップページ | enchantMOON : 双方向リンクシール : 一応公開 »

2013年10月28日 (月)

enchantMOON : 双方向リンクシールを作って考えた

「双方向リンクシール」やっぱりまだまだ不安定です。MOONPhase ver 2.7.0 で、「シールを貼付けた時と剥がした時にプログラムが実行されないことがある不具合を修正」ということなので、これで改善することを期待して、誤動作が減ったら Bookmarks にも公開することにします。

さて、シールについて、@shi3z 社長からもいろいろとコメントをいただきましたので、何か MOON に前向きな提案ができるように、ちょっと考えてみます。思いつくことをあれこれ書いて、2~3 日寝かせて整理できたら Issue Tracker に要望してみましょう。

大きく、(1)きれいに剥がれて終わるシールの実現方法、(2)システムレベルで作成したリンクの情報活用案、(3)今後の検索 API への要望、に分けて書いてみます。

(1)きれいに剥がれて終わるシールの実現方法

昨日の記事に書いたように、「検索シール」は元々目的のページに移動してからきれいに剥がれて跡を残さないつもりでした。しかし script の実行環境(カレントディレクトリ? カレントページ? カレントオブジェクト?)が移動してから peel() を実行すると、期待した動作にはなりません。

対応案の一つは、peel() が、途中でページを移動しても、実行を開始したときのカレントを保持しておいて ( binding ですね) 元のページのシールを剥がすように実装を変更すること。或いは、ページを移動してシールを剥がして終了という新しい API を追加すること。技術的難易度が同等なら、前者の方が先々使い回しが効くように思います。

但し、この場合、ondetach に割り付けた処理の実行をどうするかが問題です。

シールが剥がれるので、detach event が発生して、ondetach 処理が実行されるべきなのですが、その時のカレント環境がどうなるのか。ondetach には何らかの後処理を記述することになりそうですが、たとえば処理中で getCurrentPage() を実行したら、どのページの ID が返るのか。もし、ページを移動してから peel() した場合、ondetach に peel() と同じ binding が渡せるのであれば問題にはならないはずですが、そもそも移動して剥がすコードを書くならば、移動する前に後処理を済ませてしまうことも可能なはずです。

いっそのこと、「移動してからシールを剥がして終了」な API では、detach event を発生させないことにして、API リファレンスに「ondetach 無効」と書いてしまうのもありな気がします。peel() は実行開始時の binding で動作して、ondetach にも開始時の binding が渡るというのがすごくエレガントですが、安全に開発するには、ondetach 禁止、の方が確実でしょう。

視点を変えてみますと、そもそも移動して剥がすといった面倒な要求が出てきたのは、張り付けて残す必要のないシールを transient に実行するために、貼って実行してすぐ剥がすというオペレーションが必要になるからです。であれば、いっそのこと「張り付けずに実行」というシール(?)を作ることができれば、移動 peel() が不要になるのでは?

とも考えたのですが、@shi3z 社長によると、これは MOONPhase のモデルからすると、オブジェクトのないメッセージセンディングになってしまうらしく、(ほぼ)不許可とのことです。

それならば、逆転の発想ですが、「貼ると同時に実行してすぐ剥がれる」という動作を実現する、別の Sticker オブジェクトを作る手もあります。たとえば ImmediateSticker とか。実際には、Sticker を継承して、勝手に peel() するだけなのですが、Sticker と異なる点として onattach プロパティのみを許し、ontap, ondetach プロパティを定義できないというものにします。

開発段階では、普通の Sticker で、処理をすべて ontap に書く。onattach と ondetach は MOON.finish() だけ。で、ontap にも peel() は書かない。いちいち剥がれていたら開発できないので。機能設計が済んだら、Sticker を ImmediateSticker に変えて、処理を onattach に移せば、すぐに剥がれるシールの出来上がり。

この形でも ondetach 処理がどの binding で実行されるかによるバグの発生を回避できます。とにかく、ページを移動した後の peel() で ondetach が呼び出されてバグを紛れ込ませる、というコードを書きにくい解決策を希望します。

ですがよくよく考えると、ページを移動してシールを剥がすという動作が必要な場面は相当に限られます。優先度は低いかもしれません。

(2)システムレベルで作成したリンクの情報活用案

今回の「双方向リンクシール」では、専用の「登録シール」で作成したリンクに対してだけ、リンク元を検索します。可能であれば、システムレベルで作成したリンクに対しても、リンク元を検索したいものです。

そうするのが良いかどうかの議論は横において、もしそうするならどんな方法が考えられるか。

最も安直で、面白くない方法としては、システムレベルで指で囲んでリンクを作成する際に、私の作成したシールのように、localStorage に情報を残し、そのフォーマットを公開すること。そうすれば、searchStorage() で簡単に検索できます。但し、この情報はユーザーレベルからも改変できるので、あまり利口な方法ではありません。

そんなことをするくらいなら、シールのディレクトリの manifest.json のリンク情報を直接読みだして、searchStorage() と同等の動作をする API を追加してもらえれば、特に工夫しなくても「検索シール」同等の機能は簡単に実装できます。

但し、毎回全ページ・全シールの manifest.json をスキャンするというのは結構実行コストが高くつきます。実行コストを下げるなら、システム内部に全ページ ID を key とした hash を保持し、リンクの作成・削除ごとに entry を追加、その都度 SD card に link.json とでもいったファイル名で保存、OS のリブート時にはそこから読み込む、という方法もあります。

そのたび manifest.json をスキャンするのと、hash を内部に保持するのと、どちらが良いのかは需要次第でしょうか。いずれにしても気になるのは、スケーラビリティの問題です。現在の MOON のパフォーマンスと、SD card が 16Gbyte 程度であれば、どちらの方法でもそれほど問題にはならないのかもしれませんが、このプロジェクトが順調に推移すれば、もっと規模の大きなソリューションが出てくるかもしれません。(enchant office ?) 複数のデバイスをまたがったリンクまでサポートすることになると、どこかに twitter 並の key-value store サーバーを立てるという方法すらあります。

で、まぁ、とりあえず manifest.json 全スキャンでよいので、API だけ定義してもらって、今後の展開とリンク元検索の需要に応じて実装を変えていってもらえばよいのではないかと思います。

尤も、ここまでしてリンク元検索 API を用意して、貼ってすぐ剥がせるシールの作成環境を用意するならば、リンク元検索機能自体をシステムレベルで提供するのはそれほど無茶な要求ではないようにも感じます。

【2013/10/29 追記】

リンク元情報の保持は、今の enchantMOON の規模なら、以下の方法の方がバランスがいいかもしれない。

  • 各ページの下に "linked.json" という file を作る
  • リンクを作成した時、リンク先ページの linked.json にページの ID を追記する
  • リンクやページの削除の時は何もしない
  • リンク元ページの検索要求に対し、まず、linked.json を読み込む
  • 登録されている各ページ ID に対し
    • そのページが存在するか
    • そのページから自ページへのリンクが存在するか
  • をチェックして無効な entry を削除する
  • linked.json に書き戻す
  • linked.json の内容を検索要求元に返す

こうすれば、毎回全ページを総当たりするより動作は速く、hash を常に保持することによるメモリの消費も回避できる。システム全体で hash を保持して一つのファイルに書き出す形だと、USB で PC にマウントして、ページを直接削除されてしまった場合に情報の不整合が出るが、上記の動作だと、不整合を招かない。

(3)今後の検索 API への要望

enchantMOON において、検索機能の拡充には大きな可能性があると思います。私自身、手軽な手書きメモ端末を期待していますので、いろいろな検索機能が欲しいと感じます。また、そもそも「紙の表現力は素晴らしいが、検索できない」から enchantMOON を開発したのであれば、検索機能はむしろ key function に位置付けるべきです。もっと追及したい。

ところが、現在の MOONPhase の検索機能の実装は少し残念です。

ver 2.6.0 現在で提供されている検索 API は以下の三種類です。(openNotebook() は、「全ページ」を検索する API)

  • openNotebook()
  • searchPage()
  • searchStorage()

openNotebook() が中途半端ですが、これら検索 API はいずれも、「全ページを対象に」「指定した条件で」「検索したページを表示して選択」「指定されたページを表示する」といった機能がひとまとめになっています。これは惜しい。

既に Issue Tracker の #112 に投稿済みですが、これらはそれぞれ要素 API に分解するべきです。

「全ページを対象に」するのをデフォルトとしても、特定のページ群の中から検索できるように、MyNotebook1/info.json と互換の形式で母集団を指定し、検索結果も JSON で返す「検索 API」。JSON を与えると、ページを表示して選択する 「選択 API」。「指定のページに移動する API」は既に openPage() として提供されています。但し、選択されたページがサムネイルからぐぐっと拡大してページ全体の表示になるビジュアルは魅惑的ですので、「表示して選択して移動する API」も別に用意してよいと思います。

問題なのは、現状提供されている API が、「検索」と「表示・選択・移動」がひとまとめになっていることです。これが検索の組み合わせを不可能にしています。

JSON で与えて検索結果を JSON で返す API になっていれば、たとえば searchPage() だけでも、全ページから tag_a で検索して、その結果に対して更に searchPage() で tag_b で検索をかければ、結果的に tag_a & tag_b での絞り込み検索になります。今回の「リンク元検索」機能と、検索だけの searchPage() を組み合わせても絞り込みリンク元検索ができます。たとえば今後、各ページにプロパティが設定されて、作成日時で検索できるようになったとすると、JSON 渡しになっていれば、「30 日以内に作成された、このページにリンクしているページ」を検索することも容易です。

検索結果を表示して、選択ページに移動するのも、選択までと移動を分離しておけば、たとえばサムネイル表示でなく、リスト表示で選択するシールをユーザーが作成することもできます。

検索機能は enchantMOON の今後を大きく左右する可能性があると感じていますので、是非、「応用がきいて、展開の幅が広くなるように」機能要素を分解して API を設計してもらいたいと思います。

« enchantMOON : 双方向リンクシールを作りました(解説&言い訳) | トップページ | enchantMOON : 双方向リンクシール : 一応公開 »

enchantMOON」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1527616/53753244

この記事へのトラックバック一覧です: enchantMOON : 双方向リンクシールを作って考えた:

« enchantMOON : 双方向リンクシールを作りました(解説&言い訳) | トップページ | enchantMOON : 双方向リンクシール : 一応公開 »