Bộ câu hỏi phỏng vấn Fresher Web Fullstack - Phần 2

Bộ câu hỏi phỏng vấn Fresher Web Fullstack - Phần 2

·

16 min read

Mở đầu

Lưu ý đây chỉ là bộ câu hỏi tham khảo cho đầu vào của vị trí Fresher Web, có thể sẽ không phù hợp với những anh em đang ở level cao hơn chuẩn bị apply vào công ty mới.

Mỗi công ty thường sẽ ưa thích sử dụng những ngôn ngữ lập trình khác nhau nhất định. Những ngôn ngữ lập trình Backend phổ biến nhất hiện nay là Java, C#, Python, NodeJSPHP.

Nếu bạn có thể apply vào đúng công ty phù hợp với ngôn ngữ lập trình mình đã code quen, thì sẽ dễ dàng để các bạn bắt nhịp khi trở thành Fresher. Để biết công ty đó đang tuyển đầu vào Fresher sử dụng ngôn ngữ gì, thì đơn giản bạn chỉ cần xem mô tả công việc (JD - Job Description) của họ.

Tuy nhiên, "Liệu em có thể apply vào công ty định hướng code C#, trong khi bản thân lại biết NodeJS không?" . Câu trả lời là HOÀN TOÀN CÓ THỂ nhé. Các công ty tuyển Fresher thường sẽ không đặt giới hạn về việc đầu vào các bạn đang biết ngôn ngữ lập trình Backend nào. Mà quan trọng nhất là những kiến thức nền tảng của bạn ra sao. Ngôn ngữ lập trình khác nhau nhiều nhất là ở cú pháp, mà cú pháp thì chỉ cần học 1, 2 tuần, cùng lắm là 1 tháng code thường xuyên thì bạn sẽ cơ bản sử dụng được thôi, do đó nó không phải là vấn đề. Điểm mấu chốt là tư duy lập trình.

Dưới đây sẽ là bộ câu hỏi phỏng vấn Backend dành cho vị trí đầu vào Fresher Fullstack để các bạn có thể tham khảo:

1. Trình bày 4 tính chất của Lập trình hướng đối tượng (OOP). Nêu ví dụ thực tế của từng tính chất này.

  • 4 tính chất của lập trình hướng đối tượng là:

    • Abstraction (Tính trừu tượng)

    • Inheritance (Tính kế thừa)

    • Polymorphism (Tính đa hình)

    • Encapsulation (Tính đóng gói)

  • Thực sự lý thuyết của 4 tính chất này hầu như bạn nào đi phỏng vấn cũng trả lời được cả. Vấn đề gặp phải là các bạn không đưa ra được ví dụ thực tế, mặc dù có thể bản thân các bạn đã từng sử dụng rồi (mình đoán là như vậy, vì khi mình đưa ra ví dụ để giải đáp cho các bạn, thì thường nhận những tiếng Ồ, À, ...)

  • Mình đã từng làm một series video trên Youtube gồm những video ngắn dưới 1 phút để giải thích, cũng như lấy ví dụ thực tế cho 4 tính chất này. Các bạn có thể theo dõi tại đây nhé.

