Snippets

対抗して作ってみた。

Fragment is dead?

The Cornerに Androidの Fragmentを DISる記事 が出たんで、なんか自分の周りで Fragmentの価値が暴落している模様。 自分もかの記事には基本賛成なんだけど、いままで G社の意図にしたがって頑張って Fragmentを勉強してきたのがサンクコストになるのが悔しくて、いろいろと考えている最中。

その途中のまとめとしてこの記事を書いてみます。なにしろ、自分自身がそういうアンビバレンツな状態にあるのでうまくまとまるか心配だけど、アウトプットしないと進みそうにないので。

Advocating Against Android Fragments のすごく端折ったまとめ

  • いままで頑張ったけど、Fragmentはやっぱりいらない子だ。
    • ライフサイクル(笑) が複雑すぎ。
    • FragmentManagerImplがわけわからなくてデバッグが難しい。
    • logicと viewが混じってて unit testも難しい。
    • FragmentTransactionが非同期実行なので、それまで状態が不安定。
    • 復活する時、引数なしコンストラクタが必要なので inner classにできない。
  • まあ、それでも Fragmentはいろいろ教えてくれた。
  • Responsive UIを Fragmentなしでつくってみる!
    • 細かくは説明しないけど、 Containerって interfaceつくって頑張る!
  • ビジネスロジックの部分は Presenterっていうのを作って分離して、unit testも簡単だ。
  • バックスタック管理は Flow を使え。
  • Daggerと Mortarは Fragmentとは直交したものだから、やっぱり有効。
  • まとめ: Fragmentを使おうと頑張ったけど、心変わりしました:
    • ほとんどの難解なクラッシュは Fragmentのライフライクル関連のせいだ。
    • Viewとバックスタック、画面遷移があればレスポンシブUIはできる。

自分の想像

今までの自分の理解では、Fragmentは、Viewだけじゃなくて Presenter をモジュール化するものだった。

Androidにおける Activityは、強力でいろいろ見えすぎて、ついいろんなロジックを詰め込みすぎてしまうのはよく言われるところだ。一方、Viewは、すでにある widgetツリーでモジュール化できている。そこで、Activityの一部である Presenter ――― Viewよりもビジネスロジックよりだけど、それほど抽象化もされておらず UIに依存したレイヤ ――― に当たる部分もモジュール化できればより部品の再利用性が高まる、端的に言えばレスポンシブUIができると Honeycombの開発にあたって思ったんだろう。

それだけなら話は簡単なんだけど、G社はそんなに単純に Fragmentを作らなかった。

理由の一つはなんとなく自分にも想像できて、Androidの onResumeとかのややこしいライフサイクルに対応したかったんじゃないか。Presenterの状態は、基本 Modelから生成できるものなので、onStopでそれを開放して onResumeで再生成する、なんてセコいワザを Androidチームは考えていたのではないか。Bitmapとかのでかいデータならそれは有効だろう。

なんで FragmentManagerとかがこんなにややこしくなってしまったかは、ちょっとまだ整理できてないのでおいておく。いずれにしても、G社の人は Fragmentを単なる Presenterの分割法としては捉えず、ほかのいろんなこともさせようとして泥沼にはまっていったんじゃないかしらん。

Fragmentを捨てていいのか?

どうなんでしょう。

自分としてはまだ決心はついていない。いま書いてるコードがもう Fragmentをそこそこ使って安定して動いているので、頑張って移行する気力はないが、今後はなるべく避けるぐらいだろうか。

Presenterについて、かの Squareが言及してくれたのは自分の理解が多少あってたようで嬉しいけど、Squareは自分理論の一つには答えてくれてない: onResumeとかをハンドリングしたいときはどうするんだ?

ここらへん、モダンな環境になれた Squareは気にしないけど、省メモリ至上主義の組み込み屋体質の Androidチームがこだわってたところなんだろうなあ、とか夢想してにやにやしてたりする。実際、自分も onStop()で何かしたいという欲求はないので、必然性が出てきたら考えればいいんだろうなあ。

ヒュベニの式

ヒュベニの式

