Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Code Reviews và Engineering Culture

Technical Leadership Bài 3/60

Mở đầu — vì sao bài này quan trọng

Nếu bạn hỏi mười kỹ sư rằng họ ghét công việc gì nhất trong một ngày làm việc, một tỷ lệ đáng ngạc nhiên sẽ trả lời: "chờ review code" và "bị review code". Chờ đợi vì pull request (PR — yêu cầu gộp code) nằm mốc meo hai ba ngày không ai đụng tới. Còn bị review thì đôi khi giống như bị mổ xẻ trước đám đông: những bình luận cộc lốc, những cuộc tranh cãi về dấu cách và dấu tab, những "nit" (điều nhỏ nhặt) khiến người ta thấy công sức của mình bị coi thường.

Nhưng đây mới là nghịch lý: code review là một trong những công cụ mạnh nhất mà một Tech Lead có trong tay để định hình văn hóa kỹ thuật (engineering culture) của đội. Nó không chỉ là hàng rào chặn bug. Nó là nơi tri thức được truyền tay, nơi tiêu chuẩn được thiết lập, nơi các kỹ sư junior học nghề, và quan trọng nhất — nó là tấm gương phản chiếu chính xác nhất về việc đội của bạn đối xử với nhau như thế nào.

Trong bài này chúng ta tập trung riêng vào mục đích, cơ chế và cách một Tech Lead dùng code review để xây văn hóa kỹ thuật. Chúng ta sẽ nói về tại sao review tồn tại, thế nào là một review tốt, và làm sao để biến quá trình này từ một nghĩa vụ đáng ghét thành một điểm mạnh của đội. Những chủ đề chuyên sâu hơn — như xây dựng văn hóa review từ con số không, tự động hóa bằng linter và CI, hay pair/mob programming — sẽ được đào sâu ở các bài sau (Bài 13, 14, 15). Ở đây, ta đặt nền móng.

Khái niệm cốt lõi

Bốn mục đích thật sự của code review

Rất nhiều đội làm code review mà không bao giờ ngồi xuống hỏi: chúng ta làm việc này để làm gì? Khi không rõ mục đích, review trượt về thành nghi thức hình thức — bấm "Approve" cho xong. Một Tech Lead cần khắc sâu bốn mục đích này vào đầu cả đội.

1. Bắt lỗi trước khi lên production. Đây là mục đích hiển nhiên nhất nhưng thực ra không phải mục đích quan trọng nhất. Một cặp mắt thứ hai phát hiện được lỗi logic, edge case (trường hợp biên) bị bỏ sót, lỗ hổng bảo mật, hay giả định sai. Nhưng cần thành thật: review không bắt được mọi bug, và không nên kỳ vọng nó thay thế test tự động.

2. Lan tỏa tri thức trong đội (knowledge sharing). Đây mới là giá trị bị đánh giá thấp nhất. Khi B review code của A, B học được một phần hệ thống mà B chưa từng chạm vào. Nếu ngày mai A nghỉ phép hoặc nghỉ việc, B không bị đứng hình. Review chống lại "bus factor" — rủi ro khi tri thức chỉ nằm trong đầu một người.

3. Duy trì tiêu chuẩn chất lượng code. Review là nơi các quy ước chung được thực thi: cách đặt tên, cấu trúc thư mục, mẫu thiết kế (design pattern) mà đội thống nhất. Không có review, mỗi người viết một kiểu, và sau hai năm codebase trở thành một mớ hỗn độn không ai đọc nổi.

4. Cơ hội mentoring (kèm cặp). Với kỹ sư junior, mỗi PR là một buổi học nhỏ. Một reviewer giỏi không chỉ nói "sai rồi" mà giải thích "tại sao nên làm thế này, đánh đổi ở đây là gì". Đây là kênh phát triển con người rẻ nhất và hiệu quả nhất mà đội có.

Thế nào là một review tốt — từ phía reviewer

Một review tốt bắt đầu bằng thái độ đúng: bạn đang review code, không phải review con người. Câu chữ tưởng nhỏ nhưng tạo khác biệt lớn. "Hàm này nên tách ra để dễ test hơn" khác hẳn với "sao anh viết hàm dài thế này".

Một reviewer tốt phân biệt rõ ba tầng góp ý:

  • Blocking (chặn merge): lỗi thật sự, vấn đề bảo mật, thiết kế sai hướng. Bắt buộc sửa.
  • Suggestion (đề xuất): có thể tốt hơn nhưng không bắt buộc. Nêu rõ đây là ý kiến.
  • Nit (điều nhỏ nhặt): sở thích cá nhân, format lặt vặt. Gắn nhãn "nit:" để tác giả biết có quyền bỏ qua.
Google nội bộ có một nguyên tắc nổi tiếng: reviewer nên approve khi code làm codebase tốt lên rõ ràng, chứ không phải khi nó hoàn hảo. Đây là điểm cực kỳ quan trọng để chống lại thói cầu toàn làm nghẽn dòng chảy công việc.

Thế nào là một PR tốt — từ phía tác giả

Trách nhiệm không chỉ nằm ở reviewer. Tác giả cũng có nghĩa vụ làm cho việc review dễ dàng.

  • PR nhỏ. Nghiên cứu nội bộ của nhiều công ty cho thấy chất lượng review sụt mạnh khi PR vượt quá khoảng 200–400 dòng thay đổi. PR 2000 dòng thì reviewer chỉ đọc lướt rồi bấm Approve — vô nghĩa.
  • Mô tả rõ ràng. PR cần trả lời: thay đổi cái gì, tại sao, và review nên chú ý vào đâu.
  • Tự review trước. Trước khi gửi, tác giả đọc lại diff của chính mình. Bạn sẽ ngạc nhiên bao nhiêu lỗi ngớ ngẩn được bắt ngay ở bước này.

Tình huống thực tế

Tình huống 1: Startup fintech Việt Nam và cái "cổ chai" mang tên Tech Lead

Một startup fintech ở TP.HCM (gọi là công ty M) có đội 8 kỹ sư. Anh Tech Lead — hãy gọi là anh Đức — là người giỏi nhất và cẩn thận nhất. Anh yêu cầu mọi PR đều phải qua tay anh trước khi merge. Nghe có vẻ đảm bảo chất lượng, nhưng vấn đề bắt đầu lộ ra sau ba tháng.

Anh Đức bận họp, bận thiết kế hệ thống, nên PR thường nằm chờ 2–3 ngày. Có tuần đội có 20 PR dồn ứ. Các bạn junior không dám ping sếp, ngồi chờ trong bực bội. Velocity (tốc độ giao việc) của đội giảm khoảng 30% so với quý trước dù headcount không đổi. Tệ hơn, vì mọi review đều do một người, không ai khác trong đội hiểu sâu các phần hệ thống ngoài phần mình làm — bus factor bằng 1 ở nhiều module.

Anh Đức thay đổi cách làm: quy định mỗi PR cần ít nhất một approve từ bất kỳ kỹ sư nào trong đội (trừ những thay đổi vào module thanh toán nhạy cảm thì vẫn cần anh). Anh dành hai buổi để hướng dẫn cả đội cách review. Sau một tháng, thời gian PR chờ review trung bình giảm từ ~40 giờ xuống còn ~6 giờ. Và điều bất ngờ: các bạn junior tiến bộ nhanh hơn hẳn vì phải review lẫn nhau buộc họ đọc code người khác mỗi ngày.

Bài học: Tech Lead ôm hết review là chống chỉ định. Vai trò của Lead không phải làm reviewer duy nhất, mà là dạy cả đội review giỏi và chỉ giữ lại quyền gác cổng ở những vùng thật sự rủi ro cao.

Tình huống 2: Cuộc chiến dấu phẩy và cái giá của "nit war"

Một công ty product ở Hà Nội (công ty T, đội khoảng 15 người) có một reviewer nổi tiếng khắt khe. Mỗi PR gửi lên anh này để lại 30–40 bình luận, phần lớn là: khoảng trắng thừa, thứ tự import, tên biến nên là userId hay userID, nên xuống dòng chỗ này. Không sai, nhưng...

Kết quả là một bạn kỹ sư mới vào được ba tuần xin nghỉ. Trong buổi phỏng vấn nghỉ việc (exit interview), bạn nói thẳng: "Mỗi lần gửi PR em thấy như bị đem ra chỉ trích. Em sợ commit code." Đó là hồi chuông cảnh báo cho Tech Lead.

Vấn đề gốc: những "nit" về format hoàn toàn có thể để máy lo. Đội chưa cài công cụ format tự động (như Prettier, gofmt, hay linter), nên con người phải làm việc của máy — và làm với thái độ khiến người khác tổn thương. Tech Lead quyết định: cài formatter chạy tự động khi commit, thống nhất một style guide duy nhất, và ra quy tắc văn hóa: "Nếu máy làm được thì con người không tranh cãi." Reviewer chỉ tập trung vào logic, thiết kế và tính đúng đắn.

Bài học: Tranh cãi về format là dấu hiệu của một quy trình chưa trưởng thành, không phải của sự cẩn thận. Nó đốt cạn thiện chí (goodwill) trong đội và làm reviewer trông như đang bới lông tìm vết. (Cách tự động hóa cụ thể sẽ đào sâu ở Bài 14.)

Tình huống 3: Review như một buổi học — cách Shopee/Grin-đông-nam-á làm mentoring

Ở một đội thuộc một công ty công nghệ lớn Đông Nam Á (bối cảnh tương tự Shopee, Grab), có một thực hành đáng học: với mỗi kỹ sư junior mới, senior được phân công review sẽ không chỉ để lại bình luận trên GitHub mà, với những PR quan trọng, sẽ ngồi cùng bạn junior 15 phút để đi qua review trực tiếp. Senior giải thích "tại sao", hỏi bạn junior nghĩ gì về các phương án khác.

Một chỉ số nội bộ họ theo dõi là thời gian từ lúc một kỹ sư mới vào đến lúc PR đầu tiên của họ được merge mà không cần chỉnh sửa lớn. Nhờ cách review-như-mentoring này, con số đó rút ngắn đáng kể — kỹ sư mới "bắt nhịp" nhanh hơn vì họ hiểu lý do đằng sau tiêu chuẩn, chứ không chỉ học vẹt.

Bài học: Review async trên PR là tốt, nhưng với những khoảnh khắc dạy dỗ quan trọng, một cuộc trò chuyện trực tiếp ngắn có giá trị gấp nhiều lần. Reviewer giỏi biết khi nào nên chuyển từ text sang nói chuyện.

Hướng dẫn từng bước

Dưới đây là cách một Tech Lead thiết lập và duy trì code review lành mạnh cho đội.

Bước 1 — Thống nhất mục đích với cả đội. Dành 30 phút họp để cả đội đồng ý: review để làm gì (bốn mục đích ở trên), và cái gì không nằm trong phạm vi review (ví dụ: format do máy lo).

Bước 2 — Đặt kỳ vọng về thời gian phản hồi. Ra một cam kết rõ ràng, ví dụ: "Mọi PR được phản hồi trong vòng nửa ngày làm việc." Review nhanh là biểu hiện của sự tôn trọng — để PR nằm chờ là gián tiếp nói với đồng nghiệp rằng công việc của họ không quan trọng.

Bước 3 — Chuẩn hóa PR nhỏ. Khuyến khích tách PR lớn thành nhiều PR nhỏ. Đặt mốc mềm (soft limit) như "cố gắng dưới 400 dòng". PR nhỏ được review kỹ hơn, merge nhanh hơn, và ít gây xung đột merge.

Bước 4 — Xây quy ước ngôn ngữ review. Thống nhất tiền tố (prefix) cho bình luận: nit:, suggestion:, question:, blocking:. Điều này giúp tác giả biết ngay mức độ nghiêm trọng và giảm căng thẳng.

Bước 5 — Làm gương. Tech Lead phải là người review mẫu mực: tử tế, cụ thể, giải thích lý do, khen khi code tốt. Đội sẽ bắt chước cách Lead review nhiều hơn là bất kỳ tài liệu nào bạn viết.

Bước 6 — Đưa reviewer vào vòng phân công công bằng. Đừng để một hai người gánh hết review. Luân phiên để mọi người vừa review vừa được review — đó là cách tri thức lan tỏa.

Bước 7 — Định kỳ nhìn lại. Trong retro (họp nhìn lại), hỏi: review đang nhanh hay chậm? Có ai thấy bị tổn thương không? Có "nit war" nào không? Điều chỉnh liên tục.

