Code review hiệu quả

Đôi khi trong công việc, chất lượng code trở thành một vấn đề trong team và mọi người bắt đầu thảo luận việc làm thế nào để cải thiện được unit test và code coverage, nhưng thông thường không kéo dài được lâu. Cuối cùng, chuyện đó không còn là một chủ đề hot nữa, bởi mọi người ai cũng đều bận rộn với công việc của mình. Nhưng sau đó chỉ trong vòng một năm thôi, bạn sẽ lại đối mặt với tình trạng déjà vu (tình huống như đã trải qua rồi), bởi vào năm sau đó, những ý tưởng y hệt lại xuất hiện trong đầu bạn. 
Tên tôi là Bryan Liu – automation QA tại LINE NOW, và tôi muốn được chia sẻ cho các bạn kinh nghiệm tôi đã làm để tạo điều kiện thuận lợi cho quy trình unit test và code review tại Line Đài Loan. 

Unit test và code review

Như CTO của chúng tôi đã đề cập đến trong buổi OJT, Peer code review là một phần của văn hóa kỹ thuật của LINE. Facebook nêu lên ba điều quan trọng nhất trong development, đó là code review, code review và code review. Đúng vậy, cách duy nhất để hướng đến unit test và cải thiện chất lượng code là biến unit test trở thành văn hóa kỹ thuật, và code review tồn tại giúp ta làm được việc đó.

boyscout_rule
 “Luôn luôn để đoạn code bạn đang sửa tốt hơn một chút so với khi bạn tìm thấy nó.”