緯度経度から距離をもとめるのにヒュベニの式というのがあると聞いた。 カシミールのマニュアルによると以下のとおりである:

  D=sqrt((M*dP)^2+(N*cos(P)*dR)^2) 
  
           D:  2点間の距離(m) 
           P:  2点の平均緯度 
           dP: 2点の緯度差 
           dR: 2点の経度差 
           M:  子午線曲率半径
           N:  卯酉線曲率半径 
  
               M=6334834/sqrt((1-0.006674*sin(P)*sin(P))^3) 
               N=6377397/sqrt(1-0.006674*sin(P)*sin(P))

ちょっと見ればわかるように、ピタゴラスの定理に楕円体であることの補正を加えたものだ。平面の距離がもとになってるので、東京からNYCへの距離のような大圏コースをもとめるのはムリだろう。

そこの定数が一瞬謎だが、山だらけというサイトを見るといろいろわかる。

  • 6334834: 長半径 * (1 - 第一離心率 ^ 2)
  • 6377397: 長半径
  • 0.006674: 第一離心率 ^ 2

これを elispでかいてみる。ちなみに上の式は旧日本測地系になっているので、GRS80にあわせるよう適宜数値を直した。

(setq long-radius 6378137.0)
(setq flattening (/ 1 298.257222101))
(setq eccentricity2 (* flattening (- 2 flattening)))

(defun hubeny-radian (x0 y0 x1 y1) 
   (let* ((dr (- x0 x1))
          (dp (- y0 y1))
          (p (/ (+ y0 y1) 2.0))
          (sinp (sin p))
          (w (sqrt (- 1.0 (* eccentricity2 sinp sinp))))
          (m (/ (* long-radius (- 1 eccentricity2)) (* w w w)))
          (n (/ long-radius w)))
     (sqrt (+ (expt (* m dp) 2) (expt (* n (cos p) dr) 2)))))

(defun deg2rad (x) (/ (* pi x) 180))

(defun hubeny (lat0 lng0 lat1 lng1) 
   (hubeny-radian (deg2rad lng0) (deg2rad lat0)
                  (deg2rad lng1) (deg2rad lat1)))

さっそく計算してみる。山だらけにある例で見る.

; 東京、筑波
(hubeny 35.65500 139.74472 36.10056 140.09111)
=> 58502.45893124258


; 成田空港滑走路
(hubeny 35.802739 140.380034 35.785796 140.392265) 
=> 2180.9484697650064

途中で、 latと lngの位置を勘違いしてハマったが、なんとか正しい値が出たようだ。

本当は、さらに大圏コースも含めて正しい測地線の長さが出るようにしてみたかったが、すごく頑張ると楕円積分とか出てきそうなのでやめにする。

ingressと囲碁

ingressと囲碁は似てる、というネタを思いついたので、寄っているうちに書いておきます。

Ingressという陣取りゲーム

Ingressというのは、かの Google社が作った位置情報利用ソーシャル陣取りゲームです。最近は iOS版がでてどかっと Agent (ingressではゲームしてる人のことをこういう) が増えて情報もたくさんあるので、くわしくはググってください。

実は G社にいるときに dogfoodとかやってた気がしたんですが、なにナードの集団の G社がゲームなんか作ってるんだよ、面白いもんできるわけないやんけ、と思って参加してませんでした。ということでやり始めたのは G社やめた後です。

やってみるとはまっています。会社の行き帰りに色んな道とおってうだうだ青くするのがたのしいっす。自転車をいかして、駅の遠くに頂点をおいて、このフィールドは壊せないだろとニソニソしたり。

最近は、他の Agentとの絡みも増えてきて、責任感とか感じてやめられなくあたり、単なるソシャゲです。噂によると、ingressサークルの姫もいるらしいです。コミュニティ崩壊を G社がどう防ぐかが見ものの気もします。

囲碁という陣取りゲーム

囲碁というのは、が作った二人対戦陣取りゲームです。iOS版もくそもなく2千年ぐらい東アジアで流行ってます。今の日本ではいまいち流行ってないという雰囲気もしますが、ちゃんとテレビ番組もやってるし対戦相手も棋院とかにいけばいっぱいいるので全世界的に見れば流行っていると言ってもいいんじゃないでしょうか。

