Việc làm

11/09 · Hồ Chí Minh · Hà Nội · Tại văn phòng

ADAS Embedded Software Architect

Bosch Global Software Technologies · Embedded Engineer

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 (C/C++ & Embedded, System Design & Kiến trúc). 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. 01Undefined behavior trong C/C++ là gì? Cho ví dụ và cách phát hiện.C/C++ & Embedded · Senior

    Gợi ý trả lời

    Undefined behavior (UB) là những thao tác mà chuẩn ngôn ngữ không quy định kết quả. Compiler được phép giả định UB không bao giờ xảy ra và tối ưu theo giả định đó, nên lỗi có thể chỉ lộ ra ở bản build -O2 hoặc trên một compiler khác.

    Ví dụ hay gặp:

    • Tràn số nguyên có dấu (tràn số không dấu thì được định nghĩa là quay vòng).
    • Truy cập mảng ngoài phạm vi, dereference con trỏ null hoặc dangling.
    • Đọc biến chưa khởi tạo, data race giữa các thread.
    • Vi phạm strict aliasing, vd. ép float* sang int* rồi đọc (nên dùng memcpy hoặc std::bit_cast từ C++20).

    Phát hiện: bật cảnh báo -Wall -Wextra, chạy test với -fsanitize=address,undefined, dùng static analysis (clang-tidy, cppcheck, MISRA checker).

    Người phỏng vấn muốn nghe: "chạy đúng trên máy tôi" không chứng minh code không có UB.

    Ôn thêm câu hỏi C/C++ & Embedded →
  2. 02Thiết bị nhúng thỉnh thoảng bị treo hoặc reset ngoài hiện trường. Bạn debug thế nào?C/C++ & Embedded · Senior

    Gợi ý trả lời

    Cần thu thập dấu vết từ thiết bị trước, sau đó tái hiện trong phòng lab.

    • Lưu nguyên nhân reset: đọc thanh ghi reset cause (watchdog, brown-out, hard fault) khi khởi động và ghi vào flash hoặc gửi log lên.
    • Hard fault handler: lưu các thanh ghi PC, LR và stack frame để biết lệnh gây lỗi, sau đó tra file .map hoặc addr2line.
    • Stack overflow: bật kiểm tra stack của RTOS, tô mẫu (stack painting) để đo mức dùng tối đa.
    • Watchdog: chỉ "đá" watchdog khi mọi task quan trọng còn sống, không đá trong ISR timer.
    • Kiểm tra phần cứng: nguồn sụt áp, nhiễu, nhiệt độ.

    Trong lab dùng JTAG/SWD với GDB, logic analyzer và chạy stress test dài.

    Người phỏng vấn muốn nghe: một ca thật bạn đã xử lý, cách khoanh vùng và cách chứng minh đã sửa đúng.

    Ôn thêm câu hỏi C/C++ & Embedded →
  3. 03Lập trình đa luồng trong C++ hiện đại: std::atomic, mutex và memory order dùng khi nào?C/C++ & Embedded · Senior

    Gợi ý trả lời

    Dữ liệu chia sẻ giữa các thread mà có ít nhất một thread ghi thì phải đồng bộ, nếu không là data race (undefined behavior).

    • std::mutex với std::lock_guard hoặc std::scoped_lock (khoá nhiều mutex không deadlock): dùng cho vùng găng có nhiều biến hoặc logic phức tạp.
    • std::atomic<T>: cho biến đơn lẻ như cờ, bộ đếm, không cần khoá.
    • Memory order: mặc định seq_cst an toàn nhất. acquire/release dùng cho mẫu producer/consumer; relaxed chỉ cho bộ đếm thống kê không cần thứ tự.
    • C++20 bổ sung std::jthread (tự join, có stop token), std::latch, std::barrier, std::counting_semaphore.
    std::atomic<int> hits{0};
    hits.fetch_add(1, std::memory_order_relaxed);
    

    Hay sai: dùng memory order yếu khi chưa thật hiểu, hoặc lock-free hoá sớm khi mutex đã đủ nhanh. Kiểm tra bằng ThreadSanitizer.

    Ôn thêm câu hỏi C/C++ & Embedded →
  4. 04Là kiến trúc sư, bạn đưa ra và ghi lại một quyết định kiến trúc quan trọng như thế nào?System Design & Kiến trúc · Senior

    Gợi ý trả lời

    Quyết định kiến trúc là chọn trade-off dựa trên ràng buộc thực tế (nghiệp vụ, đội ngũ, ngân sách, thời gian), không phải chọn công nghệ "tốt nhất".

    • Xác định các thuộc tính chất lượng quan trọng nhất (hiệu năng, sẵn sàng, bảo mật, chi phí, khả năng thay đổi) và sắp xếp ưu tiên cùng stakeholder.
    • Đưa ra 2–3 phương án, so sánh rủi ro; làm POC hoặc spike cho điểm chưa chắc chắn.
    • Ghi lại bằng ADR (Architecture Decision Record): bối cảnh, quyết định, phương án đã loại, hệ quả. Lưu cùng repo để người sau hiểu "vì sao".
    • Phân biệt quyết định khó đảo ngược (chọn DB, ranh giới service) với quyết định dễ thay đổi; quyết định dễ đảo ngược thì nên làm nhanh.
    • Xem lại quyết định khi bối cảnh thay đổi.

    Người phỏng vấn muốn nghe: bạn thuyết phục đội ngũ bằng dữ liệu, lắng nghe phản biện, và kể được một quyết định từng sai cùng cách bạn sửa.

    Ôn thêm câu hỏi System Design & Kiến trúc →
  5. 05Monolith và microservices: khi nào nên tách? Cái giá phải trả là gì?System Design & Kiến trúc

    Gợi ý trả lời

    Microservices giải quyết vấn đề tổ chức: nhiều team cần deploy độc lập và scale riêng từng phần. Nó không tự làm hệ thống nhanh hơn.

    Nên cân nhắc tách khi:

    • Nhiều team đụng nhau trong cùng codebase, deploy phải chờ nhau.
    • Một phần có tải hoặc yêu cầu công nghệ rất khác phần còn lại.
    • Ranh giới nghiệp vụ (bounded context) đã rõ ràng và ổn định.

    Cái giá: gọi mạng thay vì gọi hàm (độ trễ, lỗi một phần), nhất quán dữ liệu phân tán, cần tracing, service discovery, CI/CD và vận hành phức tạp hơn.

    Người phỏng vấn muốn nghe: "modular monolith" là bước khởi đầu hợp lý: chia module rõ ràng trong một ứng dụng, sau này tách theo đúng ranh giới đó. Tách sai ranh giới tạo ra "distributed monolith", tệ hơn cả monolith.

    Ôn thêm câu hỏi System Design & Kiến trúc →
  6. 06Bạn thiết kế firmware thế nào để dễ test, dễ port sang vi điều khiển khác và áp dụng SOLID?C/C++ & Embedded · Senior

    Gợi ý trả lời

    Tách phần phụ thuộc phần cứng ra sau một lớp trừu tượng, để logic nghiệp vụ chạy và test được trên máy tính.

    • Phân lớp: driver thanh ghi / HAL → BSP → service (giao thức, lưu trữ) → application.
    • Dependency inversion: application phụ thuộc interface (struct chứa con trỏ hàm trong C, abstract class hoặc template trong C++), không gọi thẳng thanh ghi.
    • Single responsibility: mỗi module một việc, như đọc cảm biến, lọc tín hiệu, gửi dữ liệu.
    • Unit test trên host với Unity, CppUTest hoặc GoogleTest bằng driver giả; test trên phần cứng (HIL) cho phần còn lại.
    • Máy trạng thái (state machine) rõ ràng cho logic phức tạp.
    • CI build nhiều target, chạy static analysis và kiểm tra theo chuẩn code (vd. MISRA).

    Người phỏng vấn muốn nghe: bạn cân đối được giữa trừu tượng hoá và giới hạn RAM, flash, thời gian thực.

    Ôn thêm câu hỏi C/C++ & Embedded →
  7. 07RAII 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 →
  8. 08Move semantics và rvalue reference giải quyết vấn đề gì? Rule of 3/5/0 là gì?C/C++ & Embedded

    Gợi ý trả lời

    Move semantics cho phép chuyển tài nguyên (buffer, handle) từ một object tạm hoặc sắp bị bỏ đi sang object khác thay vì sao chép sâu. Rvalue reference T&& nhận các object như vậy; std::move chỉ là phép ép kiểu để cho phép move.

    std::vector<int> a(1'000'000);
    std::vector<int> b = std::move(a);  // chuyển con trỏ, không chép 1 triệu phần tử
    
    • Rule of 3: nếu tự viết destructor, copy constructor hoặc copy assignment thì gần như phải viết đủ cả ba.
    • Rule of 5: thêm move constructor và move assignment.
    • Rule of 0: tốt nhất là không tự viết hàm nào, để các thành viên RAII (vector, unique_ptr) lo.

    Hay sai: dùng lại object sau khi đã move. Object vẫn hợp lệ nhưng ở trạng thái không xác định.

    Ôn thêm câu hỏi C/C++ & Embedded →
  9. 09Thiết kế cache: các chiến lược cache-aside, write-through và cách xử lý cache invalidation.System Design & Kiến trúc

    Gợi ý trả lời

    Cache giảm độ trễ và tải cho DB, đổi lại phải chấp nhận dữ liệu có thể cũ trong một khoảng thời gian.

    • Cache-aside (phổ biến nhất): đọc cache, miss thì đọc DB rồi ghi vào cache kèm TTL. Khi cập nhật thì ghi DB rồi xoá key cache.
    • Write-through: ghi qua cache rồi cache ghi xuống DB, dữ liệu cache luôn mới nhưng ghi chậm hơn.
    • Write-behind: ghi cache trước, đẩy xuống DB sau; nhanh nhưng có thể mất dữ liệu.

    Các vấn đề cần xử lý:

    • Cache stampede: key nóng hết hạn, hàng nghìn request cùng đánh vào DB. Giải pháp: lock hoặc single-flight, làm mới sớm, thêm độ lệch ngẫu nhiên cho TTL.
    • Cache penetration: truy vấn key không tồn tại liên tục. Giải pháp: cache cả kết quả rỗng, dùng bloom filter.

    Hay sai: cập nhật cache thay vì xoá, dễ ghi đè giá trị cũ khi hai request chạy song song.

    Ôn thêm câu hỏi System Design & Kiến trúc →
  10. 10Vì sao bạn chọn ứng tuyển vào công ty chúng tôi?Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Câu này kiểm tra bạn có tìm hiểu không hay chỉ rải CV. Nối ba thứ: công ty, vị trí, và bạn.

    • Tìm hiểu trước: sản phẩm, khách hàng, công nghệ, tin tức gần đây, đánh giá của nhân viên cũ và hiện tại.
    • Chọn một hai điểm cụ thể bạn thật sự quan tâm: sản phẩm bạn từng dùng, bài toán kỹ thuật, quy mô người dùng, văn hoá làm việc.
    • Nối với kinh nghiệm hoặc mục tiêu của bạn.

    Câu mẫu: "Em có dùng ứng dụng của bên mình và thấy phần thanh toán rất mượt. Trong JD có nói team đang mở rộng hệ thống xử lý giao dịch, đúng mảng em đã làm hai năm. Em nghĩ mình đóng góp được ngay và cũng học được nhiều ở quy mô lớn hơn."

    Hay sai: "Vì công ty lớn, lương tốt" hoặc khen chung chung áp vào công ty nào cũng được.

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

Bạn đã phỏng vấn ở Bosch Global Software Technologies?

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