Với vị trí Fresher hoặc kỹ sư mới tốt nghiệp, nhà tuyển dụng hiếm khi đòi hỏi bạn phải thông thạo mọi framework mới nhất trên thị trường. Thay vào đó, họ sẽ tập trung đào sâu vào các kiến thức nền tảng (Computer Science fundamentals) để kiểm tra tư duy logic, mức độ hiểu sâu bản chất và tiềm năng phát triển dài hạn. Bài viết này tổng hợp 5 mảng kiến thức trọng tâm thường xuyên xuất hiện trong vòng phỏng vấn kỹ thuật cùng cách trả lời chuẩn xác, gãy gọn.
1. Lập trình hướng đối tượng (OOP): Bản chất thay vì thuộc lòng định nghĩa
Hầu hết ứng viên đều có thể đọc thuộc lòng 4 tính chất: Đóng gói (Encapsulation), Kế thừa (Inheritance), Đa hình (Polymorphism) và Trừu tượng (Abstraction). Tuy nhiên, người phỏng vấn sẽ không dừng lại ở lý thuyết mà thường đưa ra bài toán thiết kế thực tế để kiểm tra năng lực áp dụng.
Câu hỏi điển hình: 'Khi nào dùng Interface thay vì Abstract Class?' hoặc 'Tại sao nên ưu tiên Composition over Inheritance?'. Bạn cần làm rõ Interface đóng vai trò là một bản hợp đồng hành vi (Contract/Can-do), hỗ trợ đa kế thừa giao diện và giúp giảm độ phụ thuộc (loose coupling). Trong khi đó, Abstract Class thể hiện mối quan hệ bản chất (Is-a) và cho phép chia sẻ mã nguồn dùng chung (state và implementation mặc định). Việc lạm dụng kế thừa nhiều tầng sẽ làm code bị cứng nhắc, khó bảo trì và phá vỡ tính bao đóng khi lớp cha thay đổi.
- Interface: Định nghĩa 'hành vi' mà class cam kết thực thi (ví dụ: `PaymentGateway`, `Exportable`, `Serializable`).
- Abstract Class: Định nghĩa 'danh tính chung' và tái sử dụng logic nền tảng (ví dụ: `BaseEntity`, `AbstractController`).
- Composition over Inheritance: Thay vì ép `RobotDog` kế thừa từ `Dog`, hãy inject các thành phần như `Barkable` hoặc `Walkable` vào `RobotDog` để linh hoạt thay đổi hành vi tại runtime.
2. Cấu trúc dữ liệu & Thuật toán: Hiểu cơ chế bên dưới và Cache Locality
Thay vì chỉ hỏi độ phức tạp Big-O trên giấy, nhà tuyển dụng kỹ thuật thường đào sâu vào cách dữ liệu thực sự được tổ chức trong bộ nhớ. Một câu hỏi kinh điển: 'Tại sao việc duyệt mảng (Array) lại nhanh hơn danh sách liên kết (LinkedList) đáng kể dù cả hai đều có độ phức tạp thời gian O(N)?'.
Bản chất nằm ở Cache Locality (tính cục bộ không gian của bộ nhớ đệm CPU). Mảng lưu trữ các phần tử ở các ô nhớ liên tiếp nhau, cho phép CPU nạp nguyên một khối (Cache Line) vào L1/L2 Cache để xử lý tức thì. Ngược lại, các Node của LinkedList nằm rải rác trên vùng nhớ Heap, dẫn đến tình trạng Cache Miss liên tục và CPU buộc phải đọc từ RAM chính với độ trễ cao hơn hàng chục lần.
Bên cạnh đó, chủ đề đụng độ hàm băm (Hash Collision) trong Hash Table cũng là câu hỏi phân loại ứng viên. Bạn cần giải thích được hai kỹ thuật phổ biến là Separate Chaining (dùng Linked List hoặc chuyển sang Red-Black Tree khi bucket quá dài) và Open Addressing (Linear/Quadratic Probing).
- Array vs LinkedList: Array tối ưu cho Sequential Access và Index Lookup O(1) nhờ bộ nhớ liên tục; LinkedList linh hoạt khi thêm/xoá nhưng tốn bộ nhớ lưu trữ con trỏ (pointer overhead).
- Hash Collision: Hiểu cơ chế giải quyết xung đột và lý do cấu trúc như `HashMap` trong Java chuyển đổi LinkedList sang Red-Black Tree khi độ dài bucket vượt ngưỡng 8 để giữ worst-case search ở mức O(log N).
3. Cơ sở dữ liệu: Cơ chế hoạt động của Index và bẫy N+1 Query
Trong các hệ quản trị cơ sở dữ liệu quan hệ (RDBMS), phỏng vấn Fresher thường xoay quanh cơ chế tối ưu hoá truy vấn. Người phỏng vấn sẽ hỏi: 'Index giúp tăng tốc độ đọc dữ liệu như thế nào và trường hợp nào Index bị vô hiệu hoá?'.
Hầu hết các Database phổ biến (MySQL, PostgreSQL) sử dụng cấu trúc B+ Tree cho Index. B+ Tree giữ cho cây luôn cân bằng, toàn bộ bản ghi dữ liệu thực tế nằm tại các Node lá và được nối với nhau dạng danh sách liên kết đôi (Doubly Linked List). Cấu trúc này giảm thiểu số lần I/O đọc đĩa và hỗ trợ Range Query (`BETWEEN`, `<`, `>`) cực kỳ hiệu quả. Index sẽ không phát huy tác dụng nếu bạn áp dụng hàm biến đổi trên cột index (ví dụ: `WHERE YEAR(created_at) = 2024`) hoặc vi phạm quy tắc tiền tố ngoài cùng bên trái (Leftmost Prefix Rule) trong Composite Index.
Ngoài ra, bẫy N+1 Query trong các ORM (Hibernate, Entity Framework, Prisma) là lỗi thường gặp nhất của lập trình viên mới. Hiện tượng này xảy ra khi hệ thống thực hiện 1 câu query lấy danh sách cha, sau đó chạy thêm N câu query phụ trong vòng lặp để lấy dữ liệu bảng con liên kết. Giải pháp chuẩn là chuyển từ Lazy Loading sang Eager Loading thông qua `JOIN FETCH` hoặc câu lệnh `include`/`preload`.
- B+ Tree Index: Giảm thiểu Disk I/O, tối ưu truy vấn khoảng nhờ các Node lá liên kết tuần tự.
- Index Invalidation: Tránh ép kiểu ngầm định (Implicit Type Conversion), tránh dùng wildcard ở đầu (`LIKE '%abc'`), tránh bọc function quanh indexed column.
- N+1 Query Problem: Phân biệt rõ Lazy Loading vs Eager Loading, xử lý triệt để bằng `JOIN` hoặc gom batch query với mệnh đề `IN`.
4. Hệ điều hành: Process vs Thread và Vùng nhớ Stack vs Heap
Hiểu về Hệ điều hành giúp nhà tuyển dụng nhận biết bạn là người thực sự hiểu cách chương trình vận hành bên dưới phần cứng thay vì chỉ lắp ráp thư viện.
Process là một chương trình đang thực thi với không gian địa chỉ bộ nhớ (Address Space) độc lập. Thread là luồng xử lý nhỏ hơn chạy bên trong Process; các Thread chia sẻ chung vùng nhớ Heap, Data và Code Segment nhưng sở hữu Call Stack và tập thanh ghi (Registers) riêng. Việc chuyển đổi ngữ cảnh (Context Switching) giữa các Thread diễn ra nhanh hơn và tốn ít tài nguyên hơn so với Process.
Về mô hình bộ nhớ của một ứng dụng: Vùng nhớ Stack được quản lý tự động theo cơ chế LIFO, lưu trữ Call Stack, biến cục bộ (primitive types) và con trỏ tham chiếu, tốc độ cấp phát siêu nhanh nhưng kích thước bị giới hạn cố định (dễ gặp lỗi `StackOverflowError` khi đệ quy sâu). Vùng nhớ Heap dùng để cấp phát động cho các đối tượng (Objects), kích thước lớn hơn nhiều nhưng yêu cầu cơ chế thu gom rác (Garbage Collector) hoặc giải phóng thủ công, chi phí cấp phát và truy cập chậm hơn Stack.
- Process vs Thread: Process cô lập tài nguyên và an toàn hơn; Thread chia sẻ bộ nhớ nên cần đồng bộ hoá (Synchronization) cẩn thận để tránh Race Condition và Deadlock.
- Stack Memory: Tự động cấp phát/thu hồi theo vòng đời hàm, tốc độ cực cao, dung lượng nhỏ.
- Heap Memory: Cấp phát động theo nhu cầu lúc runtime, kích thước linh hoạt, chịu sự quản lý của GC.
5. Mạng & Web Lifecycle: Đường đi trọn vẹn của một HTTP Request
Câu hỏi 'Điều gì xảy ra từ lúc bạn gõ URL vào trình duyệt cho đến khi trang web hiển thị?' là bài kiểm tra kinh điển về bức tranh tổng thể (Big Picture) của một kỹ sư phần mềm.
Bạn cần trình bày mạch lạc theo đúng trình tự các tầng giao thức: Đầu tiên là phân giải tên miền qua DNS Lookup (kiểm tra Browser Cache, OS Cache, Router Cache, rồi đến Recursive DNS Server để tìm địa chỉ IP đích). Tiếp theo là thiết lập kết nối TCP thông qua quá trình bắt tay 3 bước (3-Way Handshake: SYN -> SYN-ACK -> ACK). Nếu dùng giao thức HTTPS, hai bên sẽ tiếp tục thực hiện TLS/SSL Handshake để trao đổi khoá phiên và mã hoá đường truyền.
Sau khi kênh truyền sẵn sàng, Client gửi HTTP Request chứa Method, Headers và Body. Phía Server tiếp nhận request qua Reverse Proxy/Load Balancer (như Nginx), chuyển tới Application Server để chạy logic nghiệp vụ, truy vấn Database và trả về HTTP Response (kèm Status Code tương ứng). Cuối cùng, trình duyệt bóc tách dữ liệu để xây dựng DOM Tree, CSSOM Tree và tiến hành Render giao diện.
- DNS Resolution: Quy trình chuyển đổi tên miền dạng người đọc sang IP dạng máy hiểu.
- TCP & TLS Handshake: Đảm bảo tính tin cậy của kết nối truyền nhận và an toàn bảo mật dữ liệu.
- HTTP Status Codes: Nắm vững ý nghĩa cốt lõi của 2xx (Thành công), 3xx (Chuyển hướng), 4xx (Lỗi từ phía Client) và 5xx (Lỗi nội bộ Server).
- Tính Idempotent trong RESTful: Hiểu rõ tại sao GET, PUT, DELETE là Idempotent (gọi nhiều lần kết quả trạng thái hệ thống không đổi) còn POST thì không.
Ghi nhớ nhanh
- Tập trung trả lời bản chất 'Tại sao' (Why) và 'Như thế nào' (How) thay vì học thuộc lòng định nghĩa mặt chữ.
- Luôn liên hệ lý thuyết nền tảng với bài toán thực tế như tối ưu bộ nhớ đệm, cấu trúc dữ liệu và xử lý tắc nghẽn truy vấn.
- Trình bày có cấu trúc rõ ràng: nêu định nghĩa cốt lõi, so sánh ưu/nhược điểm, sau đó đưa ra ví dụ thực tế trong code.
- Chuẩn bị sẵn tâm thế cho câu hỏi mở rộng: 'Nếu dữ liệu tăng lên gấp 100 lần, giải pháp hiện tại sẽ gặp điểm nghẽn (bottleneck) ở đâu?'.