Tại sao độ phức tạp chu kỳ lại quan trọng đối với một phương pháp?


10

Tôi đang sử dụng SonarLint cho Eclipse từ gần đây và nó đã giúp tôi rất nhiều. Tuy nhiên, nó đặt ra cho tôi một câu hỏi về độ phức tạp chu kỳ.

SonarLint coi là chấp nhận được CC 10, và có một số trường hợp tôi vượt quá nó, khoảng 5 hoặc 6 đơn vị. Các phần đó có liên quan đến các trình ánh xạ trong đó các giá trị phụ thuộc vào các biến khác nhau, ví dụ:

  • Trường A dựa vào Chuỗi sA;
  • Trường B dựa vào Chuỗi sB;
  • Trường C dựa vào Chuỗi sC;
  • Vân vân ...

Tôi không có lựa chọn nào khác là đặt một ifcho mỗi lĩnh vực. Đây không phải là lựa chọn của tôi (may mắn thay) mà là một hệ thống đã tồn tại và phức tạp mà tôi không thể tự thay đổi.


Cốt lõi của câu hỏi của tôi là: tại sao việc không có CC quá cao trong một phương pháp lại quan trọng đến vậy? Nếu bạn di chuyển một số điều kiện của bạn theo một hoặc nhiều phương thức phụ để giảm độ phức tạp, thì nó không làm giảm chi phí cho chức năng tổng thể của bạn, nó chỉ là chuyển vấn đề đi nơi khác, tôi đoán vậy?

(Xin lỗi vì những lỗi nhỏ, nếu có).


BIÊN TẬP

Câu hỏi của tôi không đề cập đến độ phức tạp chu kỳ toàn cầu, mà chỉ liên quan đến độ phức tạp của phương thức và phân tách phương thức (tôi có một thời gian khó khăn để giải thích chính xác ý tôi là gì, xin lỗi). Tôi đang hỏi tại sao có thể phân chia các điều kiện của bạn thành các phương thức nhỏ hơn nếu nó vẫn thuộc về một 'siêu phương thức', nó sẽ chỉ thực hiện mọi phương thức phụ, do đó thêm độ phức tạp cho thuật toán.

Tuy nhiên, liên kết thứ hai ( về mô hình chống ) rất hữu ích.




^^ ^ Câu hỏi "đầu mũi tên" có lẽ là một bản sao tốt hơn theo nghĩa là nó giải thích cách cải thiện mã của bạn nhưng tôi đã chọn câu hỏi đầu tiên vì giải thích chi tiết trả lời một phần câu hỏi của bạn về độ phức tạp chu kỳ
gnat

Việc tách một phương thức thành các phần nhỏ hơn sẽ không làm giảm tổng số lượng mã được thực thi nhưng làm rõ các tác vụ riêng lẻ đang diễn ra; mỗi cái có thể được hiểu dễ dàng hơn nhiều so với khi chúng bị rối trong một tổng thể lớn hơn. Ít nhất, nó loại bỏ nhiều biến trung gian sử dụng một lần khỏi phạm vi lớn hơn.
Doval

1
Đối với trường hợp được mô tả cụ thể của bạn, tôi sẽ làm một cái gì đó trong phương thức chính của bạn như "A = extractAFrom (sA);" cho từng lĩnh vực. Bạn có thể có thể đưa ra tên tốt hơn vì bạn biết các trường thực tế và cách sử dụng chúng.
Tin Man

Câu trả lời:


32

Điều cốt lõi ở đây: "năng lực não bộ".

Bạn thấy đấy, một trong những chức năng chính của mã là ... được đọc . Và mã có thể dễ đọc và dễ hiểu; hoặc khó khăn.

Và có CC cao chỉ đơn giản ngụ ý rất nhiều "cấp độ" trong một phương thức. Và điều đó ngụ ý: bạn, là một người đọc con người sẽ có một thời gian khó hiểu phương pháp đó.

Khi bạn đọc mã nguồn, bộ não của bạn sẽ tự động cố gắng đưa mọi thứ vào viễn cảnh: nói cách khác - nó cố gắng tạo ra một số dạng "bối cảnh".

Và khi bạn có một phương thức nhỏ (với một tên hay) chỉ bao gồm một vài dòng và CC rất thấp; sau đó bộ não của bạn có thể dễ dàng chấp nhận "khối" này. Bạn đọc nó, bạn hiểu nó; LÀM XONG.

Mặt khác, nếu mã của bạn có CC cao, bộ não của bạn sẽ tiêu tốn nhiều "chu kỳ" hơn để khấu trừ những gì đang diễn ra.

