バックエンド面接の準備をしていると、概念を一つずつ切り離して覚えてしまいがちです。でも実際の面接では、データ構造、OS、JVM、Spring、データベース、デプロイといった話題が、ひとつの流れの中でつながって問われることが多いです。
そこで今回は、質問リストをそのまま並べるのではなく、バックエンド開発者が理解しておきたい重要概念を学習の流れに沿って整理した文書としてまとめました。基礎から運用、Spring、データアクセス、デプロイまでを一続きの知識として見られるようにしています。
まずはデータ構造と探索から整理する#
バックエンド開発では、データをどれだけ速く探せるか、衝突をどう処理するか、探索コストをどう下げるかという考え方が重要です。こうした基礎は、面接でもよく確認されます。
ハッシュ衝突を解決する代表的な方法として、オープンアドレッシングとセパレートチェイニングがあります。
- オープンアドレッシング(Open Addressing) は、衝突が起きたときにハッシュテーブル配列の中から別の空きスロットを探して保存します。
- セパレートチェイニング(Separate Chaining) は、各バケットに連結リストや木構造などの別構造を持たせ、衝突した値をそこに保存します。
オープンアドレッシングは配列ベースなのでキャッシュ効率が良いことがありますが、負荷率が高くなると性能が急激に落ちやすいです。一方、セパレートチェイニングはメモリをより使いますが、衝突への耐性は比較的安定しています。Java の HashMap も基本的にはチェイニング方式です。
探索アルゴリズムとしては、DFS と BFS の違いもはっきり理解しておきたいです。
- DFS(Depth-First Search) は、一つの経路を深くたどっていき、進めなくなったら戻ります。
- BFS(Breadth-First Search) は、近いノードから順番に広げながら探索します。
DFS は再帰やスタックで実装されることが多く、経路探索やバックトラッキングによく使われます。BFS はキューを使い、重みのないグラフでの最短距離問題に強いです。
メモリとOSの視点で考える#
データ構造とアルゴリズムの先に進むと、プログラムが実際にメモリ上でどう動くのかを理解する必要があります。これは障害対応や性能分析に直結します。
代表的な概念のひとつが LRU です。LRU はページ置換アルゴリズムの一つで、最も長い間使われていないページを追い出す方式です。最近使ったデータは近いうちにまた使われやすい、という局所性の考え方に基づいています。
FIFO と比べると違いが分かりやすいです。FIFO は先に入ったものを先に追い出しますが、LRU は最近の利用履歴を考慮するので、実用的な判断になりやすいです。ただし厳密な LRU は実装コストが高いため、実際のシステムでは近似的な方法がよく使われます。
メモリ問題を追ううえでは ヒープダンプ も重要です。ヒープダンプは JVM のヒープ状態をファイルとして保存し、どのオブジェクトがメモリを多く占有しているかを調べる方法です。
特に次のような場面で役立ちます。
OutOfMemoryErrorが発生したとき- オブジェクトが増え続けてメモリリークが疑われるとき
- GC が頻繁に走るのに、メモリがうまく回収されないとき
実務では jmap や jcmd でダンプを取り、Eclipse MAT で dominator tree や leak suspects を確認することが多いです。大事なのは「ヒープダンプを触ったことがある」ではなく、どのオブジェクトがメモリを保持していて、なぜリークが起きたのかを説明できることです。
JVM の安定性は GC と並行性を一緒に見る#
バックエンドサーバーは継続的にリクエストを処理するので、メモリ回収と並行性制御を一緒に理解しておくことが、安定したサービス運用につながります。
まず GC(Garbage Collection) は、参照されなくなったオブジェクトを回収して JVM メモリを管理する仕組みです。基本は Young 領域と Old 領域、そして Minor GC や Major GC / Full GC から説明すると整理しやすいです。
代表的な GC としては次のようなものがあります。
- Serial GC: 単一スレッドで単純ですが、停止時間が長くなりやすいです
- Parallel GC: スループット重視です
- CMS: 応答遅延の削減を狙った方式ですが、現在はかなり置き換えられています
- G1 GC: region 単位で管理し、実務でもよく見ます
- ZGC, Shenandoah: 非常に短い pause time を重視しています
GC とあわせてよく出てくるのが スレッドセーフ(Thread Safe) です。複数スレッドが同時にアクセスしても、データの整合性が崩れないようにすることが目的です。
代表的な方法としては次のようなものがあります。
- 共有状態を減らし、可能なら不変オブジェクトを使う
- 必要な臨界区間だけを
synchronized、Lock、ReentrantLockで守る ConcurrentHashMapのような並行コレクションを使うAtomicIntegerやAtomicLongのような原子的操作を使う- スレッドごとに独立した状態が必要なら
ThreadLocalを使う
ここで大切なのは、「ロックをたくさん使うこと」ではなく、そもそも共有可変状態を減らす設計を優先することです。ロックはボトルネックやデッドロックの原因にもなります。
テストとアノテーションはフレームワーク理解につながる#
面接でテスト経験を聞かれるのは、単に文法を知っているかを見るためではありません。安全にコードを変えられるか、検証しやすい構造を作れているかを見ていることが多いです。
テストは次のように層で考えると整理しやすいです。
- 単体テスト: サービスやユーティリティロジックを素早く検証します
- 統合テスト: Spring コンテキスト、DB、外部連携を確認します
- API テスト: コントローラのリクエストとレスポンスを検証します
実務では JUnit、Mockito、MockMvc、Testcontainers の組み合わせをよく見ます。特に決済、注文、在庫、クーポンのように失敗コストが大きい領域では、テストの価値がさらに高くなります。
この流れで理解しておきたいのが アノテーションの動作 です。たとえば JUnit 4 では、
@BeforeClassはテストクラス全体で一度だけ実行されます@Beforeは各テストメソッドの前に毎回実行されます@Testは実際のテストメソッドです
つまり通常は @BeforeClass -> (@Before -> @Test -> @After) の繰り返し -> @AfterClass という順で動きます。
もう少し深く見ると、Java のアノテーションはメタデータです。ランタイムまで保持されるアノテーションはリフレクションで読み取ることができ、フレームワークやテストランナーがそのメタデータを解釈して適切なタイミングでメソッドを呼び出します。つまりアノテーションは単なる記法ではなく、フレームワークの動作ルールを宣言的に表す手段だと捉えると分かりやすいです。
Java の理解は関数型インターフェースとデザインパターンに表れる#
Java を使うバックエンド開発者なら、オブジェクト指向と関数型スタイルの両方に慣れていることが望ましいです。
まず 関数型インターフェース(Functional Interface) は、抽象メソッドを一つだけ持つインターフェースです。ラムダ式やメソッド参照を受け取るために使われます。java.util.function パッケージの代表的な型は押さえておきたいです。
Supplier<T>: 入力なしで値を返しますConsumer<T>: 値を受け取って消費し、戻り値はありませんFunction<T, R>: 入力を別の型の結果に変換しますPredicate<T>: 真偽値を返します
このほかにも UnaryOperator、BinaryOperator、BiFunction、BiConsumer、BiPredicate などがあります。
デザインパターンもよく問われるテーマです。ただし名前を並べることよりも、どんな問題を解決するために使うのかを説明できることが重要です。
よく挙げられるのは次のようなパターンです。
- Singleton: インスタンスを一つだけに保ちたいとき
- Strategy: アルゴリズムを差し替え可能にしたいとき
- Template Method: 共通フローを親クラスに置き、詳細を子クラスに任せたいとき
- Proxy: アクセス制御、遅延読み込み、付加機能に使いたいとき
- Decorator: 機能を動的に拡張したいとき
- Adapter: 異なるインターフェースをつなぎたいとき
- Builder: 複雑なオブジェクト生成を分かりやすくしたいとき
- Observer: 状態変化を購読して通知したいとき
- Factory: 生成責務を分離したいとき
こうしたパターンは Spring の中にも多く見られます。AOP は Proxy パターンとつながりますし、各種 Builder クラスは Builder、イベントリスナーは Observer として説明できます。
Spring では Bean Scope と AOP を一緒に理解するとよい#
Spring はオブジェクトを生成して管理するコンテナなので、Bean Scope は基本概念です。Scope は Bean がどれくらい生存し、どの範囲で共有されるかを表します。
主なスコープは次の通りです。
singleton: デフォルトで、コンテナごとに一つですprototype: 取得のたびに新しいインスタンスが作られますrequest: HTTP リクエストごとに一つですsession: HTTP セッションごとに一つですapplication: サーブレットコンテキスト単位ですwebsocket: WebSocket セッション単位です
実務ではほとんどの場合 singleton を基本に使い、状態を持つ request / session スコープの Bean は慎重に扱う必要があります。
もう一つ、Spring を語るうえで外しにくいのが AOP(Aspect-Oriented Programming) です。AOP は、ロギング、トランザクション、認可チェック、実行時間測定のように、複数箇所にまたがって現れる関心事を分離する考え方です。
主要な概念は次の通りです。
- Aspect: 共通関心をまとめたモジュールです
- Advice: 何をいつ実行するかです
- Pointcut: どこに適用するかです
- Join Point: 適用可能な実行地点です
Spring AOP は通常 Proxy ベースで動きます。実務では API 実行時間の記録、特定パッケージのトレース、共通トランザクション処理などに使われますが、使いすぎると制御フローが見えにくくなります。
API とネットワークは一緒に見ておきたい#
RESTful API を設計するなら、HTTP メソッドの意味を明確に理解しておく必要があります。
特に比較されやすいのが PUT と PATCH です。
- PUT はリソース全体を置き換える考え方です
- PATCH はリソースの一部更新に向いています
たとえばユーザー情報全体を更新するなら PUT、ニックネームだけを変えるなら PATCH のほうが自然です。実務では PUT を部分更新のように扱うこともありますが、意味としては PATCH のほうが適切なことが多いです。
ネットワークの観点では HTTP/2 も理解しておくとよいです。HTTP/2 は HTTP/1.1 の非効率を改善するために登場しました。
主な特徴は次の通りです。
- 一つの接続で複数リクエストを同時に扱う マルチプレクシング
- 重複ヘッダのコストを下げる ヘッダ圧縮
- 必要なリソースを先に送れる サーバープッシュ
- テキストより効率的な バイナリフレーミング
実務では HTTP/2 を直接実装するより、Nginx、CDN、ロードバランサー、Web サーバー設定を通じて使うことがほとんどです。そのため、このテーマは概念理解とインフラ設定への接続で整理しておくと十分です。
データアクセスでは N+1 とモデル説明力が重要#
バックエンド面接でよく出る永続化の問題の一つが N+1 問題 です。ある集合を一度取得したあと、関連エンティティを読むたびに追加クエリが N 回発生する問題です。
たとえば注文を 100 件読み込み、そのたびに会員情報を遅延ロードすると、合計 101 クエリになることがあります。データ量が増えるほど、これは大きな性能問題になります。
代表的な解決策は次の通りです。
fetch joinを使うEntityGraphを使う@BatchSizeやdefault_batch_fetch_sizeのようなバッチ取得を使う- DTO を直接取得する
- ローディング戦略そのものを見直す
重要なのは、何でも即時ロードに変えることではなく、実際のアクセスパターンに合わせて戦略を選ぶことです。
もう一つよく聞かれるのが DB 構造の説明 です。これには唯一の正解があるわけではなく、自分が扱ったサービスのドメインモデルをどれだけ構造的に説明できるかが見られます。
たとえば EC ドメインなら次のように説明できます。
- 会員
- 商品
- 注文
- 注文明細
- 決済
- クーポン
- レビュー
そして、会員と注文は 1:N、注文と注文明細も 1:N、注文明細と商品は N:1 といった関係を説明します。そこからさらに、インデックス、正規化と非正規化、大規模テーブルの扱い、トランザクション境界までつなげられると、より深い回答になります。
運用経験は監視とデプロイ戦略に表れる#
運用経験を問う質問では、ツール名を並べることよりも、どのシグナルを見て、どう原因を絞り込んだかを説明することが大切です。
監視ツールはおおむね次のように整理できます。
- Prometheus + Grafana: メトリクス収集と可視化
- ELK / OpenSearch: ログ収集と検索
- Pinpoint / Datadog / New Relic / SkyWalking: APM とトレーシング
- Spring Boot Actuator: アプリケーション状態の公開
本質は、メトリクス、ログ、トレースを組み合わせて障害を素早く検知し、原因を絞り込むことです。
デプロイ戦略も同じくらい重要です。サーバー台数が増えると、「どうデプロイするか」よりも、どう無停止でデプロイし、安全にロールバックできるかが重要になります。
代表的な方法は次の通りです。
- ローリングデプロイ
- ブルーグリーンデプロイ
- カナリアデプロイ
たとえばサーバーが 20 台あるなら、CI でビルドとテストを行い、成果物やイメージを作成し、まず一部にだけ配布してヘルスチェックと監視指標を確認し、問題がなければ段階的に広げる、という説明が自然です。問題が起きたときは、すぐにロールバックできることも必要です。
Kubernetes 環境なら rolling update、readiness probe、liveness probe と結びつけて話せますし、VM ベースなら Jenkins、Ansible、SSH 自動化などと結びつけて説明できます。
最後は実際に使った技術スタックを説明できるようにする#
どのバージョンの Spring、Spring Boot、MySQL を使ったかという質問は、暗記よりも 実際にどの技術エコシステムを経験したか を確かめる意味合いが強いです。
たとえば次のように答えられます。
- Spring Framework 5.x、6.x
- Spring Boot 2.x、3.x
- MySQL 5.7、8.0
さらに差分まで説明できると良いです。たとえば Spring Boot 3 は Java 17 以上が前提で、javax から jakarta へ移行しました。MySQL 8.0 では CTE やウィンドウ関数のサポートが強化されました。
あわせて、どんな開発書を読んだかも整理しておくとよいです。『Effective Java』、『オブジェクト指向設計実践ガイド』、『Clean Code』、『Unit Testing』、『Designing Data-Intensive Applications』のような本から、何を実務に活かしたかまで話せると学習姿勢も伝わります。
まとめ#
バックエンド面接の準備は、個別の答えを暗記するよりも、重要概念が実際のサービス開発や運用にどうつながるかを理解することのほうがずっと効果的です。
データ構造と探索は問題解決の出発点になり、OS と JVM の知識は信頼性につながります。Spring とテストは実装の安定性を示し、データベースとデプロイ戦略は実務的な判断力を表します。
結局のところ、多くの面接トピックは次の4つで整理すると答えやすくなります。
- それは何か
- なぜ必要か
- いつ使うか
- どんなトレードオフがあるか
この形で整理しておけば、深掘りの質問にも落ち着いて答えやすくなります。