Flowsやったこと、考えたことの記録この広告は、90日以上更新していないブログに表示しています。KnockoutJSでWebサービス作った今年の10月からあるスタートアップの立ち上げに参加していて、先日ベータローンチした。自分はプログラミング初心者というわけでは全くないが、大学の専攻は農学部だし、それまで一人でサービスを一から作ってリリースしたこともなかったので、完全に独力でサービスを作りあげリリースするというのはかなりタフで、学ぶところが多かった。KnockoutJSでWebアプリを作った過程の記録としたい。何を作ったのか今回立ち上げた会社は、投資銀行出身の外国人(アラン)が金融機関向けのツールを作りたいということから始まったBtoBである。Venturesの衛藤バタラさん(mixi作った人)に話を持ちかけたところから始まった。いい所にいた自分に話がきた。アランが言うには、投資銀行という場所はコミュニケーションの点で未だにイノベーションが進んでおらず、そこに最新の(?)Webアプリケーションを作れば必ずいける、という話だ。アプリケーションとしてはそこまで高度なこと(大量のトラフィックとかなんとか処理とか)が要求されているわけではなく、だからこそ自分でも挑戦してみたいという気持ちになった。自分には一からサービスを作ってみたいという気持ちがとても強かったこともあり、新卒で入った会社を飛び出して参加させてもらった。アプリケーションの機能としては、ディールの一覧を取得し、それをインタラクティブに投資家<=>投資銀行間でやりとりしたり、チャットしたりとコミュニケーションを円滑化する、というのが中心である。Webアプリとしては一般的だと思う。友達に使ってもらうようなものではないが。フロントエンドのなんやかんやをやりくりするためにKnockoutJSを選択した。Railsはとりあえず普通のWebアプリを作るためには安易すぎるくらいの選択で特に述べることはないが、KnockoutJSを選ぶというのはあまり多くないと思う。最近はだいぶディスられてるみたいだけど、JavaScriptフレームワークとしてはちょっと前にAngularJSがもてはやされてて、自分も前職でそれに触れ、純粋に面白いと思い、今回もできれば使いたいなと思っていたが、考えた結果としてAngularJSは却下した。その他にもBackboneやらEmberJSも(ちょっとだけ)検討したが、最終的にチュートリアル触った感じからKnockoutJSを選ぶことにした。Railsアプリとの相性がよいこの3つに集約される。いうことになってしまった。エンジニアとしてはちっとも面白くないしなんだかなーと思っているうえに、AngularJSがIE8のサポート次から切るよ、と言っててぐぬぬと思っていたところにKnockoutJSは「IE6から全部サポート!」などというソ○トバンクばりの大言壮語を吐くので、「これは心強い」と素直に感じてしまった。2は後述するが、KnockoutJSは代表的なJavaScriptフレームワークの中では圧倒的に学習コストが低いと思う。Angularにちょっと触れた自分としては逆にそれが魅力的だった。data-bind=とやってほげほげすればたいていのことは間に合う。ドキュメントは充実してる気はあんまりしないが、チュートリアルはわりと親切で、これを組み合わせればなんとかなりそうだ、という実感がもてた。3が結局は決定的だったが、AngularJSはRailsとの相性があまりよろしくないと思う。Rebuild.fmでも言われていたが、RailsとAngularは機能的にかぶっている部分がありすぎる。Gruntでビルドするとか、ルーティングとかうまく使いこなせれば強いのだろうが、それだったらRails使う意味があんまりないかなと思っていた。Railsのapp/assets/javascripts以下にきれいに収まってくれる。この透明感というか「全体を把握できている感」が一からサービスを作っていく上で安心できた。全体の構成Railsの役割としては大きく二つで、HTMLをほぼリソースとは関係なくレンダリングする部分と、リソースをAPIサーバとして適宜返す、という部分を/apiでネームスペースで区切って共存させることになった。レンダリングしたHTMLやJavaScriptの中には当然ながらKnockoutJSで書いたコードが入っていて、その中でKnockoutJSがAPIを叩いてテンプレートをよろしく動かすという感じだ。KnockoutJSはすべてCoffeeScriptで書いた。CoffeeScriptはクラスを定義できるので、そこでリソースが持っているデータ構造をほぼ完全に再現して、それをKnockoutJSでバインドして動かした。フロントエンドの構成ここからもうちょっと具体的な話を書きたい。Railsに導入するための参考になれば。users.js.coffeeなんとなくこういうの載せるってどうなのかなーと思って本物とは少し変えてあるのだが、要はapplication.jsの下に、共通して使うメソッドとかクラスを定義するcommonというディレクトリがあって、それ以外が各テンプレートと対応するCoffeeScriptになっていて、それぞれがサーバーとデータをやりとりする、という感じ。当然ながらチャットとかノーティフィケーション系のどこでも呼ばれないといけないデータはcommon/class.js.coffee内に入っていて、その中に共通機能をいれたViewModelを定義して、各テンプレートではそれを継承したViewModelをつくる、という感じだ。bindingHandlersには、要素をドラッグしたり、エフェクトをつけたりといったDOM操作系の機能が入っている。DOM操作は末端のCoffeeScriptには書いてなくて、データとかロジックだけをうまく切りだせていると思う。使ったコードパターン自分が書いたコードを振り返ってみると、アプリケーションの機能としては分割されているものの、違うリソースに対して同じようなふるまいを提供している部分が多い。self.loadNotifications()上がログイン下でのすべてのテンプレートのViewModelが共通して継承するクラス(の省略版)で、ログインしているユーザーの情報をAjaxでとってきたり、別に立ててあるSocketIOのサーバにつなぎに言ったりしている。使ったのがself.loadNotifications()みたいにしてデータをロードして、$.map使って定義したクラスにデータを入れ籠む、という形。これも伝わる気がしない。各データを構成するクラスは以下のような感じ。self.attemptedSurname(data.surname)上はユーザークラスで、プロフィール画面にバインドさせて編集したり更新するのに使った。idとかfirst_nameとか一通りの情報は持たせた上で、saveみたいに情報をPOSTするためのメソッドを個別に持たせた。情報を更新したら、サーバーから更新後のデータをそのまま返させて、それを使ってupdateメソッドを呼ぶことで自分自身を更新する。することでデータをまるごとリロードしたりせずともSPA的な機能を表現できた。リソースの更新にはこのように各オブジェクトが自分自身を更新できる場合もあってきれいな感じだが、実際にはその親クラスにメソッドを持たせる必要がある場合が多かった。そのオブジェクトがObservableArrayに入っている場合。observableArrayは配列を監視して、データが更新されたらテンプレートも一緒に更新する、というデータバインディングの基本機能を実現するものだが、ただ自分を変えるだけじゃなく、削除したり、他のobservableArrayに移動したりという場合にはどうしても親から操作する必要があった。まとめ今回はRailsとKnockoutJSでそこそこの規模のアプリを作るのに使った大枠をざっくりと記録した。以上の内容をまとめると、以下のようになる。各アイテムの更新の際には、一覧の数が関係なければオブジェクト自身に更新させ、数が変わるときには親のビューモデルからAPIを叩いて更新する来週も書くつもりだが、次回はもっと具体的なTips的なのを書けたらと思う。(1)月別アーカイブリンクはてなブログブログをはじめる週刊はてなブログはてなブログPro参加グループインターネットはてなブログをはじめよう!yusuke-nozoeさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。