(Luật của nam hướng đạo sinh khi code, nguồn: {codemotion}

Thực hiện theo luật nam hướng đạo sinh này hướng người review đến việc kiểm tra xem các unit test có bổ sung code mới và bug fix hay không trong quá trình review code. Bằng việc liên tục kiểm tra, code coverage sẽ được mở rộng hoặc ít nhất cũng được giữ nguyên. Ví dụ: nếu code coverage đi xuống, người có code được review sẽ phải giải thích cho team những khó khăn mà mình gặp phải và nguyên nhân tại sao họ không bổ sung thêm test. Nếu tất cả mọi người trong team đồng ý với giải thích đó và không có vấn đề gì, cá nhân đó sẽ được tiếp tục. Nếu không, chủ code sẽ phải fix!

Bí kíp để có Code review hiệu quả  

Cách review code hiệu quả nhất là thông qua pair programming (lập trình đôi), tuy nhiên sử dụng PR (Pull Request) vẫn được, nếu cách đó phù hợp với team của bạn hơn. Để xong được code review, ý tôi là thực sự xong, việc đầu tiên chúng ta cần làm là cải thiện quy trình code review trước đã; về cách làm chung, là chúng ta coi những người review như là một nguồn lực hiếm, bởi không một trách nhiệm chính nào của chúng ta có bao gồm code review, phải không các bạn?! 

Dưới đây là một vài bí quyết để code review đạt được hiệu quả và năng suất:

Sửa đổi từng chút một

Một nghiên cứu thực hiện bởi team lập trình Hệ thống Cisco (Cisco System programming team) đã chỉ ra rằng một review khoảng 60 đến 90 phút cho 200 đến 400 dòng code mang lại 70%-90% hiệu suất phát hiện lỗi. Hãy coi mỗi một PR là một đơn vị có thể release (feature, bug fix) hoặc một ý tưởng có tính kết dính có nghĩa cho PR. Để biết thêm vì sao một PR lớn sẽ không tốt và tối ưu hóa kích cỡ mỗi PR, click vào đây.

Code reviews, đăng bởi @iamdeveloper trên Twitter & Defect density (Mật độ sai sót) vs LoC (Số dòng code), từ Cisco study case

Review thường xuyên và rút ngắn thời gian của mỗi lần review

Việc review code với số lượng vừa phải, nhịp độ chậm hơn, và trong một thời gian giới hạn mang lại kết quả code review tốt nhất. Nếu số dòng code vượt trên 400, khả năng tìm ra lỗi sẽ bị giảm bớt. Tốt nhất là giữ tỷ lệ kiểm tra ở mức dưới 300 dòng code/giờ. 

Defect density (Mật độ sai sót) vs inspection rate (tỷ lệ kiểm tra), từ Cisco study case

Gửi Pull Request để review càng sớm càng tốt 

Để có được code review có giá trị, bạn hãy thảo luận trước khi tiến hành cụ thể và cố gắng đừng đưa ra các quan điểm khác nhau ở quy mô lớn. Chia các ý tưởng khác nhau thành nhiều PR và assign nhiều người review nếu thấy cần thiết, bằng việc chia các vấn đề thành nhiều phần nhỏ hơn và giải quyết từng vấn đề nhỏ một. 

Cách áp dụng giải pháp thay thế khi vấn đề cấu trúc / thiết kế được phát hiện khi review code của PR đưa lên vào phút cuối – đăng bởi @isoiphone trên Twitter

Cung cấp thông tin / bối cảnh đầy đủ cho việc tạo một PR có ý nghĩa 

Nguồn lực review code rất có giới hạn, hãy sử dụng một cách thông minh!

Để giúp người review code nhìn ra bối cảnh một cách nhanh chóng, việc cung cấp đủ thông tin là rất quan trọng. Ví dụ: vì sao thay đổi, và đã thay đổi như thế nào, đi kèm với việc nêu lên sự nhìn nhận các rủi ro hay quan ngại. Những thông tin như vậy là chất xúc tác tốt cho các cuộc thảo luận sau đó. Một điểm lợi nữa là tác giả sẽ thường xuyên tìm ra lỗi bổ sung trước khi việc review được bắt đầu. Mặc dù không phải PR nào cũng cần phải kèm thông tin cụ thể, nhưng bạn vẫn có thể chú thích ngắn gọn những gì đã làm và đã được test, hay phần nào người review cần chú trọng nhiều hơn!

Đối với cách này, các issue và template trên Github sẽ rất có ích cho bạn tham khảo. Đồng thời, việc đính kèm bản chụp màn hình để miêu tả mục tiêu của bạn cũng là một cách hay! Dưới đây là một vài ví dụ sử dụng template PR để cung cấp bối cảnh có nghĩa cho việc review code và việc xác minh QA sau này.

Các ví dụ về template Github PR

Linting và kiểm tra Code Style 

Hãy để các machine với tool như SonarQubeESLint làm công việc phân tích static code hay kiểm tra code style, và dành nhân lực cho những phần quan trọng như business logic hay thuật toán. Những công cụ scan code, công cụ kiểm tra type hay công cụ linting này có thể báo cáo cho chúng ta về bug, code smell  hay lỗ hổng, đi cùng với các test suite tốt nữa thì chắc chắn tăng được mức độ tin cậy. 

Phát hiện issue trong SonarQube theo website của SonarQube  

Một trong những phần quan trọng nhất của việc review code là thưởng cho người code vì sự lớn lên và nỗ lực của họ, vậy nên bạn hãy cố gắng dành tặng cho họ những lời khen nhiều nhất có thể nhé.

Cuối cùng, bạn sẽ không thể review code một cách đàng hoàng nếu như không hiểu các phần của code. Nếu các đoạn thảo luận của bạn có vẻ như đang đi lòng vòng, việc cầm chủ đề thảo luận đó và mang ra để chốt trực tiếp với đối phương sẽ mang lại hiệu quả nhiều hơn cho bạn.

Hãy biến điều đó thành một phần văn hóa kỹ thuật của chúng ta

Ai đó đã nói rằng “Văn hóa là thứ mà mọi người làm kể cả khi không ai nhìn vào họ”. Liệu bạn có vẫn viết test đầy đủ cho code của mình nếu quy trình code review được bỏ qua? Không dễ phải không nào? Nhưng điều đó vẫn đáng để thử bạn ạ! Nếu dự án của bạn áp dụng Agile, hay xem xét các yếu tố dưới đây để giúp team của bạn tự định hướng, liên tục cải thiện và học hỏi:

  • Quyền tự chủ (autonomy): Các thành viên trong team tự chịu trách nhiệm và làm việc theo cách mà họ muốn (Ví dụ: Scrum, pair programming).
  • Quyền làm chủ (mastery): Việc liên tục thực hiện các cách code tốt và học hỏi lẫn nhau thông qua code review sẽ nâng cao được kỹ năng code của từng cá nhân.
  • Mục đích (purpose): Chất lượng code là mục tiêu cuối cùng của chúng ta, hãy tìm ra bug ngay trong giai đoạn đầu thay vì phải đi dập lửa trên môi trường production.

Bởi vậy, để giúp xây dựng văn hóa team một cách thuận lợi, đôi đã bắt đầu nỗ lực vào hai phần:

Nâng cao kỹ năng

Đúng vậy, để đi đến tận cùng việc nâng cao kỹ năng, lập trình viên vẫn cần phải có một khái niệm vững vàng và kiến thức hoàn chỉnh, nhằm đạt được sự đồng thuận ngày càng tăng (việc thực hành) trong team của mình trong công việc. Để giúp các lập trình viên, chúng tôi đã tận dụng sự tư vấn tại bản địa để tổ chức hội thảo về Unit test, Refactor hay TDD (phát triển theo hướng kiểm thử).

Tại các cuộc hội thảo, chúng tôi đã chú trọng các chủ đề sau (không giới hạn trong danh sách):

  1. Unit test
    • Thiết kế test case để trình bày ý định thay vì thực hiện kiểm tra code
    • Phát hiện và cô lập các dependency (sự phụ thuộc)
    • Giới thiệu các phương pháp Extract & Overwrite và Dependency Injection
    • Giải thích stub & mock framework và các thư viện assertion
    • Thực hành kỹ năng refactor như extract method, inline variables, và các kỹ năng khác
  2. Thực hành Kata (lập trình)
    • Phân tích yêu cầu (requirement), trau chuốt kịch bản và tìm ra các ví dụ chính
    • Thiết kế test case để trình bày ý định thay vì thực hiện kiểm tra code
  3. TDD và Refactoring
    • Demo việc refactor, nhận diện code smell và các phương pháp liên quan để loại bỏ chúng
    • Code trực tiếp theo cách tiếp cận TDD (Ví dụ: các bước sơ khai, đèn đỏ đèn xanh)
    • Luyện tập thực hành.
Các hình ảnh workshop

Đánh giá sự tiến bộ

Bạn không thể đánh giá, cũng không thể cải thiện cái mà bạn không nhìn thấy!

Bằng cách tận dụng các Dashboard, thông báo tin nhắn để liên tục nhắc nhở mọi người theo đuổi mục tiêu, chúng tôi hiển thị luân phiên những dashboard dưới đây trên màn hình lớn ngay lối cổng vào: 

Dashboard dự án SonarQube  

Mọi chỉ số thống kê của phân tích static code được lấy từ SonarQube, các repo code kết nối trưc tiếp đến các production service được báo cáo công khai tại đây.

Code coverage theo team

Biểu đồ code coverage theo team hiển thị xu hướng coverage của mỗi repository của một team, do vậy bạn không cần phải chuyển sang từng trang dự án của SonarQube. Bằng cách đặt các biểu đồ loại này bên cạnh nhau, rất dễ dàng để so sánh các team đang có tình hình khác nhau như thế nào.

Kích cỡ PR và thời gian giải quyết

Ý tưởng cốt lõi của DevOps là làm thế nào để release các sự thay đổi của phần mềm lên môi trường production một cách thường xuyên nhưng vẫn đảm bảo được tốt về chất lượng. Mẹo được dùng ở đây là deploy theo từng phần nhỏ. Những PR lớn không chỉ khiến việc review có chất lượng trở nên bất khả thi, mà còn khiến trả giá về chất lượng code và chu kỳ release. Bởi vậy, việc làm một task/ thay đổi nhỏ là một kỹ năng có hiệu quả trong DevOps. Chúng tôi nỗ lực khuyến khích ý tưởng này bằng biểu đồ “Resolution time (Thời gian giải quyết) vs PR size (kích cỡ PR)” dưới đây:

  • Cỡ của vòng tròn: Kích cỡ của set thay đổi (số dòng code)
  • Resolution time (Thời gian giải quyết): Khoảng thời gian từ khi PR được tạo cho đến khi PR được merge.
  • #n: Số của PR

Các biểu đồ này liên tục xây dựng nhận thức nhắc nhở mọi người về sự tiến triển của việc áp dụng các thói quen và mục tiêu mục tiêu mà chúng tôi theo đuổi. Đây chỉ là một vài ví dụ của những gì chúng tôi đã làm. Bạn hãy thử suy nghĩ về phương thức nào có thể trực quan hóa được ý định, mục tiêu của mình cho người khác thấy. Tiện đây, phải nói rằng các cách này cũng có ích cho chúng ta trong việc tóm lược tình hình công việc trong các buổi họp hàng tháng. 

Thông báo comment PR

Mỗi một commit được gửi đến PR sẽ kích hoạt một webhook và gửi một github comment như hình bên dưới. Việc này để nhắc nhờ người tạo PR tạo thêm test và fix các lỗ hổng được tìm thấy ngay bên trong PR, bởi cách này có hiệu quả hơn so với việc tiến hành những việc này 2 tuần sau khi đã release hêt mọi thay đổi lên production. Để có được chỉ số chất lượng tốt hơn, người review code cũng nên giúp tìm ra nguyên nhân vì sao người có code được review đang gặp vấn đề. 

  • Last n Avg. (Số bình quân gần nhất): Thể hiện xu thế của từng metric 
  • xxx_violations (xxx_vi phạm): Số lượng bug, lỗ hổng và code smell được phát hiện
  • line_coverage: Tỷ lệ phần trăm số dòng code có unit test trên tổng số dòng code.

Tổng kết và các kế hoạch tương lai

Làm thế nào viết code sạch, làm thế nào để nhận diện code smell và loại bỏ chúng là các lý do rất phù hợp cho các cuộc thảo luận code review, và khi team thực sự sẵn sàng chỉ ra những issue chung, văn hóa team sẽ vô hình chung được cùng nuôi dưỡng. 

Một mặt khác, những metric không được track (theo dõi) sẽ là những thứ không giúp ích được gì; việc thể hiện xu hướng data theo thời gian là một việc quan trọng, nó mang lại bối cảnh cho phép chúng ta có những động thái phản hồi. Nhìn vào những đường xu hướng trong các biểu đồ bên trên, ta thấy mọi thứ đang theo hướng đi lên. Chúng tôi cũng cân nhắc thêm cả bổ sung các dashboard sau:

  • Quality: Bảng chất lượng thể hiện số lượng bug ở trạng thái open / close cùng mức độ nghiêm trọng và mật độ sai sót
  • Vận tốc: Chu kỳ deployment, lead time đến production, tỷ lệ thất bại của các sửa đổi và MTTR (Mean time to repair – Thời gian trung bình để sửa chữa)

Tham khảo