Cách triển khai bộ phân tích mã tĩnh trong một dự án cũ mà không làm mất động lực của nhóm

Cách triển khai bộ phân tích mã tĩnh trong một dự án cũ mà không làm mất động lực của nhóm
Thật dễ dàng để thử một bộ phân tích mã tĩnh. Nhưng để thực hiện nó, đặc biệt là trong việc phát triển một dự án cũ lớn, đòi hỏi phải có kỹ năng. Nếu thực hiện không chính xác, máy phân tích có thể thêm công việc, làm chậm quá trình phát triển và làm mất động lực của nhóm. Hãy nói ngắn gọn về cách tiếp cận hợp lý việc tích hợp phân tích tĩnh vào quá trình phát triển và bắt đầu sử dụng nó như một phần của CI/CD.

Giới thiệu

Gần đây tôi chú ý đến ấn phẩm "Bắt đầu với phân tích tĩnh mà không làm nhóm choáng ngợp". Một mặt, đây là một bài viết hay đáng để làm quen. Mặt khác, đối với tôi, có vẻ như nó vẫn chưa đưa ra câu trả lời đầy đủ về cách triển khai phân tích tĩnh một cách dễ dàng trong một dự án có rất nhiều Bài báo nói rằng Bạn có thể chấp nhận nợ kỹ thuật và chỉ làm việc với mã mới, nhưng không có câu trả lời về việc phải làm gì với khoản nợ kỹ thuật này sau này.

Nhóm PVS-Studio của chúng tôi đưa ra quan điểm của mình về chủ đề này. Chúng ta hãy xem ngay từ đầu vấn đề triển khai bộ phân tích mã tĩnh phát sinh như thế nào, cách khắc phục vấn đề này và cách loại bỏ dần dần nợ kỹ thuật một cách dễ dàng.

Vấn đề

Thông thường, không khó để khởi chạy và xem cách hoạt động của máy phân tích tĩnh [1]. Bạn có thể thấy những lỗi thú vị hoặc thậm chí là những lỗ hổng tiềm ẩn đáng sợ trong mã. Bạn thậm chí có thể sửa một cái gì đó, nhưng sau đó nhiều lập trình viên bỏ cuộc.

Tất cả các máy phân tích tĩnh đều tạo ra kết quả dương tính giả. Đây là một tính năng của phương pháp phân tích mã tĩnh và không thể làm gì được về nó. Trong trường hợp tổng quát, đây là bài toán không giải được, được xác nhận bởi định lý Rice [2]. Các thuật toán học máy cũng không giúp được gì [3]. Ngay cả khi một người không phải lúc nào cũng có thể biết liệu mã này hay mã kia sai, thì bạn không nên mong đợi điều này từ chương trình :).

Kết quả dương tính giả không phải là vấn đề nếu máy phân tích tĩnh đã được cấu hình:

  • Đã tắt các bộ quy tắc không liên quan;
  • Một số chẩn đoán không liên quan đã bị vô hiệu hóa;
  • Nếu chúng ta đang nói về C hoặc C++, thì các macro được đánh dấu có chứa các cấu trúc cụ thể khiến các cảnh báo vô dụng xuất hiện ở mọi nơi sử dụng các macro đó;
  • Các chức năng riêng được đánh dấu để thực hiện các hành động tương tự như các chức năng hệ thống (tương tự của chính nó memcpy hoặc printf) [4];
  • Kết quả dương tính giả bị vô hiệu hóa cụ thể bằng cách sử dụng nhận xét;
  • Và như vậy.

Trong trường hợp này, chúng ta có thể mong đợi tỷ lệ dương tính giả thấp khoảng 10-15% [5]. Nói cách khác, 9 trên 10 cảnh báo của máy phân tích sẽ chỉ ra vấn đề thực sự trong mã, hoặc ít nhất là “mã có mùi nồng”. Đồng ý rằng, kịch bản này cực kỳ thú vị và máy phân tích là người bạn thực sự của lập trình viên.

Cách triển khai bộ phân tích mã tĩnh trong một dự án cũ mà không làm mất động lực của nhóm
Trên thực tế, trong một dự án lớn, bức tranh ban đầu sẽ hoàn toàn khác. Máy phân tích đưa ra hàng trăm hoặc hàng nghìn cảnh báo về mã kế thừa. Không thể nhanh chóng hiểu được cảnh báo nào trong số này có liên quan và cảnh báo nào không. Thật không hợp lý khi ngồi xuống và bắt đầu xử lý tất cả những cảnh báo này, vì công việc chính trong trường hợp này sẽ dừng lại trong nhiều ngày hoặc nhiều tuần. Thông thường, một đội không thể chấp nhận được một tình huống như vậy. Cũng sẽ có một số lượng lớn các khác biệt làm hỏng lịch sử thay đổi. Và việc chỉnh sửa hàng loạt quá nhiều đoạn trong mã chắc chắn sẽ dẫn đến những lỗi chính tả và lỗi mới.

Và quan trọng nhất, một chiến công như vậy trong cuộc chiến chống lại các cảnh báo chẳng có ý nghĩa gì. Đồng ý rằng vì dự án đã chạy thành công trong nhiều năm nên hầu hết các lỗi nghiêm trọng trong đó đã được sửa chữa. Có, những bản sửa lỗi này rất tốn kém, phải sửa lỗi, nhận được phản hồi tiêu cực của người dùng về lỗi, v.v. Máy phân tích tĩnh sẽ giúp khắc phục nhiều lỗi này ở giai đoạn mã hóa một cách nhanh chóng và ít tốn kém. Nhưng hiện tại, bằng cách này hay cách khác, các lỗi này đã được sửa và máy phân tích chủ yếu phát hiện các lỗi không nghiêm trọng trong mã cũ. Mã này có thể không được sử dụng, nó có thể rất hiếm khi được sử dụng và một lỗi trong đó có thể không dẫn đến hậu quả đáng chú ý. Có thể bóng của nút bấm bị sai màu ở đâu đó nhưng điều này không ảnh hưởng đến việc sử dụng sản phẩm của bất kỳ ai.

Tất nhiên, ngay cả những sai lầm nhỏ vẫn là sai lầm. Và đôi khi một sai lầm có thể che giấu một điểm yếu thực sự. Tuy nhiên, việc từ bỏ mọi thứ và dành nhiều ngày/tuần để giải quyết những khiếm khuyết hầu như không biểu hiện ra có vẻ là một ý tưởng đáng ngờ.

Các lập trình viên nhìn, nhìn, nhìn tất cả những cảnh báo này về mã làm việc cũ... Và họ nghĩ: chúng ta có thể làm mà không cần phân tích tĩnh. Hãy bắt đầu viết một số chức năng hữu ích mới.

Theo cách riêng của họ, họ đúng. Họ nghĩ rằng trước tiên họ phải bằng cách nào đó loại bỏ được tất cả những cảnh báo này. Chỉ khi đó họ mới có thể hưởng lợi từ việc sử dụng thường xuyên bộ phân tích mã. Nếu không, những cảnh báo mới sẽ chìm trong những cảnh báo cũ và không ai chú ý đến chúng.

Đây là sự tương tự tương tự như với các cảnh báo của trình biên dịch. Không phải vô cớ mà họ khuyên bạn nên giữ số lượng cảnh báo của trình biên dịch ở mức 0. Nếu có 1000 cảnh báo thì khi có 1001, sẽ không có ai chú ý đến nó và cũng không rõ phải tìm cảnh báo mới nhất này ở đâu.

Cách triển khai bộ phân tích mã tĩnh trong một dự án cũ mà không làm mất động lực của nhóm
Điều tồi tệ nhất trong câu chuyện này là nếu ai đó từ cấp trên vào lúc này buộc bạn phải sử dụng phân tích mã tĩnh. Điều này sẽ chỉ làm giảm động lực của nhóm, vì theo quan điểm của họ, sẽ có thêm sự phức tạp về quan liêu chỉ cản trở. Sẽ không có ai xem báo cáo của máy phân tích và mọi hoạt động sử dụng sẽ chỉ “trên giấy”. Những thứ kia. Về mặt hình thức, phân tích được tích hợp vào quy trình DevOps, nhưng trên thực tế, điều này không mang lại lợi ích cho bất kỳ ai. Chúng tôi đã nghe những câu chuyện chi tiết tại các gian hàng từ những người tham dự hội nghị. Trải nghiệm như vậy có thể khiến các lập trình viên không muốn sử dụng các công cụ phân tích tĩnh trong thời gian dài, nếu không muốn nói là mãi mãi.

Thực hiện và loại bỏ nợ kỹ thuật

Trên thực tế, không có gì khó khăn hay đáng sợ khi áp dụng phân tích tĩnh ngay cả vào một dự án lớn cũ.

CI / CD

Hơn nữa, máy phân tích có thể ngay lập tức trở thành một phần của quá trình phát triển liên tục. Ví dụ: bản phân phối PVS-Studio chứa các tiện ích để xem báo cáo ở định dạng bạn cần một cách thuận tiện và thông báo cho các nhà phát triển đã viết các phần mã có vấn đề. Đối với những người quan tâm hơn đến việc khởi chạy PVS-Studio từ hệ thống CI/CD, tôi khuyên bạn nên tự làm quen với các công cụ tương ứng. tiết diện tài liệu và một loạt bài viết:

Nhưng hãy quay lại vấn đề số lượng lớn các kết quả dương tính giả ở giai đoạn đầu triển khai các công cụ phân tích mã.

Khắc phục nợ kỹ thuật hiện có và xử lý các cảnh báo mới

Máy phân tích tĩnh thương mại hiện đại cho phép bạn chỉ nghiên cứu các cảnh báo mới xuất hiện trong mã mới hoặc mã đã thay đổi. Việc thực hiện cơ chế này có khác nhau nhưng bản chất thì giống nhau. Trong máy phân tích tĩnh PVS-Studio, chức năng này được triển khai như sau.

Để nhanh chóng bắt đầu sử dụng phân tích tĩnh, chúng tôi khuyên người dùng PVS-Studio nên sử dụng cơ chế ngăn chặn hàng loạt cảnh báo [6]. Ý tưởng chung là như sau. Người dùng khởi chạy máy phân tích và nhận được nhiều cảnh báo. Vì một dự án đã được phát triển trong nhiều năm vẫn tồn tại, phát triển và kiếm tiền nên rất có thể sẽ không có nhiều cảnh báo trong báo cáo chỉ ra những khiếm khuyết nghiêm trọng. Nói cách khác, các lỗi nghiêm trọng đã được sửa bằng cách này hay cách khác bằng các phương pháp đắt tiền hơn hoặc nhờ phản hồi từ khách hàng. Theo đó, mọi thứ mà máy phân tích hiện tìm thấy đều có thể được coi là nợ kỹ thuật, điều này là không thực tế nếu cố gắng loại bỏ ngay lập tức.

Bạn có thể yêu cầu PVS-Studio coi những cảnh báo này là không liên quan vào lúc này (để dành nợ kỹ thuật cho sau này) và nó sẽ không hiển thị chúng nữa. Máy phân tích tạo một tệp đặc biệt để lưu thông tin về các lỗi chưa thú vị. Và bây giờ PVS-Studio sẽ chỉ đưa ra cảnh báo đối với mã mới hoặc mã đã thay đổi. Hơn nữa, tất cả điều này được thực hiện một cách khéo léo. Ví dụ: nếu một dòng trống được thêm vào đầu tệp mã nguồn, thì bộ phân tích hiểu rằng trên thực tế, không có gì thay đổi và sẽ tiếp tục im lặng. Tệp đánh dấu này có thể được đưa vào hệ thống kiểm soát phiên bản. Tệp lớn, nhưng đây không phải là vấn đề vì không có ích gì khi lưu trữ nó thường xuyên.

Bây giờ tất cả các lập trình viên sẽ chỉ thấy các cảnh báo liên quan đến mã mới hoặc mã đã thay đổi. Vì vậy, bạn có thể bắt đầu sử dụng máy phân tích, như người ta nói, từ ngày hôm sau. Và bạn có thể quay lại nợ kỹ thuật sau đó, dần dần sửa lỗi và định cấu hình máy phân tích.

Vì vậy, vấn đề đầu tiên khi triển khai máy phân tích trong một dự án lớn cũ đã được giải quyết. Bây giờ chúng ta hãy tìm hiểu xem phải làm gì với nợ kỹ thuật.

Sửa lỗi và tái cấu trúc

Điều đơn giản và tự nhiên nhất là dành một chút thời gian để phân tích các cảnh báo bị ngăn chặn hàng loạt của máy phân tích và dần dần xử lý chúng. Ở đâu đó bạn nên sửa lỗi trong mã, ở đâu đó bạn nên cấu trúc lại để cho máy phân tích biết rằng mã không có vấn đề. Ví dụ đơn giản:

if (a = b)

Hầu hết các trình biên dịch và phân tích C++ đều phàn nàn về mã như vậy, vì có khả năng cao là họ thực sự muốn viết (một == b). Nhưng có một thỏa thuận bất thành văn, và điều này thường được ghi trong tài liệu, rằng nếu có thêm dấu ngoặc đơn thì coi như lập trình viên đã cố tình viết mã như vậy và không cần phải chửi thề. Ví dụ: trong tài liệu PVS-Studio để chẩn đoán V559 (CWE-481) nó được viết rõ ràng rằng dòng sau sẽ được coi là chính xác và an toàn:

if ((a = b))

Một vi dụ khac. Có phải nó bị quên trong mã C++ này không? phá vỡ có hay không?

case A:
  foo();
case B:
  bar();
  break;

Máy phân tích PVS-Studio sẽ đưa ra cảnh báo tại đây V796 (CWE-484). Đây có thể không phải là lỗi, trong trường hợp đó bạn nên gợi ý cho trình phân tích cú pháp bằng cách thêm thuộc tính [[thất bại]] hoặc ví dụ __attribute__((dự phòng)):

case A:
  foo();
  [[fallthrough]];
case B:
  bar();
  break;

Có thể nói việc thay đổi code như vậy không khắc phục được lỗi. Vâng, điều này đúng, nhưng nó có hai tác dụng hữu ích. Đầu tiên, báo cáo của máy phân tích sẽ loại bỏ các kết quả dương tính giả. Thứ hai, mã trở nên dễ hiểu hơn đối với những người tham gia bảo trì nó. Và điều này rất quan trọng! Chỉ riêng điều này thôi, đáng để thực hiện các tái cấu trúc nhỏ để làm cho mã rõ ràng hơn và dễ bảo trì hơn. Vì máy phân tích không hiểu liệu “break” có cần thiết hay không nên các lập trình viên đồng nghiệp cũng sẽ không rõ ràng.

Ngoài việc sửa lỗi và tái cấu trúc, bạn có thể loại bỏ các cảnh báo rõ ràng là sai của máy phân tích. Một số chẩn đoán không liên quan có thể bị vô hiệu hóa. Ví dụ, có người cho rằng cảnh báo là vô nghĩa V550 về việc so sánh các giá trị float/double. Và một số phân loại chúng là quan trọng và đáng nghiên cứu [7]. Cảnh báo nào được coi là có liên quan và cảnh báo nào không tùy thuộc vào nhóm phát triển quyết định.

Có nhiều cách khác để ngăn chặn cảnh báo sai. Ví dụ: đánh dấu macro đã được đề cập trước đó. Tất cả điều này được mô tả chi tiết hơn trong tài liệu. Điều quan trọng nhất là phải hiểu rằng nếu bạn tiếp cận dần dần và có hệ thống với các kết quả dương tính giả thì chúng không có gì sai cả. Phần lớn các cảnh báo không thú vị sẽ biến mất sau khi cấu hình và chỉ còn lại những nơi thực sự cần nghiên cứu cẩn thận và một số thay đổi trong mã.

Ngoài ra, chúng tôi luôn hỗ trợ khách hàng setup PVS-Studio nếu có khó khăn phát sinh. Hơn nữa, có những trường hợp chúng tôi tự loại bỏ những cảnh báo sai và sửa lỗi [8]. Để đề phòng, tôi quyết định đề cập rằng tùy chọn hợp tác mở rộng này cũng có thể thực hiện được :).

Phương pháp bánh cóc

Có một cách tiếp cận thú vị khác để dần dần cải thiện chất lượng mã bằng cách loại bỏ cảnh báo của bộ phân tích tĩnh. Điểm mấu chốt là số lượng cảnh báo chỉ có thể giảm đi.