Một cách khác để nói rằng: bạn nên luôn luôn nghiêng về việc thích một mạng lưới những điều đơn giản phức tạp hơn một mạng lưới những điều phức tạp đơn giản. Bởi vì bộ não của bạn tốt hơn trong việc hiểu những điều nhỏ.


9
Vì vậy, về cơ bản không phải là về vấn đề kỹ thuật , mà là về con người ? Âm thanh này, thực sự, thông minh, tôi không biết làm thế nào tôi không nghĩ về nó trước đây. Cảm ơn !
Yassine Badache

4
Nếu vậy, tôi hết lòng khuyên bạn nên lấy "Mã sạch" của Robert Martin (bạn có thể tìm thấy bản pdf miễn phí trên mạng). Bạn thấy đấy, việc tạo mã dễ đọc là một trong những đức tính quan trọng nhất nhưng thường bị bỏ qua của một lập trình viên giỏi.
GhostCat chào mừng Monica C. 2/12/2016

@YassineBadache CC cũng khiến bạn khó kiểm tra mọi ngóc ngách (bảo hiểm đầy đủ).
Tulains Córdova

Đây cũng là mấu chốt của giấy goto của Dijkstra .
Seth Battin

Theo kinh nghiệm của tôi, hầu hết các lỗi đều có trong các phương thức có CC cao và khi các lỗi ở phương thức CC thấp, chúng thường hoàn toàn rõ ràng, không có cách nào để chúng che giấu quá trình chạy mã đầu tiên. Ngoài ra, tôi thấy rằng tôi gần như không bao giờ phải sửa đổi một phương pháp CC thấp - tải nhiều hơn từ não.
Loren Pechtel

6

CC, giống như tất cả các quy tắc khác về mùi mã, là một heuristic . Đó không phải là một tiêu chí không an toàn cho bạn biết một sự thật tuyệt đối. Nếu đúng như vậy, điều hợp lý cần làm chỉ đơn giản là biến những phương pháp đó thành bất hợp pháp trong ngôn ngữ và buộc mọi người phải đạt được mục đích của mình theo một cách khác.

Nhưng đó không phải là cách các chỉ số hoạt động. Hầu hết thời gian chức năng của họ là để cảnh báo mọi người về những điều họ không biết. Trong trường hợp của bạn, bạn nhận thức được rằng logic bị sai lệch và các giải pháp thay thế sẽ khiến nó trở nên phức tạp hơn. Do đó, không có lý do gì để cố gắng thỏa mãn quy tắc nguyên thủy, khi mục đích chính của nó là đưa ra cảnh báo cho những người không biết rằng có vấn đề.


2
Nếu "FieldA dựa vào String sA" như trạng thái OP, tôi không tin rằng việc chuyển cái này thành một CompateFieldA (String sA) sẽ tạo ra mã phức tạp hơn.
Taemyr

2

Nói tóm lại: đó là tất cả về khả năng đọc và do đó khả năng duy trì mã của bạn.

Nếu bạn có một phương thức dài, phức tạp với rất nhiều (lồng nhau) if, sẽ rất khó để nói nó thực sự làm gì. Nếu bạn trích xuất một số phương thức riêng tư và đặt tên cho chúng theo một cách có ý nghĩa, nó sẽ dễ dàng hơn nhiều.


Mặc dù đây là một câu trả lời hay, nhưng nó hơi ngắn. Sẽ thật tuyệt nếu bạn có thể đưa ra một ví dụ về những gì bạn đang nói, và cụ thể hơn về câu hỏi của OP: "tại sao điều quan trọng là không có CC quá cao trong một phương pháp?".
Machado

2

Độ phức tạp theo chu kỳ của một phương pháp có liên quan đến số lượng các trường hợp thử nghiệm cần thiết cho một phương thức. Cụ thể, độ phức tạp theo chu kỳ là 10 có nghĩa là 10 là giới hạn trên cho các trường hợp thử nghiệm có tổng độ bao phủ chi nhánh cho phương thức của bạn. Nó cũng liên quan đến số lượng đường dẫn phải được kiểm tra, trừ đi mọi đường dẫn không thể.

Ngoài ra, tôi đồng ý với các câu trả lời khác cho các cân nhắc khác - năng lực tinh thần của nhà phát triển hoặc chỉ số về các vấn đề tiềm ẩn hoặc tái cấu trúc hoặc thước đo khả năng đọc và duy trì mã .


0