2. Các đặc điểm của Interface. Bạn đã từng sử dụng Interface để làm gì trong code? Tại sao sử dụng Class cũng có thể viết các hàm trong đó, mà bạn lại phải sử dụng Interface?

  • Các đặc điểm của Interface:

    • Interface có thể bao gồm các property và các method, với điều kiện method đó phải rỗng (không có body), chỉ có tên hàm, kiểu dữ liệu đầu vào, đầu ra. Body sẽ được triển khai chi tiết bởi các Class implement Interface đó.

    • Interface không thể tạo ra các đối tượng như các Class, vì nó không có hàm khởi tạo.

    • Tất cả những Class khi implement một Interface, sẽ phải triển khai thân hàm cho toàn bộ các hàm trong Interface đã khai báo.

    • Các property và method trong Interface, mặc định được hiểu là abstractpublic.

  • Interface được sử dụng để đáp ứng tính đóng góitính trừu tượng trong lập trình hướng đối tượng. Các Class gọi đến các hàm trong Interface đó chỉ cần biết tên hàm, đầu vào, đầu ra của hàm đó có kiểu dữ liệu là gì thôi, không cần quan tâm chi tiết thân hàm sẽ được triển khai như thế nào.

  • Các ngôn ngữ lập trình Backend như Java, C# thường không hỗ trợ đa kế thừa (multiple inheritance), mà một class con chỉ có thể duy nhất một class cha. Tuy nhiên, với việc sử dụng Interface, một class sẽ có thể implement nhiều interface cùng lúc.

  • Tại sao sử dụng Class cũng có thể viết các hàm trong đó, mà bạn lại phải sử dụng Interface?

    • Thứ nhất, bạn có thể coi Interface như một bản hợp đồng, mà tất cả các Class implement Interface đó sẽ đều phải tuân theo các quy tắc đã có trong hợp đồng (triển khai thân hàm cho tất cả các hàm trong interface).

      • Nếu không sử dụng Interface, mà chỉ sử dụng Class với các hàm có tên, đầu vào, đầu ra giống nhau, thì sẽ có khả năng một lúc nào đó, bạn sẽ code thiếu một trong những hàm cần thiết.
    • Trường hợp thứ 2, trong dự án có hai team Backend, cần phải thi công một chức năng mới có sự hợp tác của 2 team.

      • Trong đó, team 1 sẽ code Data Access Layer, team 2 sẽ code Business Layer.

      • Team 1 sẽ gọi đến các hàm mà team 2 cùng cấp, và nhận kết quả trả về tương ứng.

      • Nếu hai team cùng nhau thảo luận và thống nhất rõ ràng các interface ngay từ ban đầu, phân tích đầy đủ tên hàm, đầu vào, đầu ra cho các hàm trong interface, thì sau đó họ hoàn toàn có thể tách ra để triển khai các Class team mình cần làm thông qua các interface đó.

      • Thay vì phải ngồi chơi xơi nước đợi team 1 làm xong, thì team 2 hoàn toàn có thể viết code fake class, implement các interface sẵn có, để kiểm chứng kết quả của mình. Khi đó, lúc ghép code lại với nhau, tỉ lệ phát sinh bug sẽ hạn chế hơn rất nhiều.

    • Trường hợp thứ 3 thường sử dụng đến interface đó là: Dự án sử dụng một vài database provider khác nhau như MySQL, SQL Server.

      • Rõ ràng là chúng đều cung cấp các thao tác như mở kết nối, đóng kết nối, thêm, sửa, xóa dữ liệu.

      • Nhưng các thư viện hỗ trợ cho từng loại database lại đặt tên hàm, đầu vào, đầu ra khác nhau. Mặc dù các hàm đó có cùng mục đích thực hiện.

      • Một cách thông thường mà các dự án hay sử dụng, đó là tự viết ra interface để khai báo thống nhất các hàm như OpenConnection(), CloseConnection(), ExecuteReader(), ExecuteScalar() chung.

      • Sau đó viết thêm các class tương ứng với từng database provider để implement các interface đó.

      • Từ đó trở đi, dù trong class có sử dụng thư viện hỗ trợ nào đi chăng nữa, thì sau cùng ta sẽ vẫn cần triển khai thân hàm phù hợp với những gì interface chung kia yêu cầu.

      • Việc thao tác với các database provider khác nhau lúc này sẽ vô cùng dễ dàng, vì chỉ cần quan tâm duy nhất đến 1 interface, không cần quan tâm đến việc các class implement interface đó triển khai thân hàm như thế nào.

3. Hàm khởi tạo là gì? Có mấy loại hàm khởi tạo? Nếu trong code mình không code hàm khởi tạo nào hết, thì sẽ xảy ra lỗi gì?

  • Hàm khởi tạo (Constructor) là hàm dùng để khởi tạo các object của một class.

  • Cú pháp khai báo hàm khởi tạo cũng đặc biệt hơn các hàm bình thường khác ở chỗ:

    • Tên của hàm khởi tạo sẽ trùng với tên của class.

    • không có kiểu dữ liệu trả về như void hay int.

    public class Employee
    {
          public string name;

          public Employee()
          {
                name = "Trần Minh Sáng";
          }
    }
  • Hàm khởi tạo chắc chắn sẽ được gọi khi muốn khởi tạo một object (đó cùng là điểm khác nhau giữa Interface và Class. Vì Interface không có hàm khởi tạo, nên nó không thể khởi tạo được object)

  • Có 3 loại hàm khởi tạo:

    • Hàm khởi tạo mặc định (default constructor)

    • Hàm khởi tạo có tham số (parameterized constructor)

    • Hàm khởi tạo không có tham số (no-argument constructor)

  • Nếu trong code mình không code hàm khởi tạo nào hết, thì cũng sẽ không xảy ra lỗi gì hết.

    • Bởi vì, các class khi đó vẫn có sẵn hàm khởi tạo mặc định (mặc dù nhìn bằng mắt thường thì sẽ không nhìn thấy trong code)

    • Chỉ có điều là khi sử dụng hàm khởi tạo mặc định, đồng nghĩa với việc bạn sẽ không thế set initial value cho các field hoặc property trong class mà thôi.

