Việc làm

25/09 · Hà Nội · Tại văn phòng

Thực tập sinh Lập trình tích hợp

FPT IS · 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 (Java, Node.js, 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. 01Lỗi N+1 query trong JPA/Hibernate là gì và xử lý ra sao?Java

    Gợi ý trả lời

    N+1 xảy ra khi bạn lấy N bản ghi bằng 1 query, rồi mỗi lần truy cập quan hệ lazy lại phát sinh thêm 1 query. Ví dụ lấy 100 đơn hàng, rồi gọi order.getCustomer() trong vòng lặp là thành 101 query.

    Cách xử lý:

    • JOIN FETCH trong JPQL: select o from Order o join fetch o.customer.
    • @EntityGraph(attributePaths = "customer") trên method của repository.
    • @BatchSize hoặc hibernate.default_batch_fetch_size để gom lazy load thành câu IN (...).
    • Với màn hình chỉ đọc, trả thẳng DTO projection thay vì entity.

    Phát hiện bằng cách bật log SQL (spring.jpa.show-sql hoặc log của Hibernate) khi dev, hoặc dùng thống kê của Hibernate.

    Hay sai: đổi sang FetchType.EAGER cho xong. Cách này chỉ đổi chỗ lỗi và làm mọi truy vấn khác nặng hơn. Fetch join nhiều collection cùng lúc cũng dễ gây tích Descartes.

    Ôn thêm câu hỏi Java →
  2. 02Bộ nhớ JVM gồm những vùng nào? Garbage Collector hoạt động ra sao và Java có bị memory leak không?Java

    Gợi ý trả lời

    Hai vùng chính: stack (mỗi thread một stack, chứa biến cục bộ và tham chiếu) và heap (chứa object, dùng chung). Ngoài ra có Metaspace chứa thông tin class.

    • GC tìm các object không còn được tham chiếu từ "GC roots" (biến trên stack, field static...) và thu hồi.
    • Heap chia theo thế hệ: object mới nằm ở young generation, sống lâu thì được chuyển lên old generation.
    • G1 là GC mặc định; ZGC hợp khi cần pause rất ngắn với heap lớn.

    Java vẫn leak khi object không dùng nữa mà vẫn còn tham chiếu:

    • Cache hoặc static Map chỉ thêm, không bao giờ xoá.
    • ThreadLocal không remove() trong thread pool.
    • Listener đăng ký mà không huỷ.

    Người phỏng vấn muốn nghe: phân biệt được OutOfMemoryError: Java heap space với lỗi Metaspace, và biết dùng heap dump để tìm ai đang giữ object.

    Ôn thêm câu hỏi Java →
  3. 03Phân biệt == và equals(). Vì sao override equals() thì phải override cả hashCode()?Java · Junior

    Gợi ý trả lời

    == so sánh tham chiếu (hai biến có trỏ cùng một object không), còn equals() so sánh nội dung theo logic bạn định nghĩa.

    • Hợp đồng: hai object equals nhau thì bắt buộc có cùng hashCode.
    • HashMap/HashSet dùng hashCode để chọn bucket trước, rồi mới dùng equals để so trong bucket. Nếu chỉ override equals, hai object "bằng nhau" có thể rơi vào hai bucket khác nhau, nên set.contains(x) trả về false dù đã add.
    • Với Java 16+, record tự sinh equals/hashCode/toString theo các field.

    Hay sai: so sánh String hoặc Integer bằng ==. Nó có thể chạy đúng nhờ string pool hoặc cache Integer từ -128 đến 127, rồi sai với giá trị khác.

    Ôn thêm câu hỏi Java →
  4. 04Trong NestJS, module, provider và dependency injection hoạt động ra sao? Guard, interceptor, pipe khác nhau thế nào?Node.js

    Gợi ý trả lời

    NestJS tổ chức app thành module. Mỗi module khai báo controller, provider (service, repository) và exports những gì module khác được dùng. IoC container của Nest tự tạo provider và inject qua constructor.

    @Injectable()
    export class OrdersService {
      constructor(private readonly repo: OrdersRepository) {}
    }
    

    Thứ tự một request đi qua: middleware, guard, interceptor (trước), pipe, handler, interceptor (sau); exception filter bắt lỗi ở bất kỳ bước nào.

    • Guard: quyết định request có được đi tiếp không (xác thực, phân quyền).
    • Pipe: biến đổi và validate input (ValidationPipe với DTO).
    • Interceptor: bọc quanh handler: log, đo thời gian, đổi định dạng response, cache.

    Hay sai: hai provider phụ thuộc vòng tròn rồi xử lý bằng forwardRef khắp nơi. Thường đó là dấu hiệu nên tách lại trách nhiệm giữa các module.

    Ôn thêm câu hỏi Node.js →
  5. 05Node.js chạy đơn luồng thì làm sao xử lý được nhiều request cùng lúc? Node hợp với loại ứng dụng nào?Node.js · Junior

    Gợi ý trả lời

    Code JavaScript của bạn chạy trên một thread, nhưng I/O (mạng, file, DB) là non-blocking: Node giao việc cho hệ điều hành hoặc thread pool của libuv, rồi tiếp tục xử lý request khác. Khi I/O xong, callback được đưa lại vào event loop.

    • Hợp với: API, BFF, real-time (WebSocket, chat), proxy, ứng dụng nhiều I/O và ít tính toán.
    • Không hợp nếu chỉ dùng thread chính cho tác vụ nặng CPU: mã hoá video, xử lý ảnh lớn, tính toán dài.
    // Chặn cả server: mọi request khác phải chờ
    app.get("/hash", (req, res) => {
      res.send(crypto.pbkdf2Sync(pw, salt, 1e6, 64, "sha512"));
    });
    

    Người phỏng vấn muốn nghe: "đơn luồng" chỉ đúng với phần code JS; Node vẫn dùng thread pool cho file system, DNS, một số hàm crypto và zlib.

    Ôn thêm câu hỏi Node.js →
  6. 06Con trỏ và tham chiếu (reference) trong C++ khác nhau thế nào?C/C++ & Embedded · Junior

    Gợi ý trả lời

    Con trỏ là biến chứa địa chỉ, có thể nullptr và trỏ sang đối tượng khác. Tham chiếu là tên gọi khác của một đối tượng đã tồn tại, phải khởi tạo ngay và không gán lại được.

    int x = 1, y = 2;
    int* p = &x;  p = &y;   // đổi đối tượng được trỏ
    int& r = x;   r = y;    // gán giá trị y cho x
    
    • Truyền tham số: dùng const T& cho đối tượng lớn chỉ đọc, T& khi cần sửa, con trỏ khi tham số có thể vắng mặt.
    • Có con trỏ tới con trỏ và phép toán số học trên con trỏ; tham chiếu thì không.

    Hay sai: trả về tham chiếu hoặc con trỏ tới biến cục bộ. Biến bị huỷ khi hàm kết thúc và dùng nó là undefined behavior.

    Ôn thêm câu hỏi C/C++ & Embedded →
  7. 07Vì sao String là immutable? Khi nào dùng StringBuilder thay cho String?Java · Junior

    Gợi ý trả lời

    String bất biến: mọi thao tác "sửa" đều tạo object mới. Nhờ vậy nó an toàn khi chia sẻ giữa nhiều thread, dùng làm key cho HashMap được (hash không đổi) và JVM có thể dùng chung qua string pool.

    • Nối chuỗi trong vòng lặp bằng + tạo nhiều object trung gian, nên dùng StringBuilder:
    var sb = new StringBuilder();
    for (String s : items) sb.append(s).append(',');
    String result = sb.toString();
    
    • StringBuffer giống StringBuilder nhưng các method có synchronized, chậm hơn và hiếm khi cần.
    • Nối vài chuỗi trên một dòng thì cứ dùng +, compiler đã tối ưu sẵn.

    Người phỏng vấn muốn nghe: bạn hiểu lý do thiết kế (an toàn, hash, pool), không chỉ thuộc định nghĩa.

    Ôn thêm câu hỏi Java →
  8. 08Checked exception và unchecked exception khác nhau thế nào? try-with-resources dùng để làm gì?Java · Junior

    Gợi ý trả lời

    Checked exception (kế thừa Exception nhưng không phải RuntimeException) bị compiler bắt buộc phải catch hoặc khai báo throws, ví dụ IOException. Unchecked (RuntimeException và con của nó) thì không, ví dụ NullPointerException, IllegalArgumentException.

    • Checked hợp với lỗi bên ngoài mà caller có thể xử lý được; unchecked thường là lỗi lập trình hoặc vi phạm điều kiện.
    • try-with-resources tự gọi close() cho mọi object implement AutoCloseable, kể cả khi có exception:
    try (var reader = Files.newBufferedReader(path)) {
        return reader.readLine();
    }
    

    Hay sai: catch (Exception e) {} rồi bỏ trống, làm mất dấu lỗi. Ít nhất phải log kèm stack trace, hoặc bọc lại thành exception có ý nghĩa và ném tiếp.

    Ôn thêm câu hỏi Java →
  9. 09HashMap hoạt động bên trong như thế nào? So sánh ArrayList và LinkedList.Java · Junior

    Gợi ý trả lời

    HashMap là mảng các bucket. Khi put, nó tính hashCode() của key, suy ra chỉ số bucket, rồi lưu entry vào đó. Nhiều key trùng bucket thì nối thành danh sách; từ Java 8, khi một bucket quá dài thì chuyển thành cây đỏ đen để tránh tìm kiếm O(n).

    • Khi số phần tử vượt capacity * loadFactor (mặc định 0.75) thì map resize gấp đôi và phân bố lại.
    • get/put trung bình O(1). HashMap không thread-safe.

    ArrayList dựa trên mảng: truy cập theo index O(1), thêm cuối nhanh, chèn/xoá ở giữa phải dời phần tử. LinkedList là danh sách liên kết đôi: truy cập theo index O(n), tốn bộ nhớ hơn cho mỗi node.

    Người phỏng vấn muốn nghe: trên thực tế ArrayList gần như luôn nhanh hơn nhờ dữ liệu nằm liền nhau trong bộ nhớ (cache-friendly).

    Ôn thêm câu hỏi Java →
  10. 10Bạn có câu hỏi gì cho chúng tôi không?Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Luôn có câu hỏi. Đây là cơ hội thể hiện sự quan tâm và cũng là lúc bạn đánh giá công ty.

    Câu hỏi nên chuẩn bị (chọn 2–3 câu hợp với người đang phỏng vấn):

    • "Một ngày làm việc của vị trí này thường như thế nào? Team có bao nhiêu người, gồm những vai trò gì?"
    • "Ba tháng đầu, anh/chị kỳ vọng người vào vị trí này làm được gì?"
    • "Team đang gặp thách thức kỹ thuật hoặc quy trình nào lớn nhất?"
    • "Quy trình release và code review của team ra sao?"
    • "Công ty đánh giá hiệu suất và review lương theo chu kỳ nào?"
    • "Vì sao vị trí này đang tuyển: mở rộng team hay thay người?"

    Hay sai: "Dạ không ạ", hoặc chỉ hỏi về nghỉ phép, lương thưởng ngay ở vòng kỹ thuật. Chuyện chế độ nên hỏi kỹ với HR.

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

Bạn đã phỏng vấn ở FPT IS?

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