胸に刻みたいExpressアンチパターン

  • 35
    いいね
  • 0
    コメント

業務でExpressを触り始めてから1年ほど経ったので、私が思う「これはヤバい」をまとめておきたいと思います。
アンチパターンなので各見出しはやっちゃいけないことです。
みなさん真似しないように。ドミナントとの約束だ。

「サーバサイドもクライアントサイドもJavaScriptとか超楽じゃん」という考えでNode.jsに手を出す。

そもそも論として、Expressの中でのアンチパターンというか、プラットフォームを選ぶときに こんな考えでNode.jsを使おうとするのはヤバい というものです。

Node.jsに手を出した人の約9割(主観)がこういう思いから始め、そしてそのほとんどが「あ、これやっぱ別物だわ」となります。
まあ確かにjsなので文法は同じなんですけどね。
どちらもnpmからライブラリを引っ張ってこれるんですけどね。
結局サーバサイドとクライアントサイドを同じノリでできるわけがないんですよ。

Node.jsがダメというわけではありませんが、クライアントサイドのJavaScriptとは分けて考えるべきです。
Meteorなんかはサーバサイドとクライアントサイドの境界がだいぶ曖昧になっているようですが、真面目に触ったことないのでよくわかりません。

「WebフレームワークってことはRailsとかLaravelみたいなものでしょ?」と過剰な期待を抱いちゃう

そこまで手厚くありません。わりと突き放してきます。

あとExpressは別にMVCのフレームワークじゃありません。MVCっぽくも使えるというだけで。
「いやいやご冗談を」と思った方はとりあえずexpress-generatorで雛形を作ってみましょう。
Modelなんてどこにもありませんよ。

Expressはひたすらミドルウェアを積み重ねて行くもの。

Routerの中に処理を全てぶち込む

やめて...やめてクレメンス...

巷に溢れるチュートリアル程度の規模なら大丈夫なんですけどね、ちょっと処理が複雑になったら一気に破綻します。
あとRouterは単体テストしづらいです。supertestとか使えば無理ではないんですけど、いずれにせよ処理が複雑になってきたら別のモジュールに切り出したいところです。
古代ローマ人も「分割して統治せよ」と言っています。

レスポンスを返したあとreturnしない

いつから「ここで処理が終わる」と錯覚していた?

res.send()とかした後も実は処理が続いてます。
一つのリクエストに対して複数のレスポンスが返ってくる、みたいなことは起きないようですが、レスポンス以外のコードは普通に実行されます。

routes/users.js
const express = require('express');
const router = express.Router();

/* GET users listing. */
router.get('/', (req, res, next) => {
  res.send('respond with a resource');
  console.log("Whats!?"); // レスポンス返した後に何かしてみる
});

module.exports = router;

試しにexpress-generatorで生成されるルーティングに適当な処理を追加しましょう。

スクリーンショット 2017-05-16 22.58.50.png

この場合ただのconsole.logなので無害ですけど、DBにアクセスしに行く処理とかがあったら恐ろしいですね。
基本的にWebアプリにおいてレスポンス返した後に何か処理を行う必要はないかと思いますので、事故を防ぐ為にもreturnしといたほうが無難かと思います。

routes/users.js
const express = require('express');
const router = express.Router();

/* GET users listing. */
router.get('/', (req, res, next) => {
  return res.send('respond with a resource'); // ここでreturnしておく
  console.log("Whats!?");
});

module.exports = router;

スクリーンショット 2017-05-16 23.05.29.png

こうしておけば、レスポンスを返した後に意図せず変なことをしてしまうことは防げます。

本番環境でデフォルトのnpm startしちゃう

それは縛りプレイです

デフォルトのnpm startの中身はnode bin/wwwなので、普通にNode.jsを実行するだけです。
そしてNode.jsはシングルスレッドで動きます。

つまりCPUを一つしか使えません。
めっちゃハイスペックなマルチコアのCPUを積んだサーバを用意しても、デフォルトのnpm startを使った時点で無意味になります。
「おー、Node.jsのサーバはCPU使用率があまり大きくならないなぁ」と安心していたら、実はCPUの性能を発揮できてなかっただけだったなんてこともあります。
ていうかありました。

このあたりを参考にしてクラスター化しましょう。