シニアバックエンド開発者(Node.js)面接対策:完全ガイド

Milad Bonakdar
著者
システム設計、アーキテクチャパターン、パフォーマンス最適化、スケーラビリティ、マイクロサービス、およびリーダーシップを網羅した30の重要な面接質問で、高度なNode.jsバックエンド開発をマスターしましょう。シニアバックエンド開発者の面接に最適な準備です。
はじめに
この包括的なガイドでは、高度な Node.js バックエンド開発に関する30の必須面接質問を掲載しています。これらの質問は、Event Loop、Streams、システム設計、パフォーマンス最適化における主要な概念を網羅することで、シニアバックエンド開発者が面接の準備をするのに役立つように設計されています。各質問には、詳細な回答、希少性評価、および難易度評価が含まれています。
シニア開発者として、Node.jsのシングルスレッドの性質と、それに基づいてスケーラブルで高性能なシステムを構築する方法を深く理解していることが期待されます。
高度な Node.js の概念 (10個の質問)
1. Node.js のイベントループについて詳しく説明してください。異なるフェーズは何ですか?
回答: イベントループは、Node.js がシングルスレッドであるにもかかわらず、ノンブロッキング I/O 操作を実行できるようにするものです。可能な限り、操作をシステムカーネルにオフロードします。
- フェーズ:
- タイマー:
setTimeout()およびsetInterval()によってスケジュールされたコールバックを実行します。 - 保留中のコールバック: 次のループイテレーションに延期された I/O コールバックを実行します。
- アイドル、準備: 内部使用のみ。
- ポーリング: 新しい I/O イベントを取得します。I/O 関連のコールバックを実行します。他のタスクがない場合、ループはここでブロックされます。
- チェック:
setImmediate()によってスケジュールされたコールバックを実行します。 - クローズコールバック: クローズコールバックを実行します (例:
socket.on('close', ...)).
- タイマー:
希少性: 非常に一般的 難易度: 難しい
2. process.nextTick() と setImmediate() の違いは何ですか?
回答:
process.nextTick(): イベントループの一部ではありません。現在の操作が完了した直後、ただしイベントループが続行する前に発生します。setImmediate()よりも優先度が高くなります。過度に使用すると、イベントループをブロックする可能性があります(飢餓状態)。setImmediate(): イベントループのチェックフェーズの一部です。ポーリングフェーズの後に実行されます。
希少性: 一般的 難易度: 普通
3. Node.js はシングルスレッドの場合、どのように並行処理を処理しますか?
回答: Node.js は、イベント駆動型のノンブロッキング I/O モデルを使用します。
- メインスレッド: JavaScript コードを実行します (V8 エンジン)。
- Libuv: イベントループとスレッドプールを提供する C ライブラリ(デフォルトは4スレッド)。
- メカニズム: 非同期操作(ファイル I/O やネットワークリクエストなど)が開始されると、Node.js はそれを Libuv にオフロードします。Libuv は、そのスレッドプール(ファイル I/O、DNS 用)またはシステムカーネルの非同期メカニズム(ネットワーク用)を使用します。操作が完了すると、コールバックはメインスレッドによって実行されるように、イベントループキューにプッシュされます。
希少性: 一般的 難易度: 普通
4. Node.js の Streams とその種類について説明してください。
回答: Streams は、連続したチャンクでソースからデータを読み取ったり、宛先にデータを書き込んだりできるオブジェクトです。データをすべてメモリにロードする必要がないため、メモリ効率が高くなります。
- 種類:
- Readable: データを読み取るため (例:
fs.createReadStream)。 - Writable: データを書き込むため (例:
fs.createWriteStream)。 - Duplex: 読み取りと書き込みの両方 (例: TCP ソケット)。
- Transform: 出力が入力に基づいて計算される Duplex ストリーム (例:
zlib.createGzip)。
- Readable: データを読み取るため (例:
希少性: 一般的 難易度: 普通
5. Streams における Backpressure と、その処理方法は何ですか?
回答: Backpressure は、Readable ストリームが Writable ストリームが処理できるよりも速くデータをプッシュするときに発生します。処理しないと、メモリ使用量が急増し、プロセスがクラッシュする可能性があります。
- 処理:
.pipe(): 最も簡単な方法です。Writable ストリームのバッファがいっぱいになると Readable ストリームを一時停止し、ドレインされると再開することで、自動的に Backpressure を管理します。- 手動: Writable ストリームの
drainイベントをリッスンし、Readable ストリームを手動で一時停止/再開します。
希少性: 普通 難易度: 難しい
6. cluster モジュールはどのように機能しますか?
回答:
Node.js はシングルスレッドであるため、単一の CPU コアで実行されます。cluster モジュールを使用すると、同じサーバーポートを共有する子プロセス(ワーカー)を作成できます。
- マスタープロセス: ワーカーを管理します。
- ワーカープロセス: それぞれがアプリケーションのインスタンスを実行します。
- 利点: 使用可能なすべての CPU コアを利用して、スループットを向上させることができます。
希少性: 一般的 難易度: 普通
7. Worker Threads vs Cluster モジュール: どちらをいつ使用しますか?
回答:
- Cluster: 別のプロセスを作成します。それぞれが独自のメモリ空間と V8 インスタンスを持っています。HTTP サーバー(I/O バウンド)のスケーリングに最適です。
- Worker Threads: 単一のプロセス内にスレッドを作成します。メモリを共有します(
SharedArrayBuffer経由)。メインのイベントループをブロックしないように、CPU 集中型タスク(例:画像処理、暗号化)に最適です。
希少性: 普通 難易度: 難しい
8. キャッチされない例外と未処理の Promise の拒否をどのように処理しますか?
回答:
- キャッチされない例外:
process.on('uncaughtException', cb)をリッスンします。アプリケーションの状態が破損している可能性があるため、通常はエラーをログに記録して(PM2 などのプロセス管理ツールを使用して)プロセスを再起動するのが最善です。 - 未処理の拒否:
process.on('unhandledRejection', cb)をリッスンします。 - ベストプラクティス: 常に
try/catchブロックと Promise で.catch()を使用します。
希少性: 一般的 難易度: 簡単
9. package-lock.json の役割は何ですか?
回答: これは、生成された正確なツリーを記述するもので、後続のインストールで、中間的な依存関係の更新に関係なく、同一のツリーを生成できます。これにより、プロジェクトがすべてのマシン(CI/CD、他の開発者)でまったく同じように動作することが保証されます。
希少性: 一般的 難易度: 簡単
10. Express.js の Middleware の概念について説明してください。
回答:
Middleware 関数は、リクエストオブジェクト (req)、レスポンスオブジェクト (res)、およびアプリケーションのリクエスト-レスポンスサイクル内の次の Middleware 関数 (next) にアクセスできる関数です。
- タスク: コードの実行、req/res オブジェクトの変更、リクエスト-レスポンスサイクルの終了、次の Middleware の呼び出し。
- 順序: 定義された順序で順番に実行されます。
希少性: 一般的 難易度: 簡単
システム設計とアーキテクチャ (10個の質問)
11. リアルタイムチャットアプリケーションをどのように設計しますか?
回答:
- プロトコル: 全二重通信用の WebSockets (
socket.ioまたはwsを使用)。 - バックエンド: Node.js は、多数の同時接続を処理するイベント駆動型の性質があるため、理想的です。
- スケーリング:
- Redis Pub/Sub: 複数のサーバーインスタンスがある場合、サーバー A に接続されたユーザーは、サーバー B のユーザーにメッセージを送信する必要があります。Redis Pub/Sub は、サーバー間でメッセージをブロードキャストするメッセージブローカーとして機能します。
- データベース:
- メッセージ: 高い書き込みスループットのための NoSQL (MongoDB/Cassandra)。
- ユーザー: リレーショナル (PostgreSQL) または NoSQL。
希少性: 非常に一般的 難易度: 難しい
12. Node.js のマイクロサービス: 通信パターン。
回答:
- 同期: HTTP/REST または gRPC。単純なリクエスト/レスポンスに適しています。
- 非同期: メッセージキュー (RabbitMQ、Kafka、SQS)。サービスの分離と負荷スパイクの処理に適しています。
- イベント駆動型: サービスがイベントを発行し、他のサービスがリッスンします。
希少性: 一般的 難易度: 普通
13. 分散トランザクション (Saga パターン) はどのように処理しますか?
回答: マイクロサービスでは、トランザクションが複数のサービスにまたがる場合があります。ACID を保証するのは困難です。
- Saga パターン: ローカルトランザクションのシーケンス。各ローカルトランザクションはデータベースを更新し、イベントまたはメッセージを発行して、Saga の次のローカルトランザクションをトリガーします。
- 補償: ローカルトランザクションが失敗した場合、Saga は一連の補償トランザクションを実行して、先行するローカルトランザクションによって行われた変更を元に戻します。
希少性: 普通 難易度: 難しい
14. サーキットブレーカーパターンについて説明してください。
回答: 失敗する可能性が高い操作(例:ダウンしたマイクロサービスの呼び出し)をアプリケーションが繰り返し実行しようとするのを防ぎます。
- 状態:
- クローズ: リクエストは通過します。
- オープン: サービスを呼び出さずに、リクエストはすぐに失敗します(高速フェイル)。
- ハーフオープン: サービスが回復したかどうかを確認するために、限られた数のリクエストを許可します。
希少性: 普通 難易度: 普通
15. Node.js API をどのように保護しますか?
回答:
- Helmet: アプリを保護するために、さまざまな HTTP ヘッダーを設定します。
- レート制限: DDoS/ブルートフォース攻撃を防ぐために、
express-rate-limitを使用します。 - 入力検証:
JoiまたはZodなどのライブラリを使用します。 - 認証: JWT または OAuth2。
- CORS: 信頼できるドメインのみを許可するように適切に構成します。
- NoSQL インジェクション: MongoDB インジェクションに対して入力をサニタイズします。
希少性: 一般的 難易度: 普通
16. サーバーレスとは何ですか?また、Node.js とどのように適合しますか?
回答: サーバーレス(例:AWS Lambda)を使用すると、サーバーをプロビジョニングまたは管理せずにコードを実行できます。
- Node.js の適合性: Node.js は、起動時間(コールドスタート)が速く、軽量であるため、サーバーレスに最適です。
- ユースケース: API エンドポイント、イベント処理 (S3 アップロード)、スケジュールされたタスク。
希少性: 普通 難易度: 普通
17. GraphQL と REST について説明してください。いつ GraphQL を使用しますか?
回答:
- REST: 複数のエンドポイント、データの過剰フェッチまたは過少フェッチ。
- GraphQL: 単一のエンドポイント、クライアントは必要なものだけを要求します。
- GraphQL の使用: 複雑なデータ要件がある場合、異なるデータ形状を必要とする複数のクライアント (Web、モバイル) がある場合、またはネットワークラウンドトリップを減らす場合。
希少性: 一般的 難易度: 普通
18. Node.js でのキャッシュの実装方法。
回答:
- インメモリ:
node-cache(単一インスタンスには適していますが、再起動時にデータが失われ、共有されません)。 - 分散: Redis (業界標準)。
- 戦略: Cache-Aside、Write-Through。
- HTTP キャッシュ: ETag、Cache-Control ヘッダーを使用します。
希少性: 一般的 難易度: 普通
19. データベース接続プーリング。
回答: リクエストごとに新しいデータベース接続を開くのはコストがかかります。
- プーリング: 再利用できるデータベース接続のキャッシュを維持します。
- Node.js:
pg(PostgreSQL) やmongooseなどのライブラリは、プーリングを自動的に処理します。ワークロードと DB の制限に基づいて、プールサイズを構成する必要があります。
希少性: 普通 難易度: 普通
20. Node.js でのファイルアップロードの処理方法。
回答:
- Multipart/form-data: ファイルアップロードの標準エンコード。
- ライブラリ:
multer(Express 用の Middleware)、formidable、busboy。 - ストレージ: サーバーのファイルシステムにファイルを保存しないでください (ステートレス)。AWS S3 などのクラウドストレージにアップロードします。ファイルをメモリにロードしないように、ファイルを S3 に直接ストリーミングします。
希少性: 一般的 難易度: 普通
パフォーマンスとテスト (10個の質問)
21. Node.js のメモリリークをどのようにデバッグしますか?
回答:
- 症状: 時間の経過とともにメモリ使用量が増加する (RSS)、最終的なクラッシュ。
- ツール:
- Node.js インスペクター:
--inspectフラグ、Chrome DevTools で接続します。 - ヒープスナップショット: スナップショットを取得して比較し、ガベージコレクションされていないオブジェクトを見つけます。
process.memoryUsage(): プログラムで監視します。
- Node.js インスペクター:
希少性: 一般的 難易度: 難しい
22. Node.js アプリケーションのプロファイリング。
回答: プロファイリングは、CPU ボトルネックを特定するのに役立ちます。
- 組み込みプロファイラー:
node --prof app.js。ログファイルを生成します。node --prof-process isolate-0x...logで処理します。 - Clinic.js: パフォーマンスの問題を診断するためのツールスイート (
clinic doctor、clinic flame、clinic bubbleprof)。
希少性: 普通 難易度: 難しい
23. 「イベントループをブロックしない」ルールについて説明してください。
回答: スレッドが 1 つしかないため、長時間実行される同期操作(例:重い計算、同期ファイル読み取り、複雑な正規表現)を実行すると、イベントループが停止します。他のリクエストは処理できません。
- 解決策: 計算を分割する (setImmediate)、Worker Threads を使用する、またはマイクロサービスにオフロードする。
希少性: 非常に一般的 難易度: 簡単
24. Node.js のユニットテストと統合テスト。
回答:
- ユニットテスト: 個々の関数/モジュールを分離してテストします。依存関係をモックします。(ツール:Jest、Mocha、Chai)。
- 統合テスト: モジュールがどのように連携するかをテストします (例:API エンドポイント + データベース)。(ツール: Supertest)。
希少性: 一般的 難易度: 簡単
25. TDD (テスト駆動開発) とは何ですか?
回答: コードの前にテストを記述する開発プロセス。
- 失敗するテストを記述します (赤)。
- テストに合格するために最小限のコードを記述します (緑)。
- コードをリファクタリングします (リファクタリング)。
希少性: 普通 難易度: 普通
26. 本番環境の Node.js アプリでログをどのように処理しますか?
回答:
console.logを使用しないでください: 場合によってはターミナル/ファイルへの書き込み時に同期(ブロッキング)になり、構造がありません。- ロガーを使用してください: Winston、Bunyan、または Pino。
- 構造: ログ管理ツール (ELK Stack、Datadog) で簡単に解析できる JSON 形式。
- レベル: Error、Warn、Info、Debug。
希少性: 一般的 難易度: 簡単
27. セマンティックバージョニング (SemVer) について説明してください。
回答:
形式: MAJOR.MINOR.PATCH (例: 1.2.3)。
- MAJOR: 互換性のない API の変更。
- MINOR: 後方互換性のある機能。
- PATCH: 後方互換性のあるバグ修正。
^vs~:^1.2.3は<2.0.0に更新されます。~1.2.3は<1.3.0に更新されます。
希少性: 一般的 難易度: 簡単
28. 環境変数とは何ですか?また、どのように管理しますか?
回答:
- 目的: DB URL、API キーなど、環境 (開発、ステージング、本番) によって異なる構成。
- 使用法:
process.env.VARIABLE_NAME。 - 管理: ローカル開発用の
.envファイル (dotenvパッケージを使用)。本番環境では、OS またはコンテナ/プラットフォームの設定で設定します。
希少性: 一般的 難易度: 簡単
29. Node.js アプリケーションをどのようにデプロイしますか?
回答:
- プロセス管理ツール: PM2 (アプリを稼働させ続け、再起動、ログを処理します)。
- リバースプロキシ: Nginx (SSL、静的ファイル、ロードバランシングを処理します) -> Node.js アプリ。
- コンテナ化: Docker (標準)。
- オーケストレーション: Kubernetes。
- CI/CD: GitHub Actions、Jenkins。
希少性: 一般的 難易度: 普通
30. イベントエミッターとは何ですか?
回答:
events モジュールは、Node.js イベント駆動型アーキテクチャの中核です。
- 使用法:
- 多くのコアモジュールがそれを拡張します:
fs.ReadStream、net.Server、http.Server。
希少性: 一般的 難易度: 簡単



