nodejs-best-practices について
Node.js開発者がランタイム、フレームワーク、アーキテクチャを選ぶための判断支援スキルです。固定レシピではなく、状況に応じた検証、セキュリティ、エラー処理、テストを扱います。
主な機能
- 01状況に応じたフレームワーク選定
- 02ランタイムとモジュールの指針
- 03レイヤードアーキテクチャの原則
- 04非同期処理とエラー処理の指針
- 05検証、セキュリティ、テストの原則
活用シーン
- 01デプロイ先に合うフレームワークの選定
- 02成長するNode.jsアプリの設計
- 03APIの検証とセキュリティの確認
- 04重要な処理経路のテスト選定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ vudovn/ ag-kit --skill nodejs-best-practicesインストール後、Claude Code で/nodejs-best-practicesを入力して読み込まれたか確認します。
詳細
Node.js のベストプラクティス
モダンな Node.js 開発のための原則と意思決定。 コードパターンを暗記するのではなく、考え方を身につけましょう。
⚠️ このスキルの使い方
このスキルでは、コピーして使う固定のコードではなく、意思決定の原則を学びます。
- 不明な点がある場合は、ユーザーに好みを確認します
- コンテキストに基づいてフレームワークやパターンを選びます
- 毎回同じソリューションを既定で選ばないでください
1. フレームワークの選択
判断ツリー
What are you building?
│
├── Edge/Serverless (Cloudflare, Vercel)
│ └── Hono (zero-dependency, ultra-fast cold starts)
│
├── High Performance API
│ └── Fastify (~5x req/sec of Express in Fastify's own hello-world benchmark; benchmark your own workload)
│
├── Enterprise/Team familiarity
│ └── NestJS (structured, DI, decorators)
│
├── Legacy/Stable/Maximum ecosystem
│ └── Express (mature, most middleware)
│
└── Full-stack with frontend
└── Next.js API Routes or tRPC
比較の指針
| 要素 | Hono | Fastify | Express |
|---|---|---|---|
| 最適な用途 | エッジ、サーバーレス | パフォーマンス | レガシー、学習 |
| コールドスタート | 最速 | 高速 | 中程度 |
| エコシステム | 成長中 | 良好 | 最大 |
| TypeScript | ネイティブ | 非常に優れている | 良好 |
| 学習コスト | 低い | 中程度 | 低い |
確認する選択基準:
- デプロイ先はどこですか?
- コールドスタート時間は重要ですか?
- チームに既存の経験はありますか?
- 保守が必要なレガシーコードはありますか?
2. ランタイムに関する考慮事項
ネイティブ TypeScript
Node.js 24+ (Active LTS): type-stripping ON by default
├── Run .ts files directly: node file.ts (no flag, stable since 24.12)
├── Erasable syntax only — enums, runtime namespaces, param properties error out
├── For those, use tsx (--experimental-transform-types was removed in Node 26)
└── Consider for: scripts, simple APIs
モジュールシステムの選択
ESM (import/export)
├── Modern standard
├── Better tree-shaking
├── Async module loading
└── Use for: new projects
CommonJS (require)
├── Legacy compatibility
├── More npm packages support
└── Use for: existing codebases, some edge cases
ランタイムの選択
| ランタイム | 最適な用途 |
|---|---|
| Node.js | 汎用、最大のエコシステム |
| Bun | パフォーマンス、バンドラー内蔵 |
| Deno | セキュリティ重視、TypeScript 内蔵 |
3. アーキテクチャの原則
レイヤー構造の概念
Request Flow:
│
├── Controller/Route Layer
│ ├── Handles HTTP specifics
│ ├── Input validation at boundary
│ └── Calls service layer
│
├── Service Layer
│ ├── Business logic
│ ├── Framework-agnostic
│ └── Calls repository layer
│
└── Repository Layer
├── Data access only
├── Database queries
└── ORM interactions
重要な理由:
- テスト容易性:レイヤーを個別にモックできます
- 柔軟性:ビジネスロジックに触れずにデータベースを切り替えられます
- 明確性:各レイヤーの責務は一つです
シンプルにする場合:
- 小さなスクリプト → 単一ファイルで問題ありません
- プロトタイプ → 構造を簡略化しても構いません
- 常に確認しましょう:「これは成長するか?」
4. エラー処理の原則
一元化されたエラー処理
Pattern:
├── Create custom error classes
├── Throw from any layer
├── Catch at top level (middleware)
└── Format consistent response
エラーレスポンスの考え方
Client gets:
├── Appropriate HTTP status
├── Error code for programmatic handling
├── User-friendly message
└── NO internal details (security!)
Logs get:
├── Full stack trace
├── Request context
├── User ID (if applicable)
└── Timestamp
ステータスコードの選択
| 状況 | ステータス | 使用する場合 |
|---|---|---|
| 不正な入力 | 400 | クライアントが無効なデータを送信した |
| 認証なし | 401 | 認証情報がない、または無効 |
| 権限なし | 403 | 認証は有効だが、許可されていない |
| 見つからない | 404 | リソースが存在しない |
| 競合 | 409 | 重複または状態の競合 |
| バリデーション | 422 | スキーマは有効だが、ビジネスルールに違反している |
| サーバーエラー | 500 | サーバー側の問題。すべてログに記録する |
5. 非同期パターンの原則
使い分け
| パターン | 使用する場合 |
|---|---|
async/await | 非同期処理を順番に実行する場合 |
Promise.all | 独立した処理を並列実行する場合 |
Promise.allSettled | 一部が失敗する可能性のある処理を並列実行する場合 |
Promise.race | タイムアウト、または最初の応答を採用する場合 |
イベントループへの配慮
I/O-bound (async helps):
├── Database queries
├── HTTP requests
├── File system
└── Network operations
CPU-bound (async doesn't help):
├── Crypto operations
├── Image processing
├── Complex calculations
└── → Use worker threads or offload
イベントループのブロックを避ける
- 本番環境では同期メソッド(fs.readFileSync など)を使用しないでください
- CPU 負荷の高い処理は別に実行してください
- 大きなデータにはストリーミングを使用してください
6. バリデーションの原則
境界でバリデーションする
Where to validate:
├── API entry point (request body/params)
├── Before database operations
├── External data (API responses, file uploads)
└── Environment variables (startup)
バリデーションライブラリの選択
| ライブラリ | 最適な用途 |
|---|---|
| Zod | TypeScript 優先、型推論 |
| Valibot | バンドルサイズを小さくしたい場合(ツリーシェイク可能) |
| ArkType | パフォーマンスが重要な場合 |
| Yup | 既存の React Form の利用 |
バリデーションの考え方
- 早期に失敗させる:早い段階でバリデーションします
- 具体的にする:明確なエラーメッセージを使います
- 信頼しない:「内部」のデータであっても信頼しないでください
7. セキュリティの原則
セキュリティチェックリスト(コードではありません)
- 入力バリデーション:すべての入力を検証する
- パラメーター化クエリ:SQL に文字列連結を使用しない
- パスワードのハッシュ化:bcrypt または argon2
- JWT の検証:署名と有効期限を必ず検証する
- レート制限:不正利用から保護する
- セキュリティヘッダー:Helmet.js または同等のもの
- HTTPS:本番環境では常に使用する
- CORS:適切に設定する
- シークレット:環境変数のみを使用する
- 依存関係:定期的に監査する
セキュリティの考え方
Trust nothing:
├── Query params → validate
├── Request body → validate
├── Headers → verify
├── Cookies → validate
├── File uploads → scan
└── External APIs → validate response
8. テストの原則
テスト戦略の選択
| 種類 | 目的 | ツール |
|---|---|---|
| ユニット | ビジネスロジック | node:test, Vitest |
| インテグレーション | API エンドポイント | Supertest |
| E2E | 一連のフロー全体 | Playwright |
テスト対象(優先順位)
- 重要な経路:認証、決済、コアビジネス
- エッジケース:空の入力、境界値
- エラー処理:問題が発生した場合、何が起きるか
- テストする価値がないもの:フレームワークのコード、単純なゲッター
組み込みテストランナー(Node.js 20 以降で安定版)
node --test src/**/*.test.ts
├── No external dependency
├── Good coverage reporting
└── Watch mode available
9. 避けるべきアンチパターン
❌ してはいけないこと:
- 新しいエッジプロジェクトで Express を使う(Hono を使ってください)
- 本番コードで同期メソッドを使う
- ビジネスロジックをコントローラーに記述する
- 入力検証を省略する
- シークレットをハードコードする
- 検証せずに外部データを信頼する
- CPU 処理でイベントループをブロックする
✅ するべきこと:
- コンテキストに基づいてフレームワークを選ぶ
- ユーザーの希望が不明な場合は確認する
- プロジェクトの成長に合わせてレイヤードアーキテクチャを使う
- すべての入力を検証する
- シークレットには環境変数を使う
- 最適化の前にプロファイリングする
10. 判断チェックリスト
実装を始める前に:
- ユーザーにスタックの希望を確認しましたか?
- このコンテキストに適したフレームワークを選びましたか?(単にデフォルトを選ぶのではなく)
- デプロイ先を考慮しましたか?
- エラー処理の方針を計画しましたか?
- 検証が必要な箇所を特定しましたか?
- セキュリティ要件を考慮しましたか?
覚えておいてください:Node.js のベストプラクティスとは、パターンを暗記することではなく、判断することです。あらゆるプロジェクトで、その要件に基づいて改めて検討する必要があります。
コメント
Markdown 対応