Lỗi thường gặp & mẹo

Lỗi 1 — Rubber-stamping (đóng dấu cho qua). Bấm Approve mà không đọc kỹ. Đây là loại review tệ nhất vì nó tạo cảm giác an toàn giả. Mẹo: nếu không có thời gian review tử tế, hãy nói thẳng "tôi chưa review được kỹ" thay vì approve bừa.

Lỗi 2 — Review quá to. PR khổng lồ khiến reviewer chỉ đọc lướt. Mẹo: nếu nhận PR quá lớn, có thể lịch sự yêu cầu tác giả tách nhỏ.

Lỗi 3 — Chỉ chê, không khen. Review chỉ toàn điểm trừ sẽ làm người ta nản. Mẹo: khi thấy đoạn code hay, hãy để lại một bình luận tích cực. "Cách xử lý edge case này gọn ghê" — một câu đó nuôi dưỡng động lực rất nhiều.

Lỗi 4 — Áp đặt sở thích cá nhân như luật. Reviewer nhầm "tôi thích thế này hơn" với "cách này đúng". Mẹo: hỏi bản thân — đây là vấn đề tính đúng đắn, hay chỉ là khẩu vị? Nếu là khẩu vị, hãy gắn nhãn "nit" và để tác giả tự quyết.

Lỗi 5 — Tranh cãi vô tận trên bình luận. Qua lại 3 vòng comment mà chưa xong nghĩa là nên nhấc điện thoại hoặc gọi video. Mẹo: quy tắc "hai lần qua lại thì chuyển sang nói chuyện".

Lỗi 6 — Không phân biệt blocking và không blocking. Tác giả không biết cái nào bắt buộc sửa. Mẹo: dùng nhãn rõ ràng, và cuối review tóm tắt "những gì cần sửa trước khi merge".

Bài tập thực hành

  • Tự đánh giá đội hiện tại. Viết ra thời gian trung bình một PR trong đội bạn phải chờ được review. Nếu con số vượt một ngày làm việc, hãy xác định nguyên nhân: thiếu người review, PR quá to, hay không có kỳ vọng rõ ràng?
  • Viết lại một bình luận độc hại. Lấy (hoặc tưởng tượng) một bình luận review kiểu chỉ trích con người, ví dụ "code này rối quá viết lại đi". Viết lại thành một bình luận mang tính xây dựng, cụ thể, có giải thích lý do và có phân loại mức độ.
  • Thiết lập quy ước cho đội. Soạn một bản ngắn nửa trang gồm: bốn mục đích review, ba mức độ bình luận (nit/suggestion/blocking), mốc thời gian phản hồi kỳ vọng, và giới hạn kích thước PR mềm. Chia sẻ với đội để lấy phản hồi.
  • Thực hành review có chủ đích. Trong tuần tới, khi review PR tiếp theo, ép mình để lại ít nhất một bình luận tích cực và ít nhất một bình luận giải thích "tại sao" chứ không chỉ "cái gì".

Tóm tắt

Code review không phải là hàng rào kiểm tra chất lượng đơn thuần — nó là một trong những đòn bẩy văn hóa mạnh nhất của một Tech Lead. Bốn mục đích cốt lõi: bắt lỗi, lan tỏa tri thức, giữ tiêu chuẩn, và mentoring — trong đó ba mục đích sau thường bị đánh giá thấp nhưng lại tạo giá trị dài hạn lớn nhất.

Một văn hóa review lành mạnh có ba đặc điểm: nhanh (không để PR chờ mòn mỏi), tử tế (review code chứ không review người, có khen có chê, có giải thích lý do), và tập trung đúng chỗ (để máy lo format, con người lo logic và thiết kế). Tech Lead định hình văn hóa này không phải bằng cách ôm hết review về mình, mà bằng cách dạy cả đội review giỏi và làm gương mỗi ngày.

Ba tình huống ta xem qua — cái cổ chai mang tên Tech Lead, cuộc chiến dấu phẩy làm mất người, và review-như-mentoring — đều dẫn về một sự thật: cách đội bạn review code chính là cách đội bạn đối xử với nhau. Xây tốt điểm này, bạn xây được nền móng cho toàn bộ văn hóa kỹ thuật.