4. Phân biệt overriding và overloading. Lấy ví dụ trong thực tế bạn từng sử dụng, hoặc đã từng nhìn thấy người khác sử dụng như thế nào.

5. Exception là gì? Bạn xử lý exception (handle exception) trong code Backend như thế nào? Có những đặc điểm gì cần lưu ý khi handle exception ở Backend?

  • Exception là những lỗi xảy ra khi thực thi code, mà lý do thường là do lập trình viên không lường trước được rằng lỗi đó có thể xảy ra trong code của mình.

    • Ví dụ: Đối tượng employee bao gồm các thuộc tính ID, Code, Name, Gender.

      • Trong code Backend có một hàm có đoạn xử lý if (employee.Gender == Gender.Male) { ... }

      • Nhưng khi gọi hàm thì lại truyền vào employee = null, khi đó sẽ xảy ra NullReferenceException khi gọi employee.Gender

  • Để handle exception sẽ thường sử dụng try - catch

    • Nếu exception xảy ra trong khối lệnh try , thì nó sẽ được bắt lại (catch) để xử lý (handle) ở khối lệnh catch
  • Một số điểm cần lưu ý khi handle exception:

    • Trong catch tối thiểu phải log lỗi lại, để phục vụ mục đích trace log khi debug.

    • Khi hướng dẫn các bạn Fresher mình thường chia sẻ với các bạn mới học thì có thể tạm thời sử dụng Console.Writeline() cũng được, để ghi nhớ logic . Nhưng trong dự án thực tế mà sau này các bạn làm việc, thì log thường không được ghi vào Console. Lý do là vì như các bạn đã biết Console là cửa sổ màu đen với text màu trắng, nhìn và tìm log lỗi trong đó thì toét mắt, rất mất thời gian.

    • Thay vào đó, các dự án sẽ thường sử dụng những công cụ khác để ghi log, ví dụ như ELK (Elasticsearch - Logstash - Kibana), trong đó:

      • Elasticsearch dùng để lưu trữ log và hỗ trợ tìm kiếm, phân tích nhanh.

      • Logstash dùng để thu thập log và lưu vào Elasticsearch.

      • Kibana dùng để hiển thị trực quan hóa dữ liệu lấy từ Elasticsearch.

        image.png

    • Một vấn đề cần lưu ý nữa khi handle exception, là không nên đẩy nguyên cả đối tượng exception về cho Frontend. Mà nên custom lại để thông báo những thông tin cần thiết thôi. Ví dụ như dự án mình làm thì thường sẽ trả về status code 500 - InternalServerError, kèm theo một đối tượng bao gồm các thuộc tính như sau:

        {
            "errorCode": 1, // Frontend sẽ dựa vào mã lỗi này để hiển thị thông báo thích hợp
            "message": "", // Thông báo ngắn gọn về lỗi đang gặp phải
            "moreInfo": "", // Mô tả chi tiết hơn về lỗi nếu có
            "traceId": "" // Sử dụng để tìm kiếm đến đúng log mình muốn tìm một cách dễ dàng
        }
      

6. Nguyên lý hoạt động của Stack và Queue là gì? Ví dụ công ty mình làm web app về mảng Marketing, theo bạn thì chúng ta có thể áp dụng Stack và Queue vào việc gì trong quá trình xây dựng sản phẩm?

  • Stack (Ngăn xếp):

    • Hoạt động theo nguyên lý Vào Sau Ra Trước - Last In First Out (LIFO)

    • Giống như việc xếp chồng sách lên nhau. Quyển sách nào được xếp lên trên cùng, thì sẽ được lấy ra đầu tiên.

    • Một ví dụ trong thực tế anh em lập trình viên thường sử dụng Stack nhất, dù là bất kỳ web app làm về mảng nào đi nữa, đó là trong quá trình debug. Chúng ta thường sẽ quan sát cửa sổ CallStack để xem các hàm gọi đến nhau như thế nào.

