12/1 に Qiita のトップページをリニューアルしました。これまで React を使っていましたが、それをやめて hyperapp を採用しました。まわりを見てもあまり採用事例が見当たらないので、この記事では一体なんで今をときめく React ではなく hyperapp を選択したのか、どういうところが魅力的なのかについて

  1. プレゼンテーション層を実装するためのツールとして
  2. 学習コスト

の観点から書きたいと思います。なおこの記事に書かれていることは全て個人の感想であり、はっきりいって個人の日記レベルです。

TL;DR

  1. プレゼンテーション層を実装するためのツールとして
    • React は機能過多だし、機能不足
    • hyperapp は過不足ない
  2. 学習コスト
    • 仮想 DOM は学ぶ価値のある知識
    • React はまだしも周辺ツールの栄枯盛衰で死ぬ再利用できない知識が多すぎる
    • hyperapp は固有の知識がほとんど要求されない

1. プレゼンテーション層を実装するためのツールとして

新しいことを始める時、ついフレームワークを何にするかから考えてしまいがちですが、本来は先にプロダクトの要件があって、そこから適切な開発言語やアーキテクチャの選択があり、そしてそれを実現するためのフレームワークないしライブラリを選定する必要があります。

今回の開発の要件を雑に一言でいえば「拡張性とメンテナンス性を持ったリッチなクライアントアプリ」を作るということでした。そしてこの分野では Web よりもむしろモバイルのネイティブアプリ界隈に一日の長があるように思います。実装環境に技術的な差異は多々あれど、ネイティブアプリ界隈の知見は参考になるはずです。

Android-CleanArchitecture とクリーンアーキテクチャ

色々と調べていった中で最もいいと思ったのが Architecting Android...The clean way? で取り上げられていた Android にクリーンアーキテクチャを適用する話でした。

クリーンアーキテクチャがドメイン駆動設計をベースとしたアーキテクチャであること、個人的に注目している Ruby 製 Web フレームワークの Hanami もクリーンアーキテクチャに強い影響を受けていることなども目に止めたきっかけだった気がします。そしてこの記事で実装された PoC 的な GitHub リポジトリ の GitHub スターが 1 万を超えていたことも大きい。

クリーンアーキテクチャというと、原典となっている The Clean Architecture にいきなり 4 層の絵が出てきて、やれ Use Case だ Entity だと書かれているのでそれがクリーンアーキテクチャだと思ってしまいがちだけど、重要なのは:

  • レイヤーアーキテクチャ
  • 依存は外から中の一方通行
  • ドメイン駆動(ドメイン層の依存を DI できる)

ということなのではないかと思います。実際原典でも下の方で「層の数は重要じゃない」みたいなことがちょろっと書かれています。

さて、件の Android にクリーンアーキテクチャを適用する記事に話を戻しましょう。この記事で提案されているアーキテクチャをかいつまんで説明すると:

image.png

Architecting Android...The clean way? より引用

  • 3 層のアーキテクチャ
    • プレゼンテーション層
    • ドメイン層
    • データ層
  • プレゼンテーション層は Interactor インタフェースを通してドメイン層に依存する
  • ドメイン層は普通の Java オブジェクトで実装して、データ層との間に Boundaries を置く
  • データ層はリポジトリパターンを使う

ということです。GitHub リポジトリを見に行くともっと色々とやっているんだけど、この記事に関して言えばこういうことです。これを見て僕は:

  • これドメイン駆動設計で見たやつだ
  • レイヤーの間もインタフェースにすることで、ツール入れ替えの影響を層の中に留められるようにできて良さそう
  • Vanilla JS 最高
  • (Rails の ActiveRecord パターンへの恨み)

みたいなことが頭をよぎり、端的に言うとこの方針がとても理にかなったもので今回の要件に適用できるものだと感じたのでした。

プレゼンテーション層に必要なもの

Android-CleanArchitecture 的なアーキテクチャを採用したとき、プレゼンテーション層の責務は何でしょうか。僕の考えは:

  • 見た目を管理すること
  • ユーザのインタラクションをトリガーにして、適切に Interactor を呼び出すこと
  • Inteactor の実行結果を踏まえて見た目を適切に更新すること

の 3 つです。そしてこれを突き詰めていくと、結局プレゼンテーション層を実装するのに僕にとって必要なのは:

  • 仮想 DOM
  • ステート管理
  • イベントハンドリング

だという考えに行き着きました。

React

つまり、なぜ React を採用しなかったかというと、前述の要求に対して React が過剰、あるいは不足だったということです:

  • 仮想 DOM で宣言的に UI を書くことができる :ok:
  • コンポーネントがステートを管理する。それだけだとダメなので結局 Redux とかが必要になる。最近は Redux より MobX がイケてるらしい。来年には MobX も古くなっているだろう。ココらへんのこと勉強するのが不毛。
  • イベントハンドリングできるが、多くの場合登録されるイベントハンドラは元を辿っていくとコンポーネントクラスのメソッドに行き着く。クラスコンポーネントは色々なことができてしまうので使いたくないのに使わないと行けない。ピュアな関数コンポーネントだけを使いたい。
  • 実装がでかい

