Việc làm

24/09 · Hồ Chí Minh · Tại văn phòng

Backend Developer

SHINHAN DS · Backend Developer

Xem mô tả & ứng tuyển trên ITviecMô tả công việc, lương và ứng tuyển nằm ở ITviec.

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 (JavaScript & TypeScript, SQL & Database, C/C++ & Embedded). 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.

  1. 01Closure là gì? Giải thích kết quả của vòng lặp for (var i...) với setTimeout.JavaScript & TypeScript · Junior

    Gợi ý trả lời

    Closure là khi một hàm "nhớ" được các biến ở phạm vi nơi nó được tạo ra, kể cả sau khi hàm bên ngoài đã chạy xong.

    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 0);
    }
    // In ra 3, 3, 3
    
    • var chỉ có một biến i cho cả vòng lặp. Khi callback chạy, vòng lặp đã xong và i bằng 3.
    • Đổi sang let thì mỗi vòng lặp có một i riêng, in ra 0, 1, 2.

    Ứng dụng thực tế: tạo biến private, hàm factory, debounce, memoize, và các hook trong React.

    Hay sai: closure giữ tham chiếu đến biến chứ không chụp lại giá trị. Closure giữ object lớn quá lâu (ví dụ trong listener không gỡ) cũng là nguồn rò rỉ bộ nhớ.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  2. 02this trong JavaScript được xác định thế nào? Arrow function khác function thường ở điểm nào?JavaScript & TypeScript · Junior

    Gợi ý trả lời

    Với function thường, this phụ thuộc vào cách gọi, không phải nơi định nghĩa:

    • obj.method(): this là obj.
    • Gọi hàm trơn fn(): undefined trong strict mode (module và class luôn là strict).
    • new Fn(): object mới được tạo.
    • fn.call(x), fn.apply(x), fn.bind(x): this là x.

    Arrow function không có this riêng; nó lấy this của phạm vi bao ngoài. Arrow function cũng không có arguments và không dùng được với new.

    const btn = { label: "OK", click() { setTimeout(() => console.log(this.label)); } };
    

    Hay sai: truyền obj.method làm callback (setTimeout(obj.method)) rồi mất this. Cách sửa: bind, hoặc bọc trong arrow function.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  3. 03Event loop của JavaScript hoạt động thế nào? Đoạn code sau in ra theo thứ tự nào?JavaScript & TypeScript

    Gợi ý trả lời

    JavaScript chạy trên một thread. Code đồng bộ chạy hết trên call stack trước, sau đó event loop lấy việc từ hàng đợi. Microtask (Promise .then, await, queueMicrotask) luôn được chạy hết trước khi sang macrotask tiếp theo (setTimeout, sự kiện I/O, sự kiện người dùng).

    console.log(1);
    setTimeout(() => console.log(2));
    Promise.resolve().then(() => console.log(3));
    console.log(4);
    // 1, 4, 3, 2
    
    • Trên trình duyệt, việc render thường diễn ra giữa các macrotask.
    • Một vòng lặp đồng bộ dài, hoặc chuỗi microtask không dứt, sẽ làm treo giao diện.

    Người phỏng vấn muốn nghe: setTimeout(fn, 0) không chạy ngay mà chỉ được xếp hàng, và vì sao microtask được ưu tiên.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  4. 04Transaction là gì? Giải thích ACID.SQL & Database · Junior

    Gợi ý trả lời

    Transaction là một nhóm thao tác được thực hiện như một đơn vị: hoặc tất cả thành công (COMMIT), hoặc không có gì xảy ra (ROLLBACK).

    • Atomicity: không có trạng thái làm dở dang.
    • Consistency: sau transaction dữ liệu vẫn thoả ràng buộc (khoá ngoại, unique, check).
    • Isolation: các transaction chạy đồng thời không thấy dữ liệu dở dang của nhau, mức độ tuỳ isolation level.
    • Durability: đã commit thì không mất dù server sập (nhờ write-ahead log / redo log).
    BEGIN;
    UPDATE accounts SET balance = balance - 500 WHERE id = 1;
    UPDATE accounts SET balance = balance + 500 WHERE id = 2;
    COMMIT;
    

    Người phỏng vấn muốn nghe: một ví dụ thực tế như chuyển tiền hoặc trừ tồn kho, và bạn biết giữ transaction ngắn, không gọi API bên ngoài khi đang mở transaction.

    Ôn thêm câu hỏi SQL & Database →
  5. 05Composite index (index nhiều cột) hoạt động ra sao? Thứ tự cột có quan trọng không?SQL & Database

    Gợi ý trả lời

    Có. Composite index sắp xếp theo cột đầu, rồi đến cột thứ hai trong cùng giá trị cột đầu, v.v. Vì vậy nó chỉ dùng hiệu quả khi query dùng các cột từ trái sang (leftmost prefix).

    Với INDEX (status, created_at):

    • WHERE status = 'paid' AND created_at > ...: dùng tốt.
    • WHERE status = 'paid' ORDER BY created_at DESC: dùng cho cả lọc lẫn sắp xếp.
    • WHERE created_at > ... (không có status): thường không dùng được.

    Nguyên tắc chọn thứ tự: cột so sánh bằng (=) đặt trước, cột so sánh khoảng hoặc sắp xếp đặt sau. Nếu index chứa đủ mọi cột query cần (covering index) thì DB không phải đọc lại bảng.

    Hay sai: tạo riêng index cho từng cột rồi nghĩ rằng chúng sẽ kết hợp hiệu quả như một composite index.

    Ôn thêm câu hỏi SQL & Database →
  6. 06RAII là gì? So sánh unique_ptr, shared_ptr và weak_ptr.C/C++ & Embedded

    Gợi ý trả lời

    RAII (Resource Acquisition Is Initialization): gắn tài nguyên vào vòng đời một object; constructor lấy tài nguyên, destructor tự giải phóng. Nhờ vậy không rò rỉ kể cả khi có exception hoặc return sớm.

    • unique_ptr: sở hữu duy nhất, chỉ move được, không tốn thêm chi phí so với con trỏ thường. Nên là lựa chọn mặc định.
    • shared_ptr: sở hữu chung bằng bộ đếm tham chiếu (cập nhật atomic), giải phóng khi bộ đếm về 0.
    • weak_ptr: quan sát một shared_ptr mà không tăng bộ đếm, dùng phá vòng tham chiếu (vd. con trỏ ngược từ con về cha).
    auto dev = std::make_unique<Device>("/dev/i2c-1");
    

    Hay sai: dùng shared_ptr khắp nơi "cho an toàn", làm mờ quyền sở hữu và tốn chi phí atomic.

    Ôn thêm câu hỏi C/C++ & Embedded →
  7. 07So sánh Promise.all, Promise.allSettled, Promise.race và Promise.any. Xử lý lỗi với async/await thế nào?JavaScript & TypeScript

    Gợi ý trả lời

    Cả bốn đều chạy nhiều Promise song song, khác nhau ở cách kết thúc:

    • all: chờ tất cả thành công; một cái lỗi là reject ngay.
    • allSettled: chờ tất cả xong, trả về trạng thái từng cái; không bao giờ reject.
    • race: lấy kết quả (thành công hay lỗi) của cái xong đầu tiên; hay dùng để đặt timeout.
    • any: lấy cái thành công đầu tiên; chỉ reject khi tất cả đều lỗi.
    try {
      const [user, orders] = await Promise.all([getUser(id), getOrders(id)]);
    } catch (err) {
      showError(err);
    }
    

    Hay sai: await lần lượt trong vòng lặp các request không phụ thuộc nhau, khiến tổng thời gian cộng dồn. Ngược lại, gọi Promise.all với hàng nghìn request cùng lúc có thể làm quá tải server; khi đó cần giới hạn số request đồng thời.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  8. 08Trong TypeScript, interface và type khác nhau thế nào? Phân biệt any, unknown và never.JavaScript & TypeScript

    Gợi ý trả lời

    Cả hai đều mô tả hình dạng object và phần lớn trường hợp dùng thay nhau được.

    • interface có thể gộp khai báo (declaration merging) và extends; hợp để mô tả object, API công khai.
    • type mô tả được union, tuple, kiểu ánh xạ, kiểu điều kiện: type Status = "idle" | "loading".

    Ba kiểu đặc biệt:

    • any: tắt kiểm tra kiểu, lỗi lọt qua compiler.
    • unknown: nhận mọi giá trị nhưng bắt buộc thu hẹp kiểu trước khi dùng. Hợp cho dữ liệu từ JSON.parse, API, catch (e).
    • never: giá trị không bao giờ xảy ra; dùng để bắt thiếu case trong switch.
    function assertNever(x: never): never {
      throw new Error("Unhandled: " + x);
    }
    

    Hay sai: dùng as SomeType để ép dữ liệu từ API. Đó chỉ là lời hứa với compiler; muốn chắc chắn phải validate lúc runtime (ví dụ bằng Zod).

    Ôn thêm câu hỏi JavaScript & TypeScript →
  9. 09Debounce và throttle khác nhau thế nào? Mỗi cái dùng trong trường hợp nào?JavaScript & TypeScript

    Gợi ý trả lời

    Cả hai giới hạn số lần một hàm chạy khi sự kiện bắn liên tục.

    • Debounce: chỉ chạy sau khi sự kiện ngừng một khoảng thời gian. Hợp với ô tìm kiếm gợi ý (gõ xong mới gọi API), validate form, resize xong mới tính lại layout.
    • Throttle: chạy tối đa một lần mỗi khoảng thời gian. Hợp với scroll, kéo thả, theo dõi vị trí chuột.
    function debounce(fn, ms) {
      let timer;
      return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => fn(...args), ms);
      };
    }
    

    Hay sai: tạo hàm debounce mới mỗi lần render (trong React), khiến timer bị reset liên tục và debounce không có tác dụng. Với ô tìm kiếm, nhớ huỷ request cũ (AbortController) để kết quả cũ không đè kết quả mới.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  10. 10Điểm yếu của bạn là gì?Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Chọn điểm yếu thật, không chí mạng với vị trí, và cho thấy bạn đang cải thiện.

    Cấu trúc: điểm yếu, ảnh hưởng đã gặp, việc bạn đang làm để khắc phục, tiến bộ đến nay.

    Câu mẫu: "Trước đây em hay ngại hỏi khi bị kẹt, tự loay hoay quá lâu, có lần làm trễ task. Giờ em tự đặt giới hạn: kẹt quá một hai giờ mà không có hướng thì em hỏi đồng đội, kèm những gì đã thử. Từ khi làm vậy em xong việc đúng hạn hơn và học được nhanh hơn từ người khác."

    Ví dụ khác có thể dùng: chưa quen nói trước đám đông, tiếng Anh nói chưa trôi chảy, hay ôm việc.

    Hay sai: "Điểm yếu của em là quá cầu toàn" (nghe như né câu hỏi), hoặc nêu điểm yếu là kỹ năng cốt lõi của vị trí.

    Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →

Bạn đã phỏng vấn ở SHINHAN DS?

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