Cách triển khai bộ phân tích mã tĩnh trong một dự án cũ mà không làm mất động lực của nhóm

Số lượng cảnh báo do máy phân tích tĩnh đưa ra sẽ được ghi lại. Cổng chất lượng được cấu hình theo cách mà bây giờ bạn chỉ có thể nhập mã không làm tăng số lượng thao tác. Do đó, quá trình giảm dần số lượng cảnh báo bắt đầu bằng việc điều chỉnh máy phân tích và sửa lỗi.

Ngay cả khi một người muốn gian lận một chút và quyết định vượt qua cổng chất lượng không phải bằng cách loại bỏ các cảnh báo trong mã mới của mình mà bằng cách cải thiện mã cũ của bên thứ ba, điều này không có gì đáng sợ. Tuy nhiên, bánh cóc sẽ quay theo một hướng và dần dần số lượng khuyết tật sẽ giảm đi. Ngay cả khi một người không muốn sửa chữa những khiếm khuyết mới của mình, anh ta vẫn sẽ phải cải thiện điều gì đó ở mã lân cận. Đến một lúc nào đó, những cách dễ dàng để giảm số lượng cảnh báo sẽ kết thúc và sẽ đến lúc các lỗi thực sự sẽ được sửa.

Phương pháp này được mô tả chi tiết hơn trong một bài viết rất thú vị của Ivan Ponomarev "Thực hiện phân tích tĩnh trong quy trình, thay vì sử dụng nó để tìm lỗi", mà tôi khuyên những ai quan tâm đến việc cải thiện chất lượng mã nên đọc.

Tác giả bài viết cũng có báo cáo về chủ đề này: "Phân tích tĩnh liên tục".

Kết luận

Tôi hy vọng rằng sau bài viết này, độc giả sẽ chấp nhận hơn các công cụ phân tích tĩnh và muốn triển khai chúng vào quá trình phát triển. Nếu bạn có thắc mắc, chúng tôi luôn sẵn sàng khuyên nhủ người dùng máy phân tích tĩnh PVS-Studio của chúng tôi và trợ giúp triển khai nó.

Có những nghi ngờ điển hình khác về việc liệu phân tích tĩnh có thực sự thuận tiện và hữu ích hay không. Tôi đã cố gắng xua tan hầu hết những nghi ngờ này trong ấn phẩm “Lý do đưa máy phân tích mã tĩnh PVS-Studio vào quá trình phát triển” [9].

Cảm ơn bạn đã quan tâm và đến tải về và thử máy phân tích PVS-Studio.

Liên kết bổ sung

  1. Andrei Karpov. Làm cách nào tôi có thể nhanh chóng thấy các cảnh báo thú vị mà bộ phân tích PVS-Studio tạo ra cho mã C và C++?
  2. Wikipedia. Định lý gạo.
  3. Andrey Karpov, Victoria Khanieva. Sử dụng máy học trong phân tích tĩnh mã nguồn chương trình.
  4. PVS-Studio. Tài liệu. Cài đặt chẩn đoán bổ sung.
  5. Andrei Karpov. Đặc điểm của máy phân tích PVS-Studio sử dụng ví dụ về Thư viện lõi EFL, dương tính giả 10-15%.
  6. PVS-Studio. Tài liệu. Ngăn chặn hàng loạt tin nhắn phân tích.
  7. Ivan Andryashin. Về cách chúng tôi thử nghiệm phân tích tĩnh trong dự án mô phỏng giáo dục về phẫu thuật nội mạch bằng tia X.
  8. Pavel Eremeev, Svyatoslav Razmyslov. Nhóm PVS-Studio đã cải tiến mã Unreal Engine như thế nào.
  9. Andrei Karpov. Lý do nên đưa máy phân tích mã tĩnh PVS-Studio vào quá trình phát triển.

Cách triển khai bộ phân tích mã tĩnh trong một dự án cũ mà không làm mất động lực của nhóm

Nếu bạn muốn chia sẻ bài viết này với khán giả nói tiếng Anh, vui lòng sử dụng liên kết dịch: Andrey Karpov. Cách giới thiệu bộ phân tích mã tĩnh trong một dự án cũ và không làm nhóm nản lòng.

Nguồn: www.habr.com

Thêm một lời nhận xét