囲碁は陣取りゲームと言いつつも、石取りゲームという側面もあります。自分の陣を広げるより相手の石を取るのに夢中になって、結局石はとれたけど全体的な陣地では負けたとか。素人ではたまにある話です。

自分は、どちらかと言うと布石と厚み重視の打ち方をしてるつもりです。序盤でうまく石を置いて全体的になんとなく自分の陣地っぽいもの (囲碁の用語では模様) を作って、相手にプレッシャーをかけつついじめて勝つという。でも、実際は陣地じゃなくてあくまで「っぽいもの」なので、端っこの守りがちゃんとできてないところから食い破られて損して負けちゃったり。まあ、ここらへんは、子どもと打っているうちにそうなっちゃった気がします。子どもというものは細かい石取りは好きで得意なので、そこらへんで勝負しないように成長してしまったと。

で、ingressでも同じように行動してる気がします。自転車を使ってるせいもあるけど、とりあえず大きくリンクを張って、敵の行動を制限する模様を作る。もちろん敵も頑張れば壊せるけど、リンクが長めなので、端点の近くまで行かないと壊せない、忙しい人にはちと邪魔者なわけです。

そしてその後、自分が作った模様の中で戦ってじわじわ敵を制圧する。中にいる味方 Agentにもなんとなく手伝ってもらって、フィールドをつくってもらってニソニソする。そういう感じです。

まあ、そうじゃないひともいて、とにかくガンガン壊していこうぜ、って人もいます。囲碁だったら石を取るだけじゃ陣地を取れなくて負けたりするけど、ingressは敵の拠点を壊すだけでも点数 (Action Pointっていいます) が入るのでレベルは上がっていく。ソシャゲなので、あとから陣地屋さんが来て、リンクを張って APを稼ぎつつ肥沃な大地にしていく。そういう役割分担もあります。囲碁と違って終わりもないので、どっちの遊び方が正しいとも言えません。ま、いろいろあると。

まとめ

囲碁と ingressは似てるって最初は思ったんだけど、最後はちょっと違うって話になってしまった。

強引にまとめれば、どっちも色んな遊び方があって個性が出るなあ、っていうことでまとめていいでしょうか。酒も切れてきたのでここらへんで終わります。さようなら。

Viewpoint Research Instituteに行ってきた

大学の同級生である よしきに招待してもらって、USは LAにある Viewpoint Research Instituteに 2日ほど訪れました。VPRIは、あの Dynabook発案者の Alan Kayひきいる研究所と思っておけばいいんでしょうか。

ちなみ自分が行った時は Alanは夏休みだとかで会えませんでした。

VPRIとSAP Communications Design Group

実際に訪れたところ、VPRIだけではなく、SAPの人も渾然一体となって働いていて、彼も正確には SAPの所属になったとかでややこしい頃でした。今更帰って調べてみたところ SAPの CDGってところと一緒になってるみたいです。CDGの BayAreaの研究所からも人が来てた話してたりしました。

たしか、最初に Alanの Groupにあった時、彼らは Appleで、それから自分の知る限り Disney、HP、SAPといろいろと動いていて、中国戦国時代の食客のようだなあ、と思いました。

みたこと

まあ、ちゃんとしたアジェンダもなくいきなり乗り込んでいったので、コンテキストについていくのが大変でした。

Geometric Constraint

研究者の一人、Alex Warthが推してるのが図形上の制約を使った UIでした。元ネタは30 Years from Sketchpadってやつです。自分はまだ paperは読んでないんですが、実際に使わせてもらったところ、簡単に制約を使ってエンジンとクランク機構みたいなアニメーションが作れました。アルゴリズムもそんなに複雑じゃないようです。

で、それを、後述する Lively Kernelと合わせる話とかしてました。面白い絵は作れるけど実用的なのかよ、とか議論になってたけど、自分はそのとき Lively Kernelってなんだかわからなかったのでちんぷんかんぷんでした。

Lively Kernelとか