CC chỉ là một heuristic, và mức độ "tệ" của một điểm cụ thể phụ thuộc vào nhiều thứ.

Điều đó nói rằng, bạn nên luôn luôn xem một CC cao như một cái gì đó làm nổi bật mã có thể / nên được tái cấu trúc. Bạn nói rằng việc chuyển ifcâu lệnh sang một phương thức khác đang che giấu vấn đề - nhưng có một mô hình nào đó mà bạn có thể trừu tượng thay vì sao chép dán n lần không? Nếu đó là một if-elsechuỗi dài , bạn có thể biến nó thành một câu lệnh chuyển đổi, hoặc có thể sử dụng đa hình, hoặc một cái gì khác không? Nếu có sự lồng ghép sâu, một số mệnh đề có điều kiện của bạn có thể được tham gia không, hoặc nó có chỉ ra các trách nhiệm riêng biệt cần được chia thành các lớp khác nhau không?


0

Tôi thấy sự phức tạp theo chu kỳ như một lời cảnh báo. Nếu bạn có thể đọc mã và nó không quá phức tạp để hiểu thì tôi sẽ không lo lắng nhiều về nó, có lẽ có những điều quan trọng hơn sai để lo lắng, luôn luôn có.

Một cách để giảm loại CC bạn đề cập là sử dụng đa hình, vì bạn đã gắn thẻ câu hỏi của mình bằng thẻ Java. Vì vậy, thay vì các đường dẫn mã được gõ một cách nghiêm ngặt, bạn có thể sử dụng các lớp được đặt tên tốt. Điều này có thể giúp đỡ, nhưng đôi khi quá mức cần thiết và có thể làm cho mã của bạn trở nên khó hiểu hơn.

Tuy nhiên, nó có thể là một dấu hiệu của mã sẽ khó duy trì. Khi đọc phương thức, bạn có dễ dàng nhận ra đường dẫn mã nào bạn sẽ đi xuống cho từng trường hợp không? Bạn có thể bỏ qua phương pháp này nếu bạn không biết rõ về cơ sở mã và đang tìm kiếm một cái gì đó liên quan nhưng xa hơn trong mã? Tôi biết một số người ủng hộ việc chia các phương thức thành nhiều phương thức 1/2 dòng với tên mô tả nhưng đôi khi tôi nghĩ rằng nó thậm chí còn khó đọc hơn mã mà nó có nghĩa là để thay thế.

Khả năng bảo trì cuối cùng là một vấn đề khó khăn và tùy thuộc vào bạn quyết định cái nào bạn nghĩ sẽ dễ đọc hơn. Thực tế là bạn đang nghĩ về điều này có nghĩa là bạn đang đi đúng hướng. Chỉ cần nhớ, người bảo trì phải cố gắng giải mã mã này trong một năm có thể là bạn. Vì vậy, làm cho nó dễ dàng cho họ càng tốt.


0

Nó cho biết bao nhiêu thời gian dành cho việc tìm kiếm (chu kỳ não) tại mã và hiểu được những gì mã đang làm.

  • Xem xét phương pháp 10 dòng - Có thể mất vài phút để hiểu những gì nó đang làm.
  • Xem xét phương pháp 100 dòng - Có thể mất một giờ hoặc hơn để hiểu những gì đang làm.
  • Xem xét phương pháp 1000 dòng - Có thể mất một ngày hoặc hơn để hiểu những gì đang làm.

Ngoài ra các phương pháp lớn hơn khó kiểm tra hơn và khó dự đoán loại hành vi nào có thể xảy ra.

Độ phức tạp theo chu kỳ là một biện pháp. Trong trường hợp này, giá trị cao hơn là chỉ số của các vấn đề tiềm năng. Mã phức tạp mất nhiều thời gian hơn để hiểu và có thể không được kiểm tra kỹ lưỡng như các phương pháp ít phức tạp hơn. Vì vậy, điều quan trọng cần lưu ý là các khu vực của mã là phức tạp với biện pháp này cho mục đích tái cấu trúc và bảo trì.

Một điều khác cần xem xét là cập nhật mã phức tạp. Khi thực hiện phân tích, một nhà phát triển có thể báo cáo rằng việc thay đổi mã ít nhiều rủi ro bằng cách xem xét độ phức tạp của nó.

Vì vậy, có rất nhiều giá trị để đo lường độ phức tạp có thể được tận dụng và sử dụng cho mục đích ra quyết định.


1
Xin lỗi Ghost Cat trả lời rất giống nhau, nên đã làm mới trang.
Jon Raynor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.