背景
僕が本格的にWebのエンジニアになったのは2014年頃からで、早いものでもう丸2年ほど経ってしまうことになります。
Webに転向してからは主にフロントエンドエンジニアとして勤務してきました。
よく言われることですが、最近のフロントエンドの趨勢は本当に早いです。
最初はキャッチアップに苦労したことを覚えています。
しかし段々と新しい何かを覚えることは苦でなくなり、今はこの流れに身を置くことが楽しいと思えるようになってきました。
激動の趨勢の中で、Webのフロントエンドエンジニアが口にするパラダイムは日ごとに変化しています。
この記事は元々社内向けに書いたものです。
色々なバックグラウンドを持つエンジニアと一緒にフロントの設計を考える場面で、共通言語を持つきっかけになればいいなー、という思いから書いたものですが、いい機会なので外向けに修正して公開してみます。
Webのフロントエンドを新しく学び始める方の参考に、少しでもなれば幸いです。
間違いや、意見の違いなどあるかもしれません。
ご指摘やご意見頂ければ嬉しいです。
JavaScriptの誕生(1995年)
今はなきネットスケープコミュニケーションズの開発者であるブレンダン・アイク氏が1995年に開発したLiveScriptという言語があって、紆余曲折あってJavaScriptという名前になったわけですが、この時期にエンジニアやってないので詳しくもないし調べてまでここで話したいことでもないのでこの辺で。
ECMAScriptの誕生(1997年)
JavaScriptはIEの3.0に採用されてから急速に普及していくわけですが、各ブラウザベンダーの実装バラバラ過ぎて辛すぎ。何か標準化された仕様必要じゃね?となって策定されたのがECMAScriptです。
つまりECMAScriptはJavaScriptの仕様書みたいなものです。
RIAという言葉が流行していた時代(2005年より少し前〜2008年ぐらいまで)
JavaScriptが誕生したものの、DOM操作のみでリッチなWebアプリケーションを作るのは至難の業でした。
そこで誕生したのがRIAという概念です。
ここで主に使われたのは、ActionScriptという言語で実装するFlashという技術です。これはベクターイメージをスクリプトで動かして、動的なコンテンツを構築する技術でした。
テキストじゃないからブラウザ上で検索できなくね、とかそもそもブラウザ単体だと動かないからプラグイン必要じゃね、とか色々問題もあって、そもそもこの時期にエンジニアやってないので詳しくもないし調べてまでここで話したいことでもないしこの技術が世界を席巻しない世界線に生きていて本当に良かったと思っているのでこの辺で。
Ajaxの登場(2005年)
Ajaxが発見されてからしばらくは、Ajax vs Flashな戦いが繰り広げられます。
結果Ajaxが勝利し、RIAという言葉は死語になりました。(広義にはAjaxもRIAという概念に含まれているとは思いますが。)
その戦いに大きく貢献したのが、後述のprototype.jsとjQueryです。
Ajaxが何かというのはgoogleで検索した方が有益な情報得られると思うので割愛。
ただ1つ言えるのは、Ajaxは洗剤の名前だ。なんで洗剤の名前かと言うとその時期に流行っていたSOAPという技術があってだn(ry
prototype.js、jQuery誕生(2006年)
Ajaxブームの中誕生した2大ライブラリがこの2つです。
prototype.jsはJavaScriptのPrototypeを拡張して、DOM操作がやりやすくなったり、Ajaxが使いやすくなったり、Array.prototype.eachみたいなメソッドが使えるようになったりする便利ライブラリです。
しかし当時のES3の仕様だと安全にprototypeの拡張を実行する術は用意されてなくて、グローバル汚染やばくね?気持ち悪くね?
となって、$という変数に全ての機能を詰め込んだjQueryが世界を席巻することになります。
フロントエンドにMVCの概念が登場(2010年)
jQueryが登場してからというものの、これが我々の求めていた世界だ!
となったフロントエンドエンジニア達は喜び勇んで、Ajaxの通信に必要なパラメータを組み立てて、DOM操作をcallbackで渡して、リクエスト完了したら実行して、みたいなことを特に何のレイヤーも設けずにやっていたわけです。
2010年ぐらいまでやって、あれ、これつらくね?と気付きはじめます。
そこでフロントエンドにMVCの概念が持ち込まれます。
(※ Railsなどに見られるWebのサーバサイドのMVCは正確にはMVCではないので、MVC2と呼べ!という武闘派もいるので注意!)
それがBackbone.jsです。
Model、Collectionでサーバ側から受け取った値を保持し、なんとRestfulなURIも自動で生成してくれる。
Router(Controller)もある。
Viewレイヤーで画面描画の処理は書けば良い。DOMの処理はそこでやろう。
などなど、これが我々の求めていたものだ!となったフロントエンドエンジニアはこいつに熱狂しました。
しかし、欲望の塊であるフロントエンジニア達はこいつにも満足しませんでした。
2way-bindingの流行(2012年から2014年前半ぐらいまで)
ここから、大フロントエンドフレームワーク時代が始まります。
少し流行ったものを思い出してみるだけでも
- Angular.js
- Knockout.js
- Ember.js
- Vue.js
- Marionette.js
- Aurelia.js
とこんなにあります。
それぞれ開発者の思想は違えど、共通している概念があります。
それが__2way-binding__でした。
これが何かと言うと、
「HTMLに表示している値って結局Ajaxで取得した情報だったりするよね。
で、それをinput要素に入れて、ユーザが書き換えてsubmitしたら、それをDOM操作で取得して、Ajaxで送るんだよね。
え、それだったらmodelの値とinput要素の値って共通でよくない??
共通にしようよ!」
というものです。
つまり、Viewに表示している値とModelの値を共通して持つということです。
Viewの変更はModelに通知されて、Modelの変更はViewに通知されて、双方向でbindingされるね!
というところから2way-bindingと名付けられました。
これが出てきた時は非常に衝撃的でした。(僕はこれに熱狂しました。)
DOM操作をしなくてもViewを変えられる!やばい分かりやすすぎる!
DOM操作は悪だ!撲滅するべきだ!DOM操作死すべき!
と(僕を含む)フロントエンドエンジニアを一気に過激派へと変える力がありました。
この頃に流行ったフレームワーク達は、MVVM(Model View ViewModel)と呼ばれたり、その構成の一部を担うものが多いです。
ViewModelというのは、Viewの表示をModelに変換したり、Modelの状態をView表示用に変換する部分をよしなにやる層を指します。
ViewModel自体はこれよりもっと前に存在した概念ですが、これが2way-bindingのパラダイムには非常に相性が良かったのです。
ちなみにMVCとかMVVMとか、呼び方なんてどうでもいいんだよ!という思想のもと、AngularJSはMVW(Model View Whatever(モデル ビュー 何か))と言っています。
が、基本的にはMVVMの実現したいことを元にしています。
(明確にMVCのCに当たるControllerがいるので違う気もしますが、AngularのControllerはScopeというViewModelの役割を担うものを生成します。なので僕はそういう印象を持っています。)
少し話がズレますが、僕の観測範囲ではこの時期に一番流行っていたのはAngular.jsでした。
(その分敵も多かったですが。)
Angular.jsにはdirectiveという概念があって、簡単に言うと独自のHTMLタグを生み出して、そこにviewの描画のためのjsの処理を押し込める、というものでした。
Angular.jsの1はコンポーネント指向ではないですが、directiveという概念はコンポーネント指向の流れを促進させました。
この功績がAngular.jsの一番大きいところかと思います。
2way-bindingは確かに市場を席巻しましたが、しかし数年すると、心変わりの激しいフロントエンドエンジニア達はこのパラダイムをも嫌うようになります。
コンポーネント指向と単方向フロー、それを実現するVirtualDOMの登場(2014年後半〜現在)
コンポーネント指向という概念は筋の良いものとして受け入れられました。
これは次期HTMLの仕様として検討中の WebComponents
にも影響を与えています。
2way-binding は残念ながら受け入れられませんでした。
主には以下の様な問題が議論されていました。
- 値がどこで変えられたのか分からなくてつらい!
- そもそも2way-bindingを実現するには、objectの値変更を監視しなきゃならん!コスト高い!(ES7で検討されてたけど最近死んでしまったObject.observeはここから来ていましたが、色々あって(rya))
- 複雑な画面だとたくさんmodelが登場してきて、関連を制御するのつらい。
2way-bindingでは、ViewModelでViewの値もModelの値も管理しないといけないところがつらさの原因になっている。
じゃあそもそもViewを描画するときに、Modelの状態から全部再描画すればいいんじゃない?
そしたらModelの値を管理するだけで良くなって、Viewの値は考えなくてよくなるんじゃない?
という発想から生み出されたのがVirtualDOMという考えであり、その実装がReactです。
(Reactはv0.14からDOMの描画はReactDOMというライブラリに分離したので、今は必ずしもブラウザでVirtualDOMを構築するViewライブラリ、という位置付けではなくなりましたが。)
VirtualDOMはModelの状態から生成されるDOM構造をブラウザに適用するときに、その差分のみを描画します。
つまりJavaScriptの中では全て再描画するかのようにコードを書けるのに、それをブラウザに適用する段階においても速度を出せる。まさに描いていた夢はこれだった。
参考: VirtualDom - なぜ仮想DOMという概念が俺達の魂を震えさせるのか - Qiita
そこにピタリとはまるのがFluxという概念で、これはViewの中での値の変更をそのままView内で処理をせず、別の層に流し込みます。
具体的にはActionCreator → Dispatcher → Storeという経路を辿ります。StoreはViewの描画に必要な値を保持している層で、ここでViewの構成に必要なModelは再生成され、再びViewに適用されます。
このフローが__単方向フロー__と呼ばれるものです。
ここでは、Viewの描画ロジックとModel(Store)のビジネスロジックは完全に分離しています。
Viewの描画は必ずViewで行われるし、それに必要な情報は確実にStoreで構成されるため、非常に見通しが良くなります。
Angular.jsは現在2に向けて鋭意開発中ですが、React.js同様完全なコンポーネント指向になります。
というかAngular2は1の全てを捨て去ります。
good bye僕の青春。
まとめると
今流行っているReact + Fluxという構成は非常に筋がいいと僕は思っています。
フロントエンドの趨勢は確かに早いです。
しかしここまでの道のりはちゃんと過去から繋がっているし、以前のパラダイムはただただ捨てられてきたわけではなく、ちゃんと現代に影響を与えています。
パラダイムシフトはまだ来るかも知れませんが、今の技術をしっかりキャッチアップし続けることでそれに耐える準備はできるはず!
という気持ちで頑張っていきます。