Lively Kernel とは、Javascriptに Smalltalk80のような対話実行環境をつけたものらしいです。リンクをたどって右クリックとかしてみると System Browserとかでて、対話的に編集できます。さらに独自のデバッガーとかもあって、デバッグ中でも編集したのがすぐに反映するように苦労してる、とかいうのを話してました。

MIT

MITのメディアラボの人が来て、人工知能っぽい話もしてたりしてました。常識を推論させる はなしや議論を助けるシステム等。実はあまり興味なかったので、いろいろ大変だなあ、ぐらいの感慨です。

まあ、そこでみんなが比較対象として言ってたのが Cycorpという会社でした。知識データベースを作って、実際にビジネスにしてるらしい。やるところはちゃくちゃくとやってるんだなあ。

J と K

よしきが J に興味を持っているということで、ながれで K とかの話をしました。なんでも、Kの開発者は変数名とかが 1文字のみならず、日常使うコマンドからログイン名まで1文字らしいっす。すごい。パスワードも1文字なんだろう、といってました。

まあ、ここらへん、金融系とかで脈々と使われていたりして、うまく頑張ればデータ解析用に広まったりすると面白いなあ。

その他

17年ぐらい前に OOPSLAで会った Toddに再会しました。偉くなって こんどの OOPSLAの Chairらしいっす。出世したなあ。

あと、オフィスの感じは開放的でした。まあ、ずっと雑談してる人が多くて、オフィスには話に来て家で仕事してるんじゃないかと思うぐらい。非コミュな自分としてはよくそれで生産性上がるなあとか。

Alexには制約処理系のソースコード分けてもらったんで、ちょっと改造して遊んでみたりしたいところです。

Android WebViewの cookieではまった。

仕事でハイブリッドアプリケーションを使っていてはまったので、他山の石となるべくメモ。 あと、これは 4.2.2 (Jellybean) でのことなので、4.4の Chromiumベースの WebViewでは 話が違っている可能性も大。

WebViewの session cookieは、かなり生存力高くリブートしても消えない!

Session cookieっていうのは、expireが指定されておらず、ブラウザのセッションが終わったら (= PCではブラウザアプリが終了したら) 消えてなくなる cookieです。 ところが Androidではこれがほっといても消えない! Activityがなくなっても、あまっさえデバイスが再起動しても消えない!まあ、考えてみるとスマフォでは「セッションってなんだ?アプリケーション終了って?」って話なので、セッションなんて環境依存したものに依拠した仕様がどうかと思うけど、リブートしても残ってるのはややびっくり。

これは StackOverflowにもしっかり書いてあります。

You are correct, session cookies do not expire automatically in the lifecycle of a WebView. If you are seeing issues with this, you can always clear all of your cookies or overwrite your session cookies explicitly with an empty value.

実際に、下の実験スクリプトで「記録」ボタンを押して、数分待ってからリブートしてこのページを訪れれば、先ほど設定した値が残っているはず (session cookieなのに!)。ちなみに数分待たなきゃいけない理由は後述。

実はこれに直接はまったわけじゃない。本当は cookieが消えるバグがあって、その原因は Session cookieだからだろう!と追っていったら単なる勘違いでした。でも間違った方向に進んで数時間無駄にした。

WebViewの cookieは、すこし待たないとフラッシュに保存されない!

よく見れば CookieSyncManagerに書いてあるんですが、Cookieの永続化は非同期に裏でやってるので、Cookieを書き換えた瞬間にアプリが死んじゃうと、変更したはずの cookieが次のセッションに反映されない。

今やってるやつは、cookie書き換えた直後に 強制アップデートしてたりするので、そこでプロセス終了して書き換えた cookieがどこかにいってはまったのでした。

もしもほかに強制アップデートさせることがあるひとがいたらご注意を。あんまりいないと

前節の実験のところで「数分待って」と書いたのもこのせいです。待たないと永続化されないので、再起動後には cookieは残ってなく session cookieが消えてめでたいように見えるのです。

この永続化ディレイは、実験スクリプトで「記録」ボタンを押してすぐにブラウザアプリを殺す (アプリ履歴で横スワイプする) と確認できます。

実験スクリプト