image.png

  • Queue (Hàng đợi):

    • Hoạt động theo nguyên lý Vào Trước Ra Trước - First In First Out (FIFO)

    • Giống như việc xếp hàng đợi mua vé xem phim. Ai xếp hàng trước thì sẽ mua được vé xem phim trước (Không tính ngoại lệ như scandal của Trấn Thành cần sự riêng tư như đợt vừa rồi nha)

    • Một ví dụ trong thực tế có thể áp dụng vào web app mảng Marketing của công ty, đó là chức năng gửi email marketing. Nếu tất cả người dùng thực hiện gửi email hàng loạt trong cùng một thời điểm, có thể gây quá tải dẫn đến tèo luôn con server gửi mail. Khi đó, chúng ta có thể sử dụng Queue để khắc phục tình trạng này. Khi người dùng gửi email, email đó sẽ được đẩy vào Queue, chúng ta có thể kiếm soát được việc muốn gửi bao nhiêu email đi trong một thời điểm bằng cách giới hạn số message lấy ra từ Queue.

image.png

7. Kể tên các thuật toán Sắp xếp (Sort) mà bạn biết. Độ phức tạp về thời gian của các thuật toán đó là gì? Thuật toán nào là nhanh nhất?

  • Các thuật toán sắp xếp và độ phức tạp của chúng:

image.png

  • Đừng cố học vẹt để nhớ độ phức tạp của các thuật toán này. Thực tế bạn chỉ cần hiểu rõ khoảng 5 thuật toán sắp xếp là oke rồi. Tuy nhiên, hãy dành thời gian đọc kỹ giải thuật của chúng, để hiểu tại sao người ta lại ghi độ phức tạp về thời gian của chúng là như vậy.

  • Thuật toán nào là nhanh nhất?

    • Đây là một câu hỏi nổi tiếng mà nếu các bạn nào hay xem youtube hoặc những blog về lập trình đều nói đến.

    • Nhưng trong quá trình phỏng vấn, mình nhận thấy nhiều bạn sinh viên vẫn đơn giản đoán bừa một trong những thuật toán trên, ví dụ chọn Quick Sort là nhanh nhất. Hỏi tại sao thì các bạn chỉ đưa ra câu trả lời chung chung là ***"em nghĩ thế, chứ em cũng không rõ tại sao"***.

    • Đáp cho câu hỏi trên đó là "Không có thuật toán nào là nhanh nhất trong mọi trường hợp cả". Một cách đơn giản là chỉ cần nhìn vào hình ảnh động dưới đây, các bạn sẽ thấy:

      • Trong trường hợp mảng cần sắp xếp có dữ liệu gần như để được sắp xếp theo thứ tự hết rồi (Nearly Sorted), thì Insertion Sort là nhanh hơn cả.

      • Nhưng với những trường hợp dữ liệu phức tạp hơn, thì Insertion Sort lại chậm hơn nhiều so với các thuật toán khác.

animation of sorting algorithms.gif

8. Kể tên các thuật toán Tìm kiếm (Search) mà bạn biết. Độ phức tạp về thời gian của các thuật toán đó là gì?

  • Các thuật toán sắp xếp và độ phức tạp của chúng:

    image.png

  • Tối thiểu anh em cũng nên hiểu rõ 2 thuật toán tìm kiếm cơ bản là Tìm kiếm tuần tự (Linear Search)Tìm kiếm nhị phân (Binary Search)

9. Một số câu hỏi khác

  • Thường là những câu hỏi DỄ HƠN, khi người phỏng vấn thấy bạn đang bối rối hoặc run. Họ sẽ đặt câu hỏi dễ để các bạn dễ dàng trả lời (nếu có kiến thức cơ bản), qua đó giúp các bạn bình tĩnh và tự tin hơn với những câu hỏi khác.

  • Phân biệt ClassObject.

  • Một class có thể vừa kế thừa abstract class, vừa implement interface hay không?

  • Kể tên các mức độ truy cập (access modifier) trong ngôn ngữ lập trình phía Backend mà bạn thường sử dụng. Phạm vi sử dụng của chúng.

  • Đặc điểm của static

Kết bài