など。なんか React はダメみたいな書き方になってしまいましたが、もちろんいいところもたくさんあって、特に「大きなコミュニティがあり、うまくカプセル化された再利用性に優れたコンポーネントが多数公開されている」というのは大きな魅力だと思います。なので:

  • 短時間でガッと実装して納品する
  • ページ間の遷移はフルリロードで、一つ一つのページを独立してリッチにできればそれでいい

みたいな状況では適しているような気がしています。あとは開発チームに React マスターみたいな人がいるとか。ただまぁ多くの場合「あなたが本当に必要なのは仮想 DOM と JSX じゃないですか?」という気がしています。

Hyperapp

では何故 hyperapp を採用したのかというと、それは前述の

  • 仮想 DOM
  • ステート管理
  • イベントハンドリング

を満たしてくれるからです。そして hyperapp がいいのは これ以外のことはしない ことです。「一つのことをうまくやる」姿勢は後述する学習コストとも絡んできます。

じゃあ具体的にどうやってドメイン層やデータ層と合わせて実現しているの、ってのは次の記事で書こうと思います。

2. 学習コスト

JavaScript 界隈のツールの栄枯盛衰の激しさを揶揄する意見も多いですが、僕も全くの同意見です。日々生まれては死んでいく流行りのツールをいちいち学んでいてはどんなに時間があっても足りません。

しかし、何も学ばなくていいとは思いません。時間が限られるのであれば、その限られた時間で何を学ぶかという選択があるということです。学ぶ価値のあることは学べばいいのです。

ではどういう知識は学ぶ価値が高いのかと言えば、色々な意見があるでしょうが、僕にとってそれは:

  • 効果が高い
  • 再利用できる
  • 息が長い

みたいな条件を満たす知識です。例えばアルゴリズムや、データ構造、プログラミングパラダイムなどといった知識はこの条件を満たします。逆に学ぶ価値の低いものは何かと言えば:

  • 効果が低い
  • 再利用できない
  • 息が短い

知識でしょう。

仮想 DOM は学ぶ価値がある

仮想 DOM は学ぶ価値のある知識です。これまでの手続き的な DOM 操作の世界から、仮想 DOM による宣言的な UI の記述への変化は革命的なものだったと思います。

React に学ぶ価値はあるが

React は圧倒的な導入事例から学ぶ価値があると感じます。またコンポーネント指向の考え方もいいですね。 Flux アーキテクチャも学びがありました。

Redux のシングルステートとか、それによってタイムトラベルができるとか、そこら辺の話は学ぶ価値があったように思います。ただ、 Redux を使うためのボイラープレートの書き方とか、 redux-thunk やらの周辺ツールは本当に辛い。 redux-saga は背景にある saga の考えは学びがありましたが、そうこうしている内に次は MobX だみたいな話になっていて、おそらく来年の今頃は MobX も古いみたいな話しになっているはずです。

hyperapp は学習コストが小さい

hyperapp は 1KB しかないので、できることが少ないので、そもそも学習するべき項目がほとんどありません。

hyperapp は仮想 DOM を使ったビュー管理ライブラリです。仮想 DOM は学ぶ価値があるので学んでください。その上で、 hyperapp から仮想 DOM を引いたら何が残るのでしょう?

  • ステート管理

は確実に残りますが、実体は単なる Object です。 immutable.js とかそういう余計なものは使いません。

  • イベントハンドリング

も実体は単に関数を仮想 DOM を通じてバインドできるだけの話しです。仮想 DOM と現実の DOM の知識の組み合わせに過ぎません。

State slicing は hyperapp 固有の知識になりそうです。(が、1 分で理解できるはず)

クリーンアーキテクチャと hyperapp

hyperapp が「息の長い」ソフトウェアになるのかどうかは分かりません。ただ、今回の記事で言及したレイヤーアーキテクチャや、プレゼンテーション層とドメイン層を分けるという設計は、具体的な実装に依存しない分、ある程度の年月を耐えられると期待しています。

仮想 DOM の次がくるかも知れません。しかしその時は hyperapp を捨てればいいのです。一つの層の中に閉じ込められた小さなツールを捨てるのは、複数の層にまたがる大きなツールを捨てるのに比べれば相対的には簡単です。栄枯盛衰が激しい世界だからこそ捨てやすさは価値を持つと思います。

まとめ

  • 小さいことは正義
  • 僕にとって React で必要なのは仮想 DOM と JSX だけだった

追記

hyperapp の開発者が社内にいることを触れないのはフェアじゃないという指摘があり、たしかにその通りだし、この記事を鵜呑みして hyperapp を採用する人が出てきても、その人と僕達が置かれている状況は若干異なるので言及しておきます。

hyperapp はもともと @JorgeBucaran が実装を始めた OSS で、彼は Qiita 開発チームのメンバーなので、最初に hyperapp の存在を知ったのはそれがきっかけです。ただそれで十分かといえばもちろんそんなことはなくて、開発者が誰かという観点で言えば、それより重要なのは hyperapp がコミュニティによって開発されていることでした。(この観点は昔僕がはてな社でバイトしていた時に CTO をしていた stanaka さんの考え方の影響が大きい)

それともうすぐ hyperapp 1.0 がリリースされるはずなので、触ってみるのはそれ以降がいいと思います。

ちなみに Increments Advent Calendar@JorgeBucaran も hyperapp について何か書く予定なので、この記事を読んで hyperapp に興味を持った人はそちらも是非読んでみてください :wave: