TopHatenarはRails並の軽さで作られている

Java好きな僕としては、TopHatenarが、Javaでも(Seasar2ファミリーを使えば特に)スピーディーなWeb開発ができることの実証例になれば良いなあと思っています。

ただし、HOT deployが使えない場合はさすがに「Javaでもスピーディー」とは言えないかも*1。S2ファミリーのフレームワークSAStruts, Cubby, Teeda, etc)なら基本的にHOT deploy対応なので大丈夫です。

ここで、TopHatenarのコードの一部を引っ張り出して、仮に同じことをRailsでやったらどうなるか考えてみようと思います。

結論を先に言うと、すごく似た感じになります。TopHatenarCubbyを使ったけど、SAStrutsでも大枠は同じになるはず。

以下は、http://tophatenar.com/view/{user}にアクセスしたとき呼ばれるアクションです(説明を簡単にするため書き換えた部分あり)。

@Path("/")
public class ViewAction extends Action {
    // リクエストパラメータ
    public String user;

    // 画面出力用オブジェクト
    public String diaryTitle;
    public int allHatenarCount;
    public HatenarModel model;
    public Rank subscriberRank;
    public Rank bookmarkRank;

    // サービス(DIされる)
    public HatenarService hatenarService;
    public RankingService rankingService;

    @Path("view/{user,[A-Za-z0-9\\-_]+}")
    public ActionResult view() {
        Hatenar hatenar = hatenarService.getHatenar(user);
        if (hatenar == null) {
            HatenaDiaryAPI api = new HatenaDiaryAPI();
            if (api.isUserPresent(user)) {
                hatenarService.addHatenar(user);
                return new Forward("view/queued.html");
            } else {
                return new Forward("view/error.html");
            }
        }

        diaryTitle = hatenar.diaryTitle;

        Rankings rankings = rankingService.getRankings();
        allHatenarCount = rankings.subscriberList.size();

        model = hatenarService.getHatenarModel(hatenar.id);
        subscriberRank = rankings.subscriberList.getRank(model);
        bookmarkRank = rankings.bookmarkList.getRank(model);

        if (subscriberRank != null && bookmarkRank != null) {
            return new Forward("view/index.html");
        } else {
            return new Forward("view/queued.html");
        }
    }
}

もしTopHatenarRailsで作っていたら、上のViewActionに相当するコントローラは次のような感じになります。

  • view_controller.rb(想像)
class ViewController < ApplicationController
  def index
    hatenar = get_hatenar(params[:id])
    if !hatenar
      api = HatenaDiaryAPI.new
      if api.is_user_present(user)
        add_hatenar(user)
        render :action => "queued"
      else
        render :action => "error"
      end
      return
    end

    @diary_title = hatenar.diary_title

    rankings = get_rankings()
    @all_hatenar_count = rankings.subscriber_list.size

    @model = get_hatenar_model(hatenar.id)
    @subscriber_rank = rankings.subscriber_list.get_rank(model)
    @bookmark_rank = rankings.bookmark_list.get_rank(model)

    render :action => "queued" unless @subscriber_rank && @bookmark_rank
  end

  def queued
  end

  def error
  end
end

似てますよね。Javaの場合はpublicフィールドの宣言が必要なのでちょっと行数が多いけど、IDEの補完がバシバシ効くことを考えれば、ほとんど差はないでしょう。

ちなみに、TopHatenarのプログラム総行数は約1800行、コメントと空行を除くと1300行ぐらいです(うちグラフ描画部が350行くらい)。

ここで生産性云々の議論をするつもりは全くないですけど、JavaでもLLに近い感覚で開発できるケースがあるということは十分言えると思います。

*1:HOT deployにはClassCastExceptionの呪いというのがあって、最初からHOT deployを意識して作られたフレームワークじゃないと相性が悪いという点に注意が必要。