バイトコードをいじらないといけない

今日は (というかもう昨日になってしまったが) Potatotips #7 というモバイル系の勉強会にいって発表 & 拝聴してきた。

内容に関しては 八木さんの記事 がまとまっているのでそっちを参照してください。自分は TravisCIについてすごく簡単な発表をしたんだけどまあ、それは置いといて。

全体的にバイトコードいじりというか、メタプログラミングっぽいのが目立ってた。Android側で言うと次の3つ:

Android側は、すべてコンパイル時に Javassistとかをつかってなんとかする、ってやつ。gfxさんの「コンパイルが遅いと愚痴りつつ、さらに遅くなる処理を入れるマゾ」という言葉が印象的だった。

iOS側は Aspectプログラミングをやるほか、 Swizllingっていう仕組みを使って実行時にメソッドの実装を置き換えてやることができるらしい。うーむ、ObjectC気持ち悪い。Dalvikも頑張ってもっとへんな柔軟性を獲得しないと。ART頑張れ。

いずれにしても、バイトコードをわけもなくいじりたくなった発表会でした。JVMじゃくて DalvikVMのコードをいじって変なことできないかなあ。

スマホUI考

友人の有野くんが YouTubeでスマフォの UXについて一席ぶっていたので考えた。

UXにそんなに工数かけてたっけ?

彼いわく、正しいスマフォアプリは90%ぐらいの工数をUXにかけると。まあ、これは彼の煽りも入っているんだろうけど、正直そこまでの感覚がない。

自分が Google Mapsを作っていた時の感覚を考えると、UXの調整 (どうやって点線を位相を揃えてうまく表示するかとか!) も時間使ったけど、非同期処理とか機種ごとにアイコンサイズを調整するためのプロトコルに時間がかかった。

というか、ここらへんの処理までも有野君は UXに入れているんだろうか? もし、そうだとすると考えてみれば自分の仕事は確かにほとんど UXだった気もする。

Googleでは当然、そこらへんが重要だという知識が最初から蓄積されているので、最初の設計段階から考慮に入れている。よって UXをやっているという感覚はなかった。ちなみに、地図本体のレンダリングに関しては、そもそも調整に時間がかかるという前提でスケジュールが組んであった。凄腕のプログラマのチームをもってしても遅れがちで、自分はやきもきしてた気がする。

G社以前で仕事をしていた組み込み系でも当然そういうのは考えていたけど、でもそんなにうまくなくて、有野君のいう「QAなにやってんだ」レベルのものを出してしまったのもあって申し訳ない。まあ、でも今ほど期待値も高くなかったからよかったのかなあ。

異常系とか

あと、最初に考慮するので面倒なのが異常系および復帰処理。

今作っている 自動アップデート機能 もそこらへんがややこしくなってしまって、面倒くさいなあと思う反面、ちゃんと作れたのは組み込み系のころの経験がものをいってるなあ、という気がする。

Webアプリはそこらへんが楽で、最後の手段としてユーザにリロードボタンを押してもらうという逃げがある。サーバからデータを取ってきて0からはじめることになる。羨ましい。

ここらへんも設計時にちゃんと洗い出す文化なら UXの増大にはならないけど、非同期処理とかを増やすたびにその失敗のケースは増えるわけで、あとから調整すると大変なことになるのは確かだろうなあ。

Webはそんなに楽なままなの?

対比として Webアプリがあげられているけど、じゃあ、なんで WebアプリのUXがそんなに楽なんだろう。HTML5でモバイルのアプリも作れば楽なのか。PhoneGapでガワを被せて配ればいいのか。

きっとそうじゃないんだろう。HTML5で作っても結局、前提となるもの (それなりに広いモニタとか、安定したネットワークとか、画面幅の差異とか、所詮Webだという期待感とか) がなくなれば同じような苦労をするようになるんだろう。そんなに楽な話があるわけがない。

というのは、Javaに慣れ親しんだ自分のポジショントークもあるけど。

まて次号

でも、有野君の話はまだつづくので、そういうことを言ってるのじゃない可能性も十分ある。話が終わるまでもう少し見てみよう。