Một hội đồng phỏng vấn sẽ thường có: Một HRmột người có chuyên môn lập trình như Dev Lead, SA, PM, Giảng viên nội bộ (nếu công ty đó có chương trình đào tạo bài bản)

HR sẽ hỏi những câu hỏi liên quan đến những vấn đề nằm ngoài chuyên môn như:

  • Giới thiệu bản thân

  • Kinh nghiệm làm việc hoặc kinh nghiệm phỏng vấn trước đó

  • Một số thông tin cơ bản về gia đình, nơi ở hiện nay

  • Mức độ tìm hiểu của bạn về công ty hiện tại

  • ...

Nếu các bạn có hứng thú thì hãy comment ở dưới bài viết này, mình sẽ chia sẻ ở bài viết khác chi tiết hơn về những câu hỏi HR thường hỏi ứng viên, mà trong quá trình ngồi hội động phỏng vấn mình học hỏi được từ bạn HR tham gia cùng mình.

Về kiến thức chuyên môn, sẽ đầy đủ cả Frontend, BackendDatabase. Tất cả các câu hỏi này đều chỉ ở mức cơ bản. Như công ty mình làm thì sẽ tuyển ứng viên vào vị trí Fresher để đào tạo trước khi trở thành Lập trình viên chính thức.

Do đó, các bạn có thể hiểu, đây là những câu hỏi đầu vào cho vị trí Fresher, nên công ty họ cũng KHÔNG ĐÒI HỎI các bạn phải có kiến thức nhiều bằng những Fresher đầu ra sau khi họ đào tạo. Vì nếu như vậy thì các bạn có thể apply vị trí Junior luôn chứ apply Fresher làm gì nữa đúng không nào.

Ngoài ra, các bạn cũng cần lưu ý là mỗi ứng viên sẽ được phỏng vấn trong khoảng thời gian từ 20 đến 30 phút (bao gồm cả thời gian HR hỏi những vấn đề ngoài lề chuyên môn ở trên). Vì vậy, hãy cố gắng rèn luyện kỹ năng trình bày một vấn đề sao cho ngắn gọn, xúc tích, dễ hiểu. Tránh việc trình bày dài dòng văn tự, hay ngồi trầm ngâm suy nghĩ quá lâu. Nếu có chỗ nào chưa hiểu, thì đề xuất cho người phỏng vấn gợi ý. Cũng sẽ có những trường hợp, câu hỏi đó quá dễ, họ sẽ không đồng ý gợi ý cho bạn, thì cũng đừng phiền lòng, thừa nhận mình còn thiếu kiến thức nền tảng không có gì là đáng xấu hổ cả. Cảm ơn người phỏng vấn và sẽ về nhà tìm hiểu theo keyword họ đã đưa ra để nâng cao kiến thức của bản thân. Đó là quá trình của sự trưởng thành diễn ra trong bản thân bạn.

Những câu hỏi được đặt ra thường sẽ có format: What? When? Why?

  • Tức là, họ sẽ hỏi một khái niệm nào đó trước tiên.

  • Sau đó có thể hỏi khi nào thì nên sử dụng hoặc bản thân bạn đã sử dụng chúng trong mini project của mình bao giờ chưa.

  • Và cuối cùng là câu hỏi Tại sao lại sử dụng, hoặc Ưu nhược điểm của việc sử dụng kiến thức này là gì. Đây chính là câu hỏi giúp người phỏng vấn phân loại được ứng viên dễ dàng nhất. Nhiều bạn chỉ dừng lại ở mức biết về thuật ngữ đó có thể thông qua việc học trên trường, thông qua việc đọc tài liệu, xem youtube hoặc các hình thức khác. Rồi sau đó làm theo hướng dẫn của họ nhưng không hiểu hoặc chưa bao giờ đặt câu hỏi tại sao mình lại nên làm như vậy.

Do đó, hãy luôn có trong mình tinh thần ham học hỏi, nhất là thói quen đặt những câu hỏi Tại sao và tìm kiếm câu trả lời cho câu hỏi đó. Biến kiến thức của người khác thành thực sự là của mình.

Và tốt nhất là hãy chia sẻ lại kiến thức đó cho mọi người. Chia sẻ và nhận ý kiến đóng góp, những câu hỏi từ mọi người là cách tốt nhất để bạn thực sự hiểu một vấn đề đó.