The Complexity of a UI

つづき

Redux の one-way data flow というアイデアは正しいので取り入れたいが、UI 全体を一つの状態で表現するのは自分の目的にはエクストリームすぎるし変更がでかすぎるので仕事で使うことはなかろう。Reducer 使おうとか人々を説得できないわ。

そして Redux にせよ MVx にせよ自分の面している主要な問題を解決してはくれないことに気がついた。それはおそらく、相手にしている問題が典型的な JSON からリストを表示するお仕事ではないせいに思える。

"App Architecture" の皆様が暗に共有している前提がある: 沢山の種類のデータがあって、それを表示するために沢山の画面を素早くつくらないといけない。そして画面の作り方はなるべく標準化されていてほしい。この Airbnb チームの記事は彼らのライブラリ MvRx で 100 screens 作ったよと誇っており、この要件を鮮やかに伝えている。

自分たちのアプリは大きな activity が二つしかなく、そのうち一つは設定 activity。自分の関心はもうひとつのメインの activity だけである。しかしこの画面が割と複雑でなんとかしたい。

カメラアプリには複数の「モード」がある(例: 写真、ビデオ)。しかしこれらのモードは同じ画面、同じ UI を共有している。この「モード」は言ってみれば reactive な data source / model. 常識的に考えると個々のモードごとに別の画面にするのがラクなわけだが、シームレスさなどの都合でそうはなっていない。

モード間で UI がまったく同じならまだ話は簡単なのだが、当然そうはいかない。shutter button の色がモードごとに変わったりする・・・のはまだいいとして、たとえばビデオだと録画時間を表示するだとか、長時間露光モードではプログレスを表示するだとか、そういうのがコード上には全部つっこまれている。

つまり一つの UI を複数種類の "model" が共有しており、そのときアクティブな mode / model が UI を専有する。当然ユーザとのインタラクションもモード次第。

そんなら各モードが勝手に UI を使えばいいじゃない、というとまあまあそうなのだけれど、現実には大量のコピペが発生する。なぜならモード間で共通の挙動も沢山あるから。そいつらをなんとか factor out してあげたい。しかし各モードは違う人々によって実装されているので、そういう cross-cutting concerns は見逃されがちである。

モード固有の UI にも問題が多い。あるモードが新しい UI を足すと、他のモード固有の UI に干渉したりする。なぜなら画面の real estate が限らているから。モードの切替時に飛ぶ鳥後を濁さないようにしてほしいのだが、モードの切り替えは mess になりがちである。

そしてモードの切り替え、およびアプリの起動はなるべく速くしたい。多くのアプリでは UI の初期化なんてネットワークリクエストの遅延でマスクできたりするのだけれど、カメラの HAL の初期化はそれなりに速い場合もあるのでデバイスの性能によっては UI の初期化がクリティカルパスになる。全てのモードの UI を非表示の状態で雑につっこんでおく、とかやられるとどんどん遅くなってしまう。Lazy に初期化しないといけない。しかしそうした laziness を後から足すのはわりかし骨が折れる作業である。その UI 部品が複数のモードから共有されていると特に。

そして様々なデータソースがガチで reactive というか realtime stream である (例: autofocusの位置.) UI も immersive なので drag みたいな操作が頻出する (例: ズーム). ViewPager にまかせとけばいい、というわけにはいかない。

そして画面の回転をシームレスにするためのロジックがこれら全てをじんわりと複雑にしている。

とか色々問題がある割に UI は割と頻繁にかわる。なぜならコンシューマ製品には見た目の新鮮さが欠かせず、しかし製品の性格上「画面の背景色」などがあまり存在しないので色とアイコンのような theme をいじってごまかす手が使えないからである。

めんどくせー。


大げさにいうと、カメラの UI は「モード」というプラグインを差し込むためのプラットフォームである。モードに必要な拡張性、カスタマイズ性を提供しつつ、挙動の一貫性やモード間の隔離や性能を保証することが期待されている。しかしそういう複雑さと戦う準備がまったくできておらず現状の mess に繋がっている。UI は detail とかいったひと、こっちきて clean architecture とやらで手伝ってくれや・・・。

この "UI は detail" の態度は自分たちのチームにも若干あり、それは比較的 junior なプログラマが UI 共通部を担当している事実から伺える。皮肉なことに、モードとかがそんなに沢山なかった製品開発の初期には割と実力のあるプログラマが色々作り込んでいた形跡がある。現状の UI の扱いにはそうした人々が move on した "保守フェーズ" という暗黙の想定を感じる。

でも QA cycle を消費しているのはそうした UI の mess に起因するしょぼいバグたちであり、UI のコード品質がチームの velocity 下げてますよね? OS の HAL や画像処理アルゴリズムのネイティブコードのクラッシュや AI 的機能の concurrency にまつわる微妙な deadlock や性能のオーバーロードによる瞬間的なコマ落ちなどは「難しい問題」でシニアな人々が沢山でてきて頑張って相手をしている一方でしょうもない UI のバグを相対的にシニアでないプログラマが直したりしているけれども、消費されている関心ではなく単純に出荷 delay でのインパクトだけを見たら「しょうもない UI バグ」の影響はなかなかのものなんじゃない?

もっともこれを "UI は detail" という態度の帰結だというのはあまりフェアではないかもしれない。どちらかというと "UI は壊れやすいもの" という諦めの帰結という方が近い気がする。どちらにせよ個人的にこれは受け入れがたい結論である。我々の UI は (競争的優位ではないかもしれないけれど) チームの生産性にとって瑣末なものではないし、それは良いコードによって改善できる問題である、はず。

というわけで今年の残りと来年は UI なんとかするぞ!その「難しいバグ」はお願いだからこっちくんな!という心意気になった今日この頃。ただ上の方の人にそういう認識がないので、肩身が狭いのだよなあ。「難しい問題」の呪いを感じる。