Hãy tưởng tượng bạn đang ở trong một nhóm gồm năm người. Bạn đang làm việc trên một ứng dụng monolithic tương đối đơn giản. Thật không may, mọi người đều push code của mình vào nhánh main mỗi khi họ hoàn thành một tính năng được giao (hoặc tệ hơn, bất cứ khi nào họ muốn). Mọi người liên tục ghi đè code của nhau, tạo ra các quy ước đặt tên khác nhau, ghi đè và có thể còn nhân đôi code, và còn tệ hơn nữa. Mọi thứ giống như miền Viễn Tây hoang dã, và đó chính là cảm giác khi không có quy trình code review.
Nếu bạn từng làm việc trong một nhóm không có quy trình code review (hoặc không có các bước kiểm tra chất lượng trong pipeline CI/CD), bạn có lẽ đã trực tiếp trải qua những pain point này. Rất nhiều thời gian bị lãng phí để sửa những thứ lẽ ra không nên được deploy lên production ngay từ đầu. Việc quay lại một phiên bản tốt và hoạt động ổn định của ứng dụng gần như là bất khả thi. Và khi những bug ngẫu nhiên xuất hiện từ legacy code? Bạn tự động nhân số story point ước lượng để sửa chúng vì code khá khó hiểu—và dĩ nhiên, developer đã viết nó thì không còn ở đây nữa.
Những hệ quả này càng nghiêm trọng khi bạn có các ứng dụng phức tạp hơn, đội ngũ lớn hơn, các đội phân tán, hoặc cả ba! Hãy tưởng tượng làm việc trên một ứng dụng gồm 25 microservices. Đội của bạn có 10 kỹ sư chịu trách nhiệm cho năm microservices, và đội này lại phân bố khắp toàn cầu. Lấy những triệu chứng trong ví dụ trước và áp dụng vào đây, bạn sẽ có những sai lầm cực kỳ tốn kém.
Pain point này—hoàn toàn không có quy trình code review—thậm chí có thể chính là lý do bạn tìm đến bài viết này! May mắn thay, bạn có thể đã áp dụng những gì học được từ hướng dẫn https://minhphien.com/guidelines-cho-code-review/ để giúp khắc phục vấn đề đó. Tuy nhiên, đáng tiếc là vẫn còn những câu đố khó (conundrums) khác liên quan đến code review có thể xuất hiện ngay cả khi bạn đã có quy trình. Đó là những gì tôi sẽ chia sẻ trong chương này.
Các pain point của code review
Code review có thể tuyệt vời nếu chúng ta giữ chúng nhất quán, dễ bảo trì và hiệu quả. Tuy nhiên, có nhiều cách khiến code review biến dạng thành một quy trình mà chúng ta không thích hoặc không muốn.
Thông thường, điều cản trở (hoặc dần dần làm suy yếu) một quy trình code review tốt là:
- Thiếu giao tiếp và niềm tin giữa các thành viên trong nhóm
- Thiếu hướng dẫn rõ ràng về code review
Cả hai điều này biểu hiện thành những pain point quen thuộc khiến code review trở nên tệ đến mức mọi người thà không có code review còn hơn. Ở đây, chúng ta sẽ chủ động khám phá những kiểu code review mà chúng ta không muốn có.
Lazy code review
Một kiểu code review gây bực bội lớn cho developer là lazy code review. Có thể quy trình vẫn tồn tại, nhưng vì một lý do nào đó, việc review trở nên:
- hời hợt
- làm vội vàng
- hoặc làm sai cách
Kiểu code review này xuất hiện dưới nhiều hình thức.
Hội chứng “Looks good to me”
Bạn vừa nhận được email thông báo: một PR mới do đồng nghiệp gửi đang chờ bạn review. Bạn có chút thời gian nên quyết định xem qua.
Khi mở pull request (PR), bạn thấy:
- 32 file thay đổi
- 1.078 dòng bị xóa
- 1.345 dòng được thêm
Và đó là tất cả những gì bạn nhớ—phần còn lại trở nên khá mơ hồ.
Bạn luôn tự hào vì mình review cẩn thận và đầy đủ, nhưng lần này thì khác. Bạn cảm thấy hơi khó chịu, nhưng cuối cùng vẫn để lại comment khét tiếng:
“LGTM” (Looks good to me)
và approve PR.
Dù sao thì, không ai thực sự review từng đó file, đúng không?
“Không sao, đây là tình huống khẩn cấp!”
3 giờ sáng, bạn là developer trực on-call và vừa bị gọi dậy.
Một vấn đề nghiêm trọng xảy ra trên production: một spike bất thường xuất hiện tại một region ở châu Âu khiến cache tăng vượt quá ngưỡng.
Bạn có các cơ chế tự động lẽ ra phải ngăn điều này, nhưng giờ thì chuyện đã xảy ra.
Mặc dù có quy trình code review rõ ràng, một đám cháy production như vậy dường như cần hotfix.
Sau khi nhanh chóng tìm ra giải pháp, bạn tích hợp hotfix trực tiếp vào production, bỏ qua quy trình review.
Điều này hoạt động và hoàn toàn hợp lý trong tình huống đó. Nhưng một tiền lệ không lành mạnh đã được thiết lập:
Nếu đủ khẩn cấp, quy trình có thể bị bỏ qua.
Từ đây trở đi, các workaround nguy hiểm bắt đầu trở thành chuẩn mực thay vì ngoại lệ.
Hệ thống “bạn thân” thiên vị
Sau một buổi chiều tập trung hiếm hoi, cuối cùng bạn cũng hoàn thành feature được giao trong sprint. Tự hào và nhẹ nhõm, bạn mở PR và cẩn thận viết context cho reviewer.
Ngày hôm sau bạn kiểm tra trạng thái PR.
PR của bạn vẫn mở.
Trong khi đó PR của các đồng nghiệp khác đều đã được approve.
Bạn bắt đầu thấy khó chịu.
Khi xem kỹ hơn, bạn phát hiện ra hai thành viên thân nhau trong nhóm chỉ approve PR của nhau, chỉ vài phút sau khi PR được mở.
Và họ đã làm vậy trong một thời gian dài.
Dù không phải lỗi trực tiếp của code review, hành vi này vẫn ảnh hưởng đến cách cả team nhìn nhận quy trình. Khi code review làm lộ ra những vấn đề về dynamics trong team, nó có thể nhanh chóng trở thành vật tế thần.
Chat system bị lạm dụng
Team của bạn vừa áp dụng policy mới: mọi PR cần ít nhất một reviewer approve.
Tuy nhiên bạn nhận thấy hầu hết PR được approve chỉ trong 5 phút.
Ban đầu bạn tự hỏi liệu team có đủ lớn để review nhanh như vậy không. Team có tổng cộng 11 developer.
Sau đó bạn phát hiện sự thật:
Team đã tìm ra workaround trong chat.
Mỗi khi có PR mới, tác giả chỉ cần nhắn vào chat team để xin approve nhanh.
Người nào đọc tin nhắn trước sẽ mở PR và approve mà không hề kiểm tra code.
Thậm chí có một QA engineer được gọi là “serial approver”—người approve mọi PR mở.
Mặc dù policy tồn tại, nhưng mọi thứ không hoạt động như dự định.
Lazy code reviews là vô dụng.
Trong tất cả các tình huống này, pain point rất rõ:
- quy trình được áp dụng cho một số người nhưng không phải tất cả
- review không đúng cách (do lười hoặc workaround)
Kết quả là:
- sự oán giận
- căng thẳng
- stress lớn trong team
Tình trạng này càng tệ hơn nếu tech lead hoặc manager phớt lờ hoặc dung túng hành vi đó.
Mean code review (Code review độc hại)
Một kiểu code review gây hại nghiêm trọng là mean code review.
Nếu bạn từng nhận:
- comment quá tiêu cực
- comment công kích cá nhân thay vì code
thì bạn đã trải nghiệm kiểu review này.
Đây là kiểu review mà developer sợ nhất.
“Tôi không có bộ lọc”
Trên một repository open source của một CSS framework, comment trong hình 7.1 được tìm thấy trong một PR.
Đây không phải ảnh ghép (ngoại trừ che thông tin cá nhân).
Nó tồn tại trên một repository thật ngoài internet.
Nếu người mở PR này là người lần đầu đóng góp open source, tôi gần như chắc chắn họ sẽ không bao giờ đóng góp nữa.
Bất kể ai gửi PR đó, họ có thể sẽ không còn cảm thấy được chào đón trong project này nữa.
Còn với người comment, đây là ví dụ rất rõ về những comment không bao giờ nên viết.
Có nhiều cách mang tính xây dựng hơn để truyền đạt ý kiến.
“Bạn không thuộc về nơi này”
Giả sử bạn là người mới trong team.
Bạn không mới với ngành phần mềm, nhưng bạn mới vào công ty.
Hồi hộp nhưng hào hứng, bạn muốn đóng góp vào codebase.
Sau nhiều nỗ lực và kiểm tra kỹ, bạn mở PR đầu tiên.
Vài giờ sau, bạn quay lại và thấy một loạt comment.
Những comment này:
- yêu cầu sửa các vấn đề mang tính chủ quan
- chỉ ra “những lỗi ngu ngốc” bằng ngôn từ tương tự
- khiến bạn cảm thấy tệ
Đây chắc chắn không phải một khởi đầu tốt.
Bây giờ hãy tưởng tượng thay bạn trong tình huống này bằng:
- một junior developer
- hoặc người đang bắt đầu công việc lập trình đầu tiên
Trải nghiệm đó sẽ ảnh hưởng thế nào?
Nó sẽ khiến họ nhìn nhận code review ra sao?
Bạn có muốn ở lại team như vậy không?
Làm việc cho công ty bỏ qua những trao đổi như vậy?
Ở lại một ngành mà điều đó là bình thường?
Câu trả lời có lẽ khá rõ.
Code review không nên độc hại.
Trong những code review này:
- sự khéo léo (tact) không tồn tại
- phê bình mang tính xây dựng là khái niệm xa lạ
Những sai lầm này có thể gây tổn hại lớn nhất cho team.
Shape-shifting code review (Code review biến hình)
Trong trường hợp này, code review trở nên không thể quản lý đối với reviewer.
Review kéo dài rất lâu vì code bạn bắt đầu review không còn là code bạn đang review nữa.
Stacking PRs
Khi một PR phụ thuộc vào PR khác, rồi PR đó lại phụ thuộc PR khác nữa, điều này gọi là stacking PRs.
Ý định và context ban đầu của PR trở nên không rõ ràng.
Reviewer sẽ gặp các câu hỏi như:
- Có nên xét cả thay đổi từ các PR khác không?
- Comment của tôi còn áp dụng được không?
- Nếu các PR phụ thuộc thuộc về tác giả khác thì sao?
- Tôi có nên @mention họ vào PR này không?
Toàn bộ quá trình trở nên không thể quản lý.
Mục tiêu di động (Moving target)
Bạn được giao review một PR “nhanh”.
Bạn review gần xong thì BAM!
Commit mới được push.
Bạn phải review lại.
May mắn là thay đổi mới không nhiều.
Bạn review lại, chuẩn bị bấm Approve…
PR quay lại trạng thái Needs Review.
Vì sao?
Lại có commit mới.
Bạn bắt đầu tự hỏi:
- Điều này sẽ xảy ra bao nhiêu lần?
- Tại sao mở PR khi chưa hoàn thành?
- Làm sao để không lãng phí thời gian review đi review lại?
Code review cần quản lý được.
Trong hai tình huống này, reviewer sẽ cực kỳ bực bội khi:
- PR chưa sẵn sàng
- mục tiêu review liên tục thay đổi
Nếu review liên tục thay đổi target, nó sẽ không bền vững về lâu dài.
Và chắc chắn bạn sẽ có vài đồng nghiệp rất khó chịu.
Stringent code review (Code review quá khắt khe)
Ở đầu kia của phổ vấn đề, cũng có chuyện review quá mức.
Đặc biệt khi không có automation.
Nếu quy trình code review:
- quá nhiều bước
- quá cứng nhắc
- quá phức tạp
- quá phụ thuộc thao tác thủ công
- quá nghiêm ngặt
thì mọi người sẽ lách quy trình thay vì tuân theo.
“Bạn đã làm X, Y, Z chưa—à còn D, E, G nữa?”
Trong một công việc trước đây, quy trình code review để deploy production rất tệ.
Trước hết phải chạy nhiều script thủ công để kiểm tra.
Sau đó xác nhận trên PR rằng chúng chạy thành công.
Tiếp theo PR cần nhiều link:
- link staging preview
- link report log
- link work ticket
(vì hệ thống version control khác với hệ thống task management nên không tích hợp được)
Sau khi hoàn tất, reviewer mới bắt đầu review.
Nếu có sửa đổi, tôi phải làm lại toàn bộ các bước.
Mỗi lần sửa code, tôi phải cập nhật lại link staging mới.
Đôi khi service tạo link staging:
- lỗi
- timeout
- quá tải
Và chỉ có một agent tạo link cho toàn bộ tổ chức 120 người.
Không khó hiểu khi team ghét quy trình này.
“Mọi thứ đều phải qua tôi”
Ở một công ty khác, quy trình ban đầu khá tốt.
Có môi trường:
- testing
- staging
- production
Có automation quality checks.
Nhưng sau đó xuất hiện yêu cầu mới:
project manager phải approve mọi giai đoạn.
Kết quả:
- deploy vào testing cần developer + project manager approve
- deploy staging cần QA + project manager approve
- deploy production cần CTO + project manager approve
Nghe có vẻ an toàn hơn.
Nhưng thực tế team phải chờ project manager rảnh để approve, khiến quy trình vốn đã dài lại càng chậm hơn.
Code review nên liền mạch với workflow.
Nếu team bị bottleneck bởi các bước xung quanh code review trước khi review bắt đầu, có vấn đề.
Nếu deploy một fix nhỏ nhưng phải:
- xin nhiều approval
- thu thập chữ ký
- vượt qua nhiều gate
mọi người sẽ nhanh chóng chán quy trình.
Và khi việc phát hành giá trị cho khách hàng bị trì hoãn, chi phí cho tổ chức sẽ tăng lên.
Ở mức tệ nhất, mọi người ngừng quan tâm, điều này gây hại cho cả team lẫn codebase.
Vậy chúng ta phải làm gì?
Ây da, đó là một hành trình khá hỗn loạn, phải không?
Nếu bạn đọc các tình huống trên và gật đầu đồng ý, có lẽ bạn đã từng trải qua code review kém hiệu quả hoặc tệ hại.
Tin tốt là nhiều pain point có thể quy về các vấn đề phổ biến:
- team không có hiểu biết chung về kỳ vọng
- không rõ review cần làm gì và trách nhiệm của mỗi người
- không tận dụng automation
- giao tiếp kém trong quá trình review
Phần tiếp theo sẽ nói về những vấn đề khó hơn.
Hãy xem cách làm cho code review tốt hơn nữa.


Để lại một bình luận
Bạn phải đăng nhập để gửi bình luận.