10 câu hỏi có thể gặp khi phỏng vấn
Chọn theo kỹ năng và cấp của tin (Golang, SQL & Database, Data Engineer & Data Analyst). Gợi ý trả lời do Drama Công Ty biên soạn để bạn ôn nhanh, không phải đề của công ty.
01Cần xử lý 10.000 job (gọi API ngoài) với tối đa 20 job chạy cùng lúc, dừng sớm nếu có lỗi. Bạn thiết kế thế nào?Golang · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Golang →Đây là bài worker pool có giới hạn concurrency. Cách gọn nhất là
errgroup(packagegolang.org/x/sync/errgroup):g, ctx := errgroup.WithContext(ctx) g.SetLimit(20) for _, job := range jobs { g.Go(func() error { return process(ctx, job) }) } if err := g.Wait(); err != nil { return err }SetLimitkhiếng.Gochặn lại khi đã đủ 20 goroutine đang chạy.- Lỗi đầu tiên sẽ huỷ
ctx; các job khác phải tôn trọngctx(truyền vào HTTP request) để dừng sớm.
Cách cổ điển: tạo 20 worker đọc từ một channel job, gửi kết quả qua channel khác, đóng channel đúng thứ tự.
Cần nghĩ thêm: rate limit phía API ngoài (
golang.org/x/time/rate), retry có backoff, có cần dừng hết khi một job lỗi hay chỉ ghi lại lỗi rồi tiếp tục.Hay sai: tạo 10.000 goroutine cùng lúc gọi API ngoài, làm cạn connection và bị đối tác chặn.
02Goroutine khác gì OS thread? Làm sao chờ nhiều goroutine chạy xong?Golang · Junior
Gợi ý trả lời
Ôn thêm câu hỏi Golang →Goroutine là "luồng nhẹ" do runtime Go quản lý: stack khởi đầu chỉ vài KB và tự giãn, chi phí tạo rất thấp. Scheduler của Go phân phối nhiều goroutine lên một số ít OS thread (mô hình M:N), số thread chạy song song tối đa theo
GOMAXPROCS.Chờ nhiều goroutine bằng
sync.WaitGroup:var wg sync.WaitGroup for _, u := range urls { wg.Add(1) go func() { defer wg.Done() fetch(u) }() } wg.Wait()Go 1.25 có thêm
wg.Go(func() { ... })gói gọnAddvàDone.Hay sai: gọi
wg.Add(1)bên trong goroutine, khiếnWaitcó thể trả về trước khi goroutine kịp đăng ký. Một lỗi khác: hàmmainkết thúc thì mọi goroutine bị dừng theo, không ai chờ chúng.03Array và slice khác nhau thế nào? Vì sao
appendđôi khi làm thay đổi cả slice khác?Golang · JuniorGợi ý trả lời
Ôn thêm câu hỏi Golang →Array có độ dài cố định và là giá trị (gán là copy toàn bộ). Slice là một "khung nhìn" gồm con trỏ đến mảng bên dưới,
lenvàcap.- Gán hoặc cắt slice (
b := a[1:3]) không copy dữ liệu; hai slice dùng chung mảng bên dưới. appendkhi còncapsẽ ghi thẳng vào mảng chung, nên có thể ghi đè dữ liệu slice khác đang thấy. Khi hếtcap, nó cấp phát mảng mới và từ đó hai slice tách rời.
a := []int{1, 2, 3, 4} b := a[:2] b = append(b, 99) // a thành [1 2 99 4]- Muốn tách hẳn:
slices.Clone(a)hoặc dùng full slice expressiona[:2:2]để giới hạncap. - Biết trước kích thước thì
make([]T, 0, n)để tránh cấp phát lại nhiều lần.
Người phỏng vấn muốn nghe: luôn dùng giá trị trả về của
append(s = append(s, x)).- Gán hoặc cắt slice (
04Phân biệt INNER JOIN, LEFT JOIN, RIGHT JOIN và FULL OUTER JOIN. Khi nào dùng LEFT JOIN?SQL & Database · Junior
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →JOIN quyết định giữ lại những dòng nào khi ghép hai bảng theo điều kiện.
- INNER JOIN: chỉ giữ dòng khớp ở cả hai bảng.
- LEFT JOIN: giữ mọi dòng bảng trái; bảng phải không khớp thì cột thành
NULL. - RIGHT JOIN: ngược lại với LEFT, ít dùng vì có thể đổi chỗ bảng.
- FULL OUTER JOIN: giữ tất cả dòng của cả hai (MySQL không hỗ trợ trực tiếp, phải
UNIONhai LEFT JOIN).
Ví dụ tìm khách chưa từng đặt hàng:
SELECT c.id, c.name FROM customers c LEFT JOIN orders o ON o.customer_id = c.id WHERE o.id IS NULL;Hay sai: đặt điều kiện lọc bảng phải trong
WHERE(vd.WHERE o.status = 'paid') làm LEFT JOIN biến thành INNER JOIN; điều kiện đó phải để trongON.05WHERE và HAVING khác nhau thế nào? Thứ tự thực thi logic của một câu SELECT ra sao?SQL & Database · Junior
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →WHERElọc từng dòng trước khi gom nhóm;HAVINGlọc sauGROUP BY, nên dùng được hàm tổng hợp nhưCOUNT,SUM.Thứ tự logic:
FROM/JOIN→WHERE→GROUP BY→HAVING→SELECT→DISTINCT→ORDER BY→LIMIT/OFFSET.SELECT department_id, AVG(salary) AS avg_salary FROM employees WHERE status = 'active' GROUP BY department_id HAVING AVG(salary) > 20000000;- Vì
SELECTchạy sauWHERE, bạn không dùng được alias của SELECT trong WHERE (đa số DB). - Điều kiện không cần hàm tổng hợp thì nên để ở WHERE để giảm số dòng phải gom nhóm.
Người phỏng vấn muốn nghe: bạn hiểu thứ tự logic, từ đó giải thích được vì sao alias hoặc aggregate dùng sai chỗ bị lỗi.
- Vì
06WHERE khác HAVING thế nào? Thứ tự thực thi logic của một câu SELECT là gì?Data Engineer & Data Analyst · Junior
Gợi ý trả lời
Ôn thêm câu hỏi Data Engineer & Data Analyst →WHERElọc từng dòng trước khi gộp nhóm;HAVINGlọc nhóm sau khi đãGROUP BYvà tính hàm tổng hợp.Thứ tự logic:
FROM/JOIN→WHERE→GROUP BY→HAVING→SELECT→DISTINCT→ORDER BY→LIMIT.SELECT customer_id, COUNT(*) AS orders FROM orders WHERE created_at >= DATE '2026-01-01' GROUP BY customer_id HAVING COUNT(*) >= 3;Hay sai: dùng alias định nghĩa trong
SELECTngay ởWHERE(đa số hệ quản trị báo lỗi), hoặc lọc điều kiện dòng bằngHAVINGlàm truy vấn chậm hơn.07Go xử lý lỗi như thế nào? Khi nào dùng
panic?errors.Isvàerrors.Asđể làm gì?Golang · JuniorGợi ý trả lời
Ôn thêm câu hỏi Golang →Lỗi trong Go là giá trị kiểu
error, được trả về như kết quả thông thường và phải kiểm tra tường minh.panicchỉ dành cho tình huống không thể tiếp tục hoặc lỗi lập trình (ví dụ cấu hình bắt buộc bị thiếu lúc khởi động), không dùng cho lỗi nghiệp vụ.Bọc lỗi để giữ ngữ cảnh mà không mất lỗi gốc:
if err != nil { return fmt.Errorf("load user %d: %w", id, err) } // Ở tầng trên: if errors.Is(err, sql.ErrNoRows) { /* trả 404 */ }errors.Is: so với một lỗi cụ thể trong chuỗi bọc.errors.As: lấy ra lỗi thuộc một kiểu cụ thể để đọc field của nó.recovertrongdeferdùng ở biên (middleware HTTP) để một request panic không làm sập cả server.
Hay sai: dùng
%vthay%wkhi bọc, làmerrors.Iskhông tìm thấy lỗi gốc.08Interface trong Go khác gì Java hay C#? Vì sao một interface chứa con trỏ nil lại khác
nil?Golang · JuniorGợi ý trả lời
Ôn thêm câu hỏi Golang →Go implement interface ngầm định: kiểu nào có đủ method thì tự thoả mãn interface, không cần khai báo
implements. Nhờ vậy interface thường được định nghĩa ở phía sử dụng, nhỏ gọn (io.Readerchỉ có một method), và dễ thay bằng mock khi test.Giá trị interface gồm hai phần: kiểu và giá trị. Nó chỉ bằng
nilkhi cả hai đều nil.func find() error { var err *MyError = nil return err // interface có kiểu *MyError, nên != nil }Caller kiểm tra
err != nilsẽ thấytruedù "không có lỗi".Hay sai: khai báo interface lớn ở phía cài đặt cho mọi struct, theo thói quen từ Java. Câu hay được nhắc trong cộng đồng Go: nhận vào interface, trả về struct cụ thể. Khi không có lỗi, hãy
return niltrực tiếp.09Channel buffered và unbuffered khác nhau thế nào?
selectdùng để làm gì? Khi nào xảy ra deadlock?GolangGợi ý trả lời
Ôn thêm câu hỏi Golang →- Unbuffered: gửi bị chặn đến khi có bên nhận (và ngược lại). Đây là điểm đồng bộ giữa hai goroutine.
- Buffered (
make(chan T, n)): gửi chỉ bị chặn khi buffer đầy, nhận bị chặn khi buffer rỗng.
selectchờ trên nhiều channel cùng lúc, thường dùng cho timeout hoặc huỷ:select { case res := <-results: handle(res) case <-ctx.Done(): return ctx.Err() }Quy tắc: chỉ bên gửi đóng channel; gửi vào channel đã đóng gây panic; nhận từ channel đã đóng trả giá trị zero ngay lập tức (
v, ok := <-chđể phân biệt).for range chdừng khi channel đóng.Deadlock xảy ra khi mọi goroutine đều đang chờ nhau, ví dụ gửi vào channel unbuffered mà không có ai nhận. Runtime báo "all goroutines are asleep" nếu toàn bộ chương trình bị kẹt; kẹt một phần thì không báo gì và thành goroutine leak.
10Bạn thấy mình ở đâu sau 2–3 năm nữa?Câu hỏi hành vi & văn hoá
Gợi ý trả lời
Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →Người phỏng vấn muốn biết mục tiêu của bạn có khớp với hướng phát triển ở công ty và bạn có định gắn bó không.
- Nêu hướng phát triển cụ thể, thực tế: đi sâu chuyên môn (senior, chuyên gia một mảng) hay quản lý (lead, PM).
- Kèm kế hoạch: kỹ năng cần học, trách nhiệm muốn nhận thêm.
- Gắn với cơ hội ở vị trí đang ứng tuyển.
Câu mẫu: "Trong 2–3 năm tới em muốn trở thành senior có thể tự thiết kế và chịu trách nhiệm một module lớn, đồng thời hướng dẫn được các bạn mới. Em đang học thêm về thiết kế hệ thống và thấy team bên mình có nhiều bài toán ở quy mô lớn, rất hợp để em phát triển theo hướng đó."
Hay sai: "Em muốn mở công ty riêng" hoặc "em chưa nghĩ tới". Cũng đừng nói muốn ngồi vào chỗ của người đang phỏng vấn.
Bạn đã phỏng vấn ở FireGroup?
Kể lại các vòng và câu hỏi đã gặp (ẩn danh) để người sau ôn đúng trọng tâm.
Chia sẻ kinh nghiệm phỏng vấn