AngularJSの素晴らしさを整理してみる

久々のブログになります。
3年ほどJavaScriptを利用した開発をしてきましたが、最初はなぜJavaScriptMVCフレームワークが必要なのかいまいちわからず、いろいろ試行錯誤してきました。
今日はタイトルの通りAngularJSが素敵だなということを書きたいのですが、よくあるベストプラクティスみたいなものではなく、自身がどのように思考回路を経由してここに行き着いたのかという経験談を記しておきたいと思います。

ちなみに私のJavaScript力は高くありませんのであしからず・・・。

jQuery

昔々、JavaScript MV(V)Cみたいなものがなかった時代、JavaScriptでリッチなものを作ろうとなるとjQueryやDojoのような低レイヤーのフレームワークが主に利用されていました。
その当時簡単なシングルページアプリケーションを作っていましたが私はjQueryを採用しました。
jQueryはユーザイベントを拾ったり、サーバとの通信をサポートしているので、私は以下の思考回路でアプリを開発してました。

  • イベントを拾う
  • $.ajaxを利用してサーバと通信する
  • addClassやappend(html)を利用してViewを変更する

思考回路は非常にシンプルなので開発はしやすかった記憶があります。しかし、今そのソースコードは保守性がかなり低い状態になってしまいました。その理由は以下の通りです。

  • 構造化されていないため、コードを追うのが難しい
    • コードを増やせば増やすほど見通しが悪くなる
  • テストを書く技術力がなく、簡単に変更ができない

開発当時はわかりましたが、今は理解するのが難しいです。
ということで動きはしましたが、とても納得のできるソースコードはかけませんでした。

Backbone.js

jQueryの開発の1年後くらいでしょうか。当時注目されていた(今もか)WebSocketを利用して本格的なチャットシステムを開発するチャンスをもらいました。
そのときはjQueryの経験があったこととBackbone.jsの登場まもなくということで運命を感じた私はすぐにBackbone.jsに飛びつきました。
最初はほとんどドキュメントがない状態で書き始めたので最初はとても苦労しました。
そのときは以下の思考回路で開発をしていました。

  • View,Collection,Modelの設計をする
  • イベントを拾う(Viewのbind)
  • Modelを利用してサーバと通信する
  • Modelの変更をViewに適用する

Backbone.jsを利用したおかげでソースコードを構造化できるようになりましたが、設計の手間が増えました。
ViewにCollectionを持たしてさらにその一つ一つがModelを持つというのもそれなりに手間がかかりました。

テストについては、Cucumber+Capybaraを利用してWebSocket含めたストーリーテストを書くことでアプリの
一貫性を保つことができました。
構造化とテストの一貫性を実現できて、保守性自体はjQueryより大幅にあがったと思います。
(これは特にBackboneに限った話ではなくjQueryでもCucumber+Capybaraでテスト書くことは可能でした。)

ただ、それでもBackbone.jsを利用した開発手法は何か納得できないものがありました。
それは以下のような点です。

  • JavaScript単体テストが書きづらかった
    • ModelとViewの依存性が高いと感じた
  • 実際のHTMLとView側のbindが直感的ではなかった
    • ViewでjQueryセレクタのような形で記述するが具体的にどこを示しているのか直感的にわからなかった
  • Modelの変更をViewに伝えるのにModelの中でViewを呼び出していた
    • 当時でも他にいい方法があったのかもしれませんが、その当時は少なくともlistenToのような仕組みはなかったです。

ということでもう少し経験を積めば慣れていたかもしれませんが、満足はできないなーという想いでした。

AngularJS

そして今年に入ってAngularJSを利用し始めました。
RedmineGoogleカレンダーライクなプラグインを作っています。
Angualarの概要は一部ドキュメントの翻訳もしましたのでよければ見てみてください。
私は最初Angularを書いていて正直ちんぷんかんぷんでした。
抽象化レベルが高く、自由度が高すぎたのが原因でした。しかしすこしずつ書き直していくと以下の手順でかけるようになりました。

  • HTMLにAngularでbindすべきイベントを記述する
  • AngularのControllerでイベントを受け取る
  • VIewの変更ないしサーバとの通信をModelのビジネスロジックに記述する
  • Viewを変更する

この手順はとてもきれいに書けて開発がテンポよく行えるようになりました。
ここまできてやっと気づけたのですがこのAngularの手順はRailsで書くアプリと似ています。
Railsの場合、私は以下のような手順で開発しています。

  • HTMLを書く
  • formのsubmitやリンク等のイベントをサーバ側でControllerが受け取る
  • Controllerは必要な処理をModelのビジネスロジックに依頼する
  • Viewを返す

Angularで書くと以下のように記述できます。

  • HTMLを書く
  • ng-clickやng-mouseover等のイベントをAngularのController(scope)が受け取る
  • Controllerは必要な処理をModelのビジネスロジックに依頼する
  • Viewを返す

例えばカレンダーにイベントを作るとき、Controllerは以下のように書いています。

scope.createEvent = function() {
   // エラーの時の振る舞いを書く
   var error = function(response) {
     console.log(response);
     scope.showNotification("ライセンス数の上限に引っかかっています");
    };

   // 保存に成功したときの振る舞いを書く
   var success = function(event) {
     scope.myCalendar.fullCalendar("renderEvent", event,  true);
     scope.last_update_event = event;
   };

   // モデルに保存を依頼
   scope.formEvent.create(success, error);    
   scope.closeEventForm();
};

まさにRailsのControllerみたいな書き方ができてます。
他にもViewとモデルの双方向バインディングとかテストのしやすさとかdirectiveとかまだまだ書きたいことはありますが、
今回は力つきたのでここまでです。
とにかくjQuery,Backbone,Angularを触ってみましたが今のところAngularに夢中になる予感なのです。