Android らしい Java - 3. 薄い抽象
Android プラットホームの API はひどい。
プラットホームというもの一般の API デザインが時代にあわせ少しずつ良くなる中、Android は時代を10年くらい巻き戻した感がある。深い継承。でかいクラス。ヒラより多いマネージャたち。コンサーンもレスポンシビリティもテスタビリティも何もない。
モバイルデバイスには従来の Java が気にかけなかった様々な制約がある。同じように行かない。それはわかる。でもねえ。
過去にもひどい API のプラットホームはあり、人々は大きく二つの方法で立ち向かった: 一つ目は、プラットホームを無視して自分で再発明する方法。Qt や XUL, Swing みたいなクロス OS のツールキットはだいたいこの路線。二つ目は抽象化レイヤをかぶせて隠す方法。Windows API に対する MFC, WTL や SWT. あるいは DOM に対する jQuery.
Android 上での再発明が進んでいる様子はない。クロス環境のツールは概ね失敗している。それはユーザがネイティブの手触りを重視するようになったからでもあるし、再発明のオーバーヘッドを許せるほど端末の性能が余っていないからでもあるだろう。React Native は例外的に頑張っているが、今のところ決定打ではない。
抽象化路線はどうか。従来の抽象化レイヤは下の API をすっぽり包んで表に出さないものが多かった。その大げさな作りを「漏れのない抽象化」と有難がりさえした。
Android で人気のライブラリに大げさな抽象は少ない。ボイラープレートを引き取ったり、プラットホームに足りない機能を追加するピンポイントが主流。Xamarin のような異言語環境ですら忠実に API をマップしていて驚く。
あるとき有力なオープンソースライブラリ開発者の一人が悪名高い API "Fragment" のボイコットを提案し、大きな議論を呼んだ。Fragment は Android API のダメさを凝縮した存在だと思うし、私も仕事で苦労している。でも多くの Android 開発者はボイコットに抵抗を示した。自分の同僚を見回しても特に Fragment を憎む様子はない。
プラットホームの API を使おうとするこの強いバイアスは、従来の Java にはなかったものだ。サーバサイドの Java では JDK に入っている機能を再実装, フレームワーク化するのが当たり前。XML パーサなんて何個あるかわからないし、Servlet API を捨てることだって辞さない。
このバイアスはどこから来るのか。一番の理由はオーバーヘッドだろう。ライブラリを使うとコードが大きくなるし、遅くなる。しょぼい端末を相手にしうる Android アプリにとって、でかさや遅さは命取り。だから最小限にしたい。
コミュニティの体力も理由だと思う。Android 開発者コミュニティはまだ全盛期の Java コミュニティほど大きくない。だから包括的なフレームワークや再発明が筍みたいに生まれたりしない。少ない数の人々がピンポイントで穴を埋めている。
文化的な違いも感じる。従来の Java は、それ自体がクロス OS を目指す再発明プラットホームだった。Android Java に「ラッピング」レイヤとしての意図はない。Android の API が source of truth. アプリ開発者もそんな直截さを感じ取っている、気がする。
レイヤは薄く留め、プラットホームのらしさを活かす。このバイアスは Android Java の良い所だと思う。API のデザインはプラットホームの特性を織り込んでいる部分も多い。開発者が API を学び使いこなそうとするほど、アプリは「ネイティブらしく」振る舞うようになる。
抽象化の規模を抑えたい。けれどそこにはプラットホーム API のひどさという難敵が待っている。そのバランスをとるゲーム。Android Java にまつわるライブラリやデザインの議論を眺めるときはそんなことを考える。たとえば自分の感覚だと MVVM や ORM は大げさすぎる。
でも何か良いアイデアがあるわけではないし、使う人を責める気もない。
Android らしい結論が出るのは、 .NET や JS が通った道を多くの Android 開発者が追体験したあとだろう。 Effective Java や Marrin Fowler について延々語る Podcast を聞きながら先行きに思いを巡らせる。