Menu
ESC

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

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

Đang tải...

Bài 12 — Code Review Communication

Communication Skills cho Tech Teams Bài 12/60

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

Nếu bạn đã đi làm trong ngành phần mềm được vài tháng, chắc chắn bạn đã từng nhận một comment code review khiến bạn khó chịu. Một dòng ngắn gọn kiểu "Cái này sai rồi", hay "Sao lại viết thế này?", hoặc tệ hơn là một loạt yêu cầu sửa mà không hề giải thích lý do. Ngược lại, có thể chính bạn — với tư cách reviewer — đã từng để lại những comment mà sau này nhìn lại thấy hơi… gay gắt.

Đây là điều ít ai nói thẳng với bạn: code review là một trong những hoạt động giao tiếp căng thẳng nhất trong đời sống của một kỹ sư phần mềm. Bởi vì nó chạm vào cái tôi. Code là sản phẩm trí tuệ, và khi ai đó chỉ ra lỗi trong code của bạn, một phần não bộ sẽ hiểu nhầm rằng họ đang chỉ ra lỗi ở chính con người bạn. Điều tương tự xảy ra ở chiều ngược lại: reviewer nếu không cẩn thận sẽ vô tình biến một cuộc trao đổi kỹ thuật thành một buổi "phán xét".

Trong khóa học này, những bài sau (Bài 13 và Bài 14) sẽ đi sâu vào kỹ thuật đưa feedback và nhận feedback cụ thể trong code review. Còn ở Bài 12 này, chúng ta lùi lại một bước để nắm cái gốc: văn hóa và tư duy giao tiếp khi làm code review. Bạn sẽ hiểu tại sao một pull request (PR) không chỉ là một cơ chế kiểm soát chất lượng, mà là một kênh giao tiếp có băng thông rất hẹp — nơi mọi hiểu lầm dễ nảy sinh — và làm sao để dùng kênh đó một cách hiệu quả, tôn trọng, và giúp cả đội cùng lớn lên.

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

Code review không phải gatekeeping — mà là knowledge sharing và collective ownership

Nhiều người mới đi làm hình dung code review giống như một cái cổng (gate): có một người gác cổng (senior) quyết định code của bạn được "cho qua" hay không. Cách hình dung này tuy không sai hoàn toàn, nhưng nó bóp méo bản chất và tạo ra tâm lý đối đầu.

Hãy đổi góc nhìn. Code review thực chất phục vụ ba mục tiêu song song:

  • Knowledge sharing (chia sẻ tri thức): Reviewer học được cách người khác giải quyết vấn đề, còn author học được các góc nhìn, pattern, hoặc rủi ro mà mình chưa thấy. Một PR tốt là nơi cả hai bên đều rời đi thông minh hơn lúc bắt đầu.
  • Collective ownership (sở hữu tập thể): Khi bạn approve một PR, bạn đang cùng chịu trách nhiệm về đoạn code đó. Nó không còn là "code của bạn ấy" mà là "code của đội". Điều này thay đổi hoàn toàn cách bạn comment — bạn đang cùng nhau làm cho một tài sản chung tốt hơn.
  • Chất lượng và tính nhất quán: Đây mới là phần "gatekeeping" mà mọi người hay nghĩ tới. Nhưng nó chỉ là một trong ba mục tiêu, không phải toàn bộ.
Khi bạn giữ đủ cả ba mục tiêu trong đầu, giọng văn khi review của bạn sẽ tự nhiên mềm mại và xây dựng hơn.

Băng thông hẹp của văn bản viết

Code review gần như luôn diễn ra qua văn bản viết (comment trong GitHub, GitLab, Bitbucket…). Văn bản viết thiếu ngữ điệu, ánh mắt, biểu cảm khuôn mặt — những thứ chiếm phần lớn ý nghĩa trong giao tiếp trực tiếp. Một câu bạn nghĩ là "trung tính" khi gõ ra, người đọc có thể cảm nhận là "lạnh lùng" hoặc "trịch thượng".

Nguyên tắc vàng: khi giao tiếp qua văn bản, hãy giả định người đọc đang có một ngày tồi tệ. Nghĩa là hãy viết dư một chút sự tử tế, dư một chút ngữ cảnh, dư một chút "vì sao". Sự dư thừa đó chính là thứ bù đắp cho băng thông đã mất.

Phân loại comment: bắt buộc, đề xuất, hay chỉ là suy nghĩ

Một trong những nguồn xung đột lớn nhất là author không biết comment nào phải sửa và comment nào tùy họ. Các đội trưởng thành giải quyết việc này bằng cách gắn nhãn (label) rõ ràng cho từng comment. Một quy ước phổ biến gọi là "conventional comments":

  • blocking: / must: — Vấn đề nghiêm trọng, phải sửa trước khi merge (ví dụ: lỗ hổng bảo mật, bug logic).
  • suggestion: — Đề xuất cải thiện, author cân nhắc nhưng có quyền từ chối.
  • nit: (viết tắt của nitpick — bắt bẻ vặt) — Góp ý nhỏ về style, đặt tên biến… hoàn toàn không bắt buộc.
  • question: — Bạn chỉ đang muốn hiểu, chưa chắc có vấn đề gì.
  • praise: — Khen ngợi phần làm tốt (đừng bỏ qua nhóm này!).
Chỉ cần thêm một tiền tố như nit: vào đầu comment, bạn đã hạ nhiệt cả cuộc trao đổi, vì author hiểu ngay đây không phải chuyện lớn.

Nguyên tắc "phê bình code, không phê bình người"

So sánh hai cách viết cùng một ý:

  • ❌ "Bạn không hiểu cách async hoạt động."
  • ✅ "Đoạn này có vẻ chưa await promise, nên kết quả có thể trả về trước khi query xong. Mình hiểu đúng không?"
Câu thứ hai nói về đoạn codehành vi của nó, để ngỏ khả năng chính reviewer hiểu sai. Nó mời gọi đối thoại thay vì kết tội. Đây là kỹ năng nền tảng mà mọi comment tốt đều dựa vào.

Tình huống thực tế

Ví dụ 1 — Comment "cụt lủn" làm rạn nứt một đội ở Đà Nẵng

Một công ty outsourcing khoảng 40 kỹ sư ở Đà Nẵng có một senior tên Hùng, giỏi kỹ thuật nhưng review PR rất "tiết kiệm chữ". Comment điển hình của anh: "Refactor lại", "Không ổn", "Xem lại pattern". Với anh, đây là cách làm việc hiệu quả, tiết kiệm thời gian.

Vấn đề là hai bạn junior trong nhóm bắt đầu sợ mở PR. Mỗi lần bị Hùng review, các bạn phải nhắn riêng qua Slack hỏi "Anh ơi, ý anh là sao ạ?", tạo ra vòng lặp qua lại kéo dài. Có PR mất 3 ngày mới merge được chỉ vì các vòng hỏi-đáp ngoài lề. Tệ hơn, một bạn junior thú nhận trong buổi 1-on-1 rằng bạn ấy đã bắt đầu tránh nhận task khó vì "review của anh Hùng làm em thấy mình bất tài".

Team lead can thiệp bằng một thỏa thuận đơn giản: mỗi comment yêu cầu thay đổi phải trả lời được câu hỏi "vì sao" và "gợi ý hướng đi". Hùng đổi "Refactor lại" thành "Hàm này đang làm 3 việc (validate, tính toán, gọi API). Nếu tách thành 3 hàm nhỏ thì sẽ dễ test hơn. Em thử xem sao nhé." Cùng một yêu cầu kỹ thuật, nhưng thời gian merge trung bình của nhóm giảm từ 2,5 ngày xuống còn dưới 1 ngày trong vòng một tháng.

Bài học: Sự ngắn gọn của reviewer thường bị đẩy chi phí sang author dưới dạng hoang mang và vòng lặp hỏi-đáp. Thêm 15 giây viết "vì sao" tiết kiệm hàng giờ cho cả đội.

Ví dụ 2 — PR "review chiến tranh" 87 comment và một cuộc gọi 10 phút

Tại một startup fintech ở TP.HCM, có một PR nổi tiếng nội bộ vì nó tích tụ tới 87 comment qua lại giữa hai kỹ sư về cách đặt tên và cấu trúc một module. Hai người bắt đầu trả lời nhau ngày càng ngắn và gay gắt, mỗi bên bảo vệ quan điểm của mình. Cả team nín thở theo dõi trên GitHub như xem một trận đấu.

CTO nhìn thấy, và thay vì nhảy vào comment thứ 88, anh gõ một dòng: "Hai bạn nhảy vào call 10 phút nhé, mình join cùng." Trong cuộc gọi, hóa ra hai người đồng ý với nhau tới 90% — họ chỉ đang tranh cãi về một chi tiết mà qua văn bản trông như bất đồng lớn. Cuộc gọi kết thúc trong 8 phút, họ chốt hướng đi, và một người tóm tắt kết luận vào một comment cuối cùng trên PR để lưu lại lịch sử.

Bài học: Khi một luồng comment vượt quá 2–3 vòng qua lại mà chưa hội tụ, đó là tín hiệu rõ ràng rằng văn bản viết đã hết tác dụng. Chuyển sang kênh đồng bộ (call/họp nhanh) và luôn quay lại ghi tóm tắt kết luận vào PR để giữ lịch sử cho người sau.

Ví dụ 3 — Văn hóa "praise" ở một đội remote

Một đội kỹ sư người Việt làm remote cho một công ty ở Singapore có một thói quen nhỏ nhưng mạnh mẽ: quy ước rằng mỗi PR review phải có ít nhất một comment praise: nếu có điểm đáng khen. Ban đầu nghe hơi gượng, nhưng theo thời gian nó đổi hẳn không khí.

Khi một junior viết một unit test bao được cả edge case mà senior chưa nghĩ ra, reviewer để lại: "praise: Cái test case cho trường hợp input rỗng này hay lắm, mình quên mất tình huống đó. Cảm ơn nhé." Junior kể lại rằng comment đó khiến bạn tự tin hẳn và bắt đầu chủ động viết test kỹ hơn. Dữ liệu nội bộ của đội cho thấy tỉ lệ PR bị bỏ dở (author mở rồi không đụng tới nữa vì nản) giảm rõ rệt sau khi đưa praise thành thói quen.

Bài học: Code review không chỉ để bắt lỗi. Ghi nhận điểm tốt vừa củng cố hành vi đúng, vừa giữ cho author sẵn sàng đón nhận cả những feedback khó nghe hơn.

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

Dưới đây là quy trình giao tiếp cho reviewer khi tiếp cận một PR:

  • Đọc mô tả PR trước khi đọc code. Hiểu author đang cố giải quyết vấn đề gì. Nếu mô tả sơ sài, comment đầu tiên nên là một câu hỏi lịch sự nhờ bổ sung ngữ cảnh, chứ đừng vội phán xét từng dòng.
  • Đọc lướt toàn bộ một lượt trước khi comment. Có thể vấn đề bạn định nêu ở file A đã được xử lý ở file B. Comment vội khiến bạn trông thiếu cẩn thận và làm author mất thời gian.
  • Phân loại và gắn nhãn mỗi comment. Dùng tiền tố blocking, suggestion, nit, question, praise. Việc này giúp author biết ngay cái gì phải làm, cái gì tùy chọn.
  • Viết theo công thức: quan sát + tác động + gợi ý. "Đoạn này [quan sát]. Điều đó có thể dẫn tới [tác động]. Bạn thử cân nhắc [gợi ý] xem sao?" Công thức này biến mệnh lệnh thành đối thoại.
  • Đặt câu hỏi thay vì ra lệnh khi chưa chắc chắn. "Có lý do gì đặc biệt để dùng vòng lặp ở đây thay vì map không?" tôn trọng hơn nhiều so với "Dùng map đi."
  • Biết khi nào dừng văn bản. Nếu quá 2–3 vòng comment mà chưa hội tụ, chủ động đề xuất một cuộc gọi ngắn, rồi ghi tóm tắt kết luận lại vào PR.
Và đây là quy trình cho author:

  • Viết mô tả PR rõ ràng ngay từ đầu — vấn đề, cách giải quyết, những điểm bạn muốn reviewer để ý kỹ. Bạn càng cho ngữ cảnh, comment nhận được càng chất lượng.
  • Chia PR nhỏ. Một PR 2000 dòng gần như không thể review tử tế; reviewer sẽ chỉ approve cho xong. PR dưới 400 dòng nhận được feedback sâu hơn nhiều.
  • Coi mọi comment là ý tốt (assume good intent). Đọc comment "Sao lại làm thế này?" theo nghĩa tò mò, không phải công kích.
  • Phản hồi mọi comment, kể cả khi bạn không đồng ý — giải thích lý do, hoặc đánh dấu resolved. Im lặng khiến reviewer không biết bạn đã tiếp thu hay chưa.

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

  • Lỗi: Comment bằng mệnh lệnh cụt lủn. "Sửa lại đi" không cho author biết sửa cái gì và vì sao. Mẹo: luôn kèm lý do và, nếu được, một gợi ý cụ thể.
  • Lỗi: Trộn lẫn nit với vấn đề nghiêm trọng. Khi 15 comment về khoảng trắng nằm chung với 1 comment về lỗ hổng bảo mật, author dễ bỏ sót cái quan trọng. Mẹo: gắn nhãn rõ ràng, và cân nhắc bỏ qua các nit vặt nếu team đã có linter/formatter tự động lo.
  • Lỗi: Review kiểu "áp đặt phong cách cá nhân". Bắt author viết theo đúng cách bạn sẽ viết, dù cách của họ cũng đúng. Mẹo: phân biệt "khác" và "sai". Nếu chỉ là khác, đó cùng lắm là một suggestion, không phải blocking.
  • Lỗi: Reviewer im lặng quá lâu. PR nằm chờ 3 ngày làm author nản và block cả team. Mẹo: nếu bận, hãy nhắn một dòng "Mình sẽ review chiều nay nhé" để author biết bạn không bỏ quên.
  • Lỗi: Author phản pháo phòng thủ. Trả lời "Mình làm thế là có lý do" bằng giọng cáu kỉnh khiến reviewer ngại góp ý lần sau. Mẹo: tách cái tôi ra khỏi code; cảm ơn reviewer đã bỏ thời gian đọc.
  • Mẹo tổng quát: Trước khi bấm "Submit review", đọc lại comment của mình và tự hỏi: "Nếu nhận comment này lúc 6 giờ chiều sau một ngày mệt mỏi, mình sẽ thấy thế nào?" Nếu thấy nhói, hãy viết lại.

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

  • Viết lại comment gay gắt. Lấy ba comment dưới đây và viết lại theo công thức "quan sát + tác động + gợi ý", có gắn nhãn phù hợp:
- "Code này chậm." - "Sao không dùng cache?" - "Tên biến khó hiểu quá."

  • Tự audit 5 comment gần nhất của bạn. Mở GitHub/GitLab, tìm 5 comment review gần nhất bạn từng viết. Đánh giá mỗi comment: có "vì sao" không? Có gắn nhãn không? Có mang giọng mệnh lệnh không? Ghi lại điều bạn muốn cải thiện.
  • Thử quy ước praise trong một tuần. Trong tuần tới, mỗi lần review một PR, cố tình để lại ít nhất một comment praise: chân thành. Cuối tuần, tự quan sát xem không khí tương tác với đồng đội có khác đi không.
  • Nhận diện điểm dừng. Nhìn lại một luồng comment dài mà bạn từng tham gia. Nó nên chuyển sang call ở vòng thứ mấy? Nếu được làm lại, bạn sẽ viết câu đề nghị chuyển kênh như thế nào?

Tóm tắt

Code review là một kênh giao tiếp có băng thông hẹp, chạm trực tiếp vào cái tôi của cả author lẫn reviewer. Nếu coi nó là cổng gác để "cho qua" hay "chặn lại", bạn sẽ vô tình tạo ra văn hóa đối đầu. Nếu coi nó là nơi chia sẻ tri thức và cùng sở hữu chất lượng chung, bạn sẽ tự nhiên viết những comment tử tế và xây dựng hơn.

Ba điều cần nhớ: phê bình code chứ không phê bình người — nói về hành vi của đoạn code, để ngỏ khả năng chính mình hiểu sai. Gắn nhãn mỗi comment (blocking, suggestion, nit, question, praise) để author biết cái gì phải sửa, cái gì tùy chọn. Và biết khi nào rời văn bản — khi tranh luận vượt 2–3 vòng chưa hội tụ, chuyển sang call rồi quay lại ghi tóm tắt.

Kỹ năng đưa và nhận feedback cụ thể trong code review sẽ được đào sâu ở Bài 13 và Bài 14. Nhưng nếu bạn nắm vững tư duy nền tảng ở bài này — rằng mỗi PR là một cơ hội để cả đội cùng lớn lên — thì mọi kỹ thuật phía sau sẽ trở nên tự nhiên.