guard文のあれこれ

あるメソッドで、渡されたパラメータによっては処理をまったくしないということがある。 その場合guard文を書くことでネストが深くならなくて、読みやすくなることはイディオムとしてよく知られている。

しかし、guard文を書くと逆に読みにくくなってしまう場合があるんじゃないかと最近仕事のコードを書いていて思った。とくに、必ず特定の値を返すメソッドの場合。 「必ず特定の値を返すメソッド」はどんな時に書くのかと考えると、例えば、Interceptorパターンを実装していて、パラメータは降ってきて特定の条件下では処理はするけど、必ず後続のInterceptorに処理を継続させたくてtrueを返す場合。

public boolean before(AObject o, AMap param) {
  if (!cond(param)) {
    return true;
  }

  // brabrabra

  return true;
}

二回もreturn文が出てきて気持ち悪いのでここは、guard文を書かないで素直に書くほうが読みやすいんじゃないかと。

public boolean before(AObject o, AMap param) {
  if (cond(param)) {
    // brabrabra
  }
  return true;
}

Mac OS -> Ubuntu

教授がMac OSをメインで使っていた影響で、学生時代からメインマシンにMacを使ってきたけれども、転職を期にUbuntuへ移行しました。

  • 職場の開発マシンがUbuntuなので、普段からプログラミングスタイルや開発環境のノウハウを貯める
  • xmonadの完成度が高くてプログラミング環境として集中できる(職場にxmonad使い多くて吹いた)
  • 別にMac OSが必要な仕事をするわけでもないし、プライベートでも興味がない。結局Xcodeもcommand line toolのインストール時等、数える程しか起動しなかった

など、よくよく考えるとMacでなければならない理由はなくて、手軽にUnixライクな環境が使えればよかった。 とはいえ、純粋なUnixではなくUnixの皮をかぶったDarwinなので、たまに不都合(ビルドがすんなりできないとか)が出たりしたときはつらいなーとか思って諦めてそのまま使ったり、頑張って解決したりしてきたけど、そんな悩みもなくなった(はず)。 切り替えてから1ヶ月ほど経過してるけどいまのところ問題もなく、むしろ快適に感じている。

nodeでRedisを使ってセッション管理

フレームワークにexpressを使う場合、connectが提供するsessionモジュールを使うと楽に実装できる。 さらに、Redisにセッションデータを保存する場合、connect-redisを使うと楽だ。

https://github.com/visionmedia/connect-redis

他にも、express-session-redisというモジュールがあるけれども、コードを読んでセンスがあると思ったのは、connect-redisの方。 connectがセッションストア用インタフェースを作ってくれているので、それを継承して作ったほうがスマート。

Twitterでログインするやつをconnect-redisを使って書いてみた。

https://gist.github.com/yoppi/5604149

nodeでWebアプリを開発するときに考えること

僕は、全体を俯瞰して作り出すので遅いのだけれども、トータルとして同じくらいのスピードになるかなと思って、新しい言語やフレームワークを使うときは、まずは全体で必要になりそうな技術であったり、問題点を潰すことにしています。

フレームワーク

nodeのフレームワークは、たくさんありすぎてどれを使っていいのやら、という状況だけれども express 使っておけば良いというのが僕の中での結論。 ルーティング、テンプレート、セッション管理といった基本的な機能を簡単に使える(connectが素晴らしいというのもあるけど)ので、複雑なことをしたければあとは自分で頑張るほうがいいと思う。

それに、全部読みきれる量であるということ。 使うライブラリのコードを読みきれるというのはすごい重要。フレームワークでサポートしていないことをしたくなったときにどこに手を入れて良いのかがすぐに判断できるから。 また、expressのテストコードはmochaを使っているので、本体と合わせて読むと、どうやってテストコード書けばいいかも勉強できて良い。

O/Rマッパー

RDBMSを使ってそこそこの規模のWebアプリを書こうと思うと、O/Rマッパーがあるとすっきりする。が、探してみるとActiveRecordのような決定的なものがない。 ぱっと見でよさそうなのが、node-orm2

https://github.com/dresende/node-orm2

基本的なクエリに加えて集計関数も投げられるし、has-oneとかhas-manyといった関連も定義でき、フックも充実、さらにexpressとも相性がいい。 Rails界に住んでる人は、モデル毎にファイルを分けて定義したくなるので、手動でロードしないといけないのでちょっと面倒。

var orm = require('orm'),
    fs = require('fs');

var dbConfig = JSON.parse(fs.readFileSync(__dirname + '/database.json'));
var db = orm.connect(dbConfig.dev);
fs.readdir(__dirname + "/models", function(err, models) {
  if (err) {
    console.log(err);
    return;
  }
  models.forEach(function(model, i) {
    db.load(model, function(err) {
      console.log(err);
    });
  });
});

一般的にnodeでRDBMSを操作することはやはり少ないのかなぁ。スロークエリ頻発するともはや非同期IOは意味をなさなくなるというところから、mongoやCouch、Redisを積極的に使う方針にしたほうがよいのだろうか。

migration

RDBMS使うなら、migrationの機構がないと死ねる。node-db-migrateが使いやすい。Rails流。up/downで操作、データベースにmigrationsテーブル作って管理するところなど。

https://github.com/nearinfinity/node-db-migrate

上記のnode-orm2と相性はまぁまぁ。唯一ぐんにょり来るのが、設定ファイルのプロパティ名が違っていること。 node-orm2では、protocolだがnode-db-migrateはdriverになっている。database.jsonで両方記述しておくとうまくいくが、ぐんにょり来る。 あと、Rails界の人は、

  • updated_atcreated_atは必ず自分で定義しないといけない
  • サロゲートキーも自分で定義(idも自動付与されず自分でPK、AUTO_INCREMENTを指定する)

に注意。

auto loader

hotnodeが今のところ快適に使えている。 コヒスク使う人は、hotcoffeeコマンドで。 シングルページアプリケーション程度の規模なら問題なし。

https://github.com/saschagehlich/hotnode

デバッガ

とりあえず、node-inspector使っておけ、らしい。

https://github.com/dannycoates/node-inspector

Webkitブラウザ上でサーバサイドのコードをデバッグ実行できるので死ぬほど便利。一度使うと便利すぎてないと生きていけなくなる。 上記のhotnodeとも組み合わせて使える。

$ hotnode --debug app.js # アプリ起動
$ node-inspector # 別ターミナルで実行してChromeなどにアクセスする

ホスティング

普通のWebアプリなら迷わずHerokuだけれども、たとえばWebSocketを使いたい場合Herokuはまだサポートしていない。

https://devcenter.heroku.com/articles/using-socket-io-with-node-js-on-heroku

Herokuは1Dynoなら無料で公開できる(ただし750時間までなので注意)ので、これほどまでに使いやすいPaaSはないので諦めるのは辛いところ。 WebSocketの代わりにロングポーリングでも良いのだけれども、iPhoneiPadだと通信中のぐるぐるが回ったままで、気にする人は気にするので気持ち悪さを与えて結果として使わないということがあるので、なるべくWebSocket使いたい。

とりあえずは、Herokuで作り問題が出て来て(お金に余裕のある人は)、nodejitsuやAWS、VPSあたりを借りるがいいのでは。

デプロイ

nodeアプリを動かすときに、Heroku や nodejitsu といったPaaS使わない場合、手動(capコマンド実行等)/自動(git pushトリガー, jenkinsトリガー)問わずproduction環境にデプロイする必要がある。

Stack Overflowの解答を眺めていると、Capistranoを使っている人が割と多い。

プロセス管理

nodeは、内部でエラーが発生すると、落ちる。イコールサービスが止まる。なので、基本的に自動で上げるためのプロセス管理が必要になる。 まぁこれはいくらでもあるので、monit、god、supervisor等慣れたものを使うのが良いと思う。

あとは、node製のものとして、foreverがある。 nodejitsuはforever使っているとのこと。 Stack Overflowでの解答も「とりあえずforever」という意見が多い。

Rubyの標準ライブラリ及びgemのtagsファイルをロードする

Vimスクリプトを書いた。 https://github.com/yoppi/config/blob/master/vim/dot.vim/ftplugin/ruby/tag.vim

プログラミングしているときに、実装を知りたいときがよくあるので、Vimで素早くタグジャンプできるようにした。 ただ、

という問題があるので、もっと便利なようにtagsファイルを動的に更新していくような感じにしていく。

redisable

というgemを作った。

http://github.com/yoppi/redisable

RubyオブジェクトをRedisとマッピングさせる既存の有名なライブラリに、

の2つがあるけど、次の欲しかったものを実現するのが少し遠かったので作った。

  • モデル毎に複数のRedisサーバにアクセスできる(sharding)
  • オブジェクトをマッピングするというより、そのオブジェクトを通してRedisにアクセスしたい

という意味を込めてredisable(redis + enable)という名前にしている。

RSpecMocks/rr

TestDoubleライブラリをrr(Double Ruby)からRSpec標準のRSpecMocksに切り替えてるのだけど、やっぱり違和感がある。 rrはTestDoubleの考えをそのままライブラリ化した実装で、xUnit Test Patternsを熟読した人にとって馴染み易いと思う。

だけど、RSpec Mocksはいまいちstubmockの使い分けが不透明だったり...mockspyに当たるのはshould_receiveを使うというのがわかりづらいなーと。 rr、全然メンテナンスされてないのでメンテナになろうか、と、思ったら、

https://github.com/rr/rr

メンテナの人が変わってて活発にコミットが入る様になった模様。これで一安心か...