この記事には実証版があります。 同じ主題を、動くコードと実際に描かれた画面で作り直しました — 画面の層だけが溶ける — インストールなしのアプリ、そしてコンパイルが凍らせたもの。この記事は書かれたまま残します。
前回のVol「インストールなきアプリの時代」で、私たちは大きな主張をした。画面を機器ではなくサーバーが定義すれば、ビルド・審査・インストール・更新という長い鎖がまるごと消える、と。反応はちょうど半分に割れた。「それは本当にできるのか」と「もう似たものを使っていた」。どちらの反応も同じ場所を指していた — その鎖が当たり前ではないということを。
今回のVolは、その鎖をもう一つ深く掘り下げる。鎖には多くの輪があるが、すべての輪がぶら下がっている最初の輪が一つある。あまりに底にあって普段は見えもしない輪。コンパイル。 この文章は、コンパイルが画面に何をするのか、私たちがどうしてそこに閉じ込められたのか、そしてそれが必然ではなかったことを語る。長い文章になるだろう。鎖の根を扱うのだから。

コンパイルは翻訳ではない
コンパイルを辞書的に定義すれば「人が読むコードを、機械が実行する形へ翻訳すること」だ。間違ってはいない。コンピュータの授業の最初の時間にそう習う。ところがこの定義は、コンパイルが画面に何をするのかについては一言も語ってくれない。
画面の観点からコンパイルをもう一度定義してみよう。
コンパイルとはその瞬間のすべての決定を、たった一つの固い塊に凍らせて入れることだ。
ボタンが画面のどこに置かれるか、色は何か、文字の大きさはいくつか、押すと何が起きるか、その次どの画面へ移るか — この数百の決定が、コンパイルされるその瞬間に凍結される。別々に散らばっていた決定が一つの塊に固まり、その塊が機器に植えられる。この凍結には明らかな利点がある。固まったものは速く、予測可能で、安定している。ユーザーの機器で一貫して動く。
問題はその次だ。凍らせたものは、また決定し直すのが難しい。
ボタンの色を一つ変えたいとしよう。決定を一つだけ変えればいい話だ。ところがその決定は、すでに他の数百と一緒に一つの塊に凍っている。決定を一つ取り出して直すには、塊全体を溶かし(ソースを開き)、その決定を変え、また丸ごと凍らせ(再びコンパイルし)なければならない。そして新たに凍った塊をまた機器に植えねばならない — パッケージングし、署名し、ストアに上げ、審査を待ち、配信して。前回のVolで長く描いたあの鎖は、別の角度から見れば氷を溶かしてまた凍らせる一サイクルの費用だった。
ここにこの文章の最初の結び目がある。私たちが耐えてきた配布の苦痛は、怠慢や古い道具のせいではなかった。「画面という決定が機器の中に凍っている」という構造から必然的に流れ出たものだった。鎖を罵るのではなく、氷を見なければならない。
私たちはどうして氷に閉じ込められたか
この氷は初めからあったわけではない。短く系譜を辿ろう。今の息苦しさがどの地層で固まったのかを知れば、何を溶かすべきかも明らかになる。
第一世代 — パッケージソフトウェア。 プログラムをCDやフロッピーに収めて売っていた時代。画面もロジックも、すべてコンパイルされてユーザーのコンピュータにまるごとインストールされた。直すには新バージョンをプレスして郵送し、ユーザーが再びインストールせねばならなかった。更新の周期は四半期、運が悪ければ年単位。氷の原型がここで作られた — プログラムの本体が機器の中に凍っている。 当時はこれが唯一の道だった。ネットワークが遅かったか、そもそもなかったから。
第二世代 — ウェブ。 ブラウザが前提をひっくり返した。ウェブページはコンパイルされない。サーバーが「ここに見出し一つ、その下に段落一つ、その下にリンク一つ」と書かれた文書を送れば、ブラウザはそれを受け取った場所で描く。画面は機器に凍っていない。訪れるたびにサーバーが定義するとおり新たに描かれる。だから直しが即座だった — サーバーの文書を一行変えれば、次の訪問者は変わった画面を見る。ビルドもインストールも更新もなかった。鎖の最初の断絶だった。私たちは自由になった — 文書を扱うかぎりにおいて。
第三世代 — アプリストア。 スマートフォンが登場すると流れは逆戻りした。カメラ、GPS、加速度センサー、プッシュ通知、オフライン動作、指にぴたりと吸いつく六十フレームのアニメーション — ウェブがその頃は与えられなかったネイティブの能力のために、私たちは再びコンパイルされて機器にインストールされるアプリへ戻った。画面をまた凍らせたのだ。そして今度は氷の上に一枚さらに乗った。ストアという関門と審査。鎖は第一世代より長くなったまま再び固まった。
ここで最も大事な一つを見なければならない。私たちがアプリストアモデルへ戻った理由はネイティブの能力ゆえであって、コンパイルとインストールと審査という氷を望んだからではなかった。氷は能力を得るためにやむなく付いてきた費用だった。ところが時が流れるうちに、私たちはその費用を能力と一束に見なすようになった。「ネイティブの能力を望むならコンパイルも、鎖も甘受せよ」と。この文章が問うのが、まさにその束だ。能力と氷は本当に分けられないのか?
業界がすでに氷を割ろうとした痕跡
業界がこの氷をただ耐えていたわけではない。割ろうとする試みは続いてきた。そしてその試みの成功と限界を見れば、本当の解法の輪郭が浮かび上がる。
ハイブリッドアプリ(ウェブビュー)。 アプリという殻の中にブラウザを入れ、画面はウェブで描いた。画面をサーバーで変えられるので氷が一部溶けた。しかし代償が大きかった。ウェブビューはネイティブほどなめらかでなく、機器の深い機能に届きにくく、ユーザーに「ウェブのようなアプリ」という中途半端な印象を与えた。能力を一部あきらめて即時性を買ったわけだ — 私たちがそもそもウェブを去った、まさにその能力を。
コードプッシュ(ホットアップデート)。 審査を経ずにJavaScriptのバンドルを機器へ押し込み、アプリのロジックを更新する方式。緊急の修正には有用だった。しかし本質は依然として機器にコードを凍らせることだった。ただ少しだけ柔らかい氷だっただけ。ストアのポリシーと綱引きをせねばならず、大きな変更は結局正式な審査に戻らねばならなかった。氷を割ったのではなくわずかに柔らかくしただけだ。
サーバードリブンUI(SDUI)。 ここからが本質に近づく。大手サービスが静かに使ってきた方式だ。画面の構成 — どのカードを、どの順で、どのデータで見せるか — をサーバーが仕様として送り、アプリはその仕様を受けてネイティブのウィジェットで描く。フィードやホーム画面のように頻繁に変わる領域で威力を発揮した。画面を液体のまま置きつつ(サーバーが定義)、描く手はネイティブに残した(アプリが描く)。三つの試みの中で最も正解に近い。
ところがSDUIにも天井があった。たいていは各社が自社サービスのためだけに作った閉鎖的なシステムだったという点だ。その会社のそのアプリでのみ動く仕様、その会社のサーバーとだけ話す構造。汎用の標準ではなかった。だから「うちのフィード画面はサーバーが定義する」はできても、「どんなサーバーでも、どんな機器にでも、画面と道具を定義して送る」はできなかった。氷を自分の庭でだけ溶かしただけで、庭の外へは持ち出せなかったのだ。
ここまでが業界の到達した地点だ。即時性はウェブが、能力はネイティブが、画面の動的定義はSDUIが、それぞれ証明した。三つとも揃っていた。ただその三つが一つの開かれた標準の上で出会ったことがなかっただけだ。
氷を取り出すが、能力は守る
サーバー主導UIが — この雑誌が扱う方式が — することが、まさにその未完の合流だ。画面という決定だけを溶かし、描く能力はネイティブに残す。そしてその合流を一社の庭ではなく、開かれた規約の上で行う。
構造を見よう。サーバーは「タイトル一つ、その下にボタン一つ、ボタンを押すとこの道具を呼び出す」という軽い定義を送る。機器にあるのは、その定義を受けてネイティブのウィジェットで描く汎用のランタイム一つだけだ。画面はウェブのように液体のまま残り、描く手はネイティブそのまま。カメラも、センサーも、六十フレームのアニメーションもそのまま使える — 描く側が本物のネイティブランタイムだから。私たちがウェブを去る際にあきらめた能力を、今度はあきらめない。
このとき機器の中にはもはや「このアプリだけの、コンパイルされて凍りついた画面の塊」がない。何が来ても描いてくれるランタイム一つがあるだけだ。だから画面を変える行為の物性が変わる。以前は氷を溶かしてまた凍らせる行為だった — ソースを開き、直し、コンパイルし、植え。いまは液体に指を入れてかき混ぜる行為だ — サーバーの定義を一行直せば、次の更新で画面がそのまま変わる。同じ「ボタンの色を変える」が、一方では三日かかり、一方では十秒で済む。二つの違いは努力ではなく物性だ。
ひとつの場面
抽象的に聞こえるだろうから、ひとつの場面を描こう。サーバーにこんな定義が入っているとしよう — 「この画面には歓迎の文句が一つ、その下にボタンが一つ。ボタンを押すと注文の道具を呼び出す。」 ユーザーがアプリを開くと、機器のランタイムがこの定義を受けてそのまま描く。文句とボタンが現れる。
いまあなたがサーバーでその定義を直す。「ボタンを二つに。一つは注文、一つはキャンセル。色は青。」 保存する。次の瞬間、店内にあるすべての機器の画面でボタンが二つになる。店員たちは何もしていない。更新を押しも、アプリを取り直しも、ストアに行きもしなかった。あなたはコンパイルせず、審査を待たず、配信ボタンを押さなかった。定義を一行直しただけだ。十分の決定が十分ですべての画面に届く。 鎖がまるごと消えた跡だ。
当然浮かぶ反論
ここまで読んだ技術者なら頭の中にいくつもの反論が浮かんだはずだ。その反論に正面から答えなければ、この文章は空虚な宣言に終わる。一つずつ片づけよう。
「画面を毎回サーバーから受けたら遅くないか?」 画面の定義は小さい。重いコードのバンドルではなく、「ボタン一つ、テキスト一つ」分の軽い仕様だ — たいてい数キロバイト。しかも一度受けた定義はキャッシュされる。肝心の重いもの、すなわち描画エンジンはすでに機器にネイティブである。サーバーが定めるのは何を描くかであって描く行為そのものではない。ユーザーが体感する性能はネイティブそのままだ。
「ではオフラインでは何もできないのか?」 キャッシュされた定義は接続が切れても動く。最後に受けた画面はそのまま出ていて、定義が変わるときだけサーバーに尋ねる。「常に接続されていなければならない」という誤解は、毎瞬間サーバーを呼ぶという誤った図から来る。実際には変更分だけやりとりする。ウェブがPWAでオフラインを得たのと同じ原理だが、ネイティブランタイムの上でだ。
「また新しいフレームワークを学べというのか?」 いや。核心は新しい道具ではなく順序が変わったことだ。画面をコードで書いて機器に凍らせていた場所に、画面を定義としてサーバーに置く。学ぶべきは巨大な新体系ではなく「定義を書く方法」一つだ。だから入門が十行で始められる(このVolのコーディング記事がその十行を開く)。
「セキュリティは? サーバーが画面と動作を送るなら、悪意ある定義を送ることもできるのでは?」 だからランタイムは受けた定義を信頼せず検証する。 定義ができることはランタイムが定めた境界の中に縛られる — 任意のコード実行ではなく、あらかじめ定義されたウィジェットと道具の組み合わせだけが可能だ。ブラウザが任意のサイトのJavaScriptをサンドボックスの中だけで実行するのと同じ発想だ。(この境界をどう引くかは、次のVol「すべてのサーバーがアプリだ」で正面から扱う。)
「アプリストアのポリシー違反ではないか?」 微妙な領域で、正直に言って場合による。ストアは「審査を迂回して、アプリの核心動作を任意のネイティブコードでまるごと変える」ことを警戒してきた。しかし「サーバーがコンテンツと画面構成を定義する」ことは、すべてのフィード、すべてのコマースアプリがすでにやっていることだ。境界は任意のコードを植えるかにあって、画面をサーバーが定義するかにはない。このモデルが後者にとどまるかぎり、既存のSDUIがそうだったようにポリシーの内にある。(ただしこれは解釈であり法律の助言ではない。実際の適用時には各ストアの最新ガイドラインを確認すべきだ。)
ではコンパイルに何が残るか
正直に片づけよう。コンパイルが消えるのではない。場所を移す。
リアルタイム制御、重い計算、機器の深いところのドライバー、セキュリティの底 — こうしたものは依然としてコンパイルされ、機器とサーバーに固く立っていなければならない。ミリ秒を争い、一寸も揺れてはならないものは凍らせたままにするのが正しい。溶けるのは人が見て押す画面の層だ。何を見せるか、どう配置するか、どんな流れでつなぐか — 頻繁に変わり、頻繁に実験され、人ごとに違っていなければならないその層。
考えてみれば画面は本来、頻繁に変わるべきものだった。値札が変わり、メニューが変わり、ボタンの位置を実験し、ユーザーごとに違うものを見せる。そんなふうに頻繁に変わるべきものを、私たちは最も変えにくい場所(コンパイルされた機器の中)に凍らせておいた。それが不自然だったのだ。私たちはコンパイルを捨てたのではない。
コンパイルしてはいけなかったものを、コンパイルから取り出しただけだ。
固くあるべきものはより固く凍らせ、流れるべきものは流れさせる — その分離がこの転換の核心だ。
だから、疑え
ここまで読んでも「それでも本当にできるのか」と思うなら、その疑いが正しい。文章で書いたビジョンはいくらでももっともらしく書ける。歴史をもっともらしく通し、反論にもっともらしく答えることもできる。大事なのはそれが実際に動くかだ。
だからこの雑誌はビジョンを長々と並べるところで止まらない。今回のVolの次の文章たちで、私たちはその液体状態の画面が最も固い場所 — チップの上で — どう動くかをじかに見せる。専用のGUIも、ファームウェアの焼き込みもなく評価ボードを触る一人のエンジニアの午後を。そして、コーディングを知らない農家が三十年分の畑の記録をどう画面にしたかを。氷を取り出せば、触れる人が増える — それがこのVol全体の話だ。
最後に一つだけ残しておこう。あなたが最後に何かを「再コンパイル」したのはいつか。画面の一行を直すためにその全過程をもう一度回したのは。その慣れ親しんだ儀式が — 少なくとも画面という層では — 消え始めている。
makemind.dev 「探索」— 「コンパイルを捨てる」Volの巻頭です。画面がコンパイルから解き放たれると何が変わるのかを、チップと畑で辿ります。