ความซับซ้อนของวงจรเมื่อเรียกวิธีเดียวกันหลาย ๆ ครั้ง


12

ขอบคุณสำหรับคำถามที่รีวิวรหัสฉันได้มีความขัดแย้งเล็กน้อย (ซึ่งเป็นโอกาสที่จะเรียนรู้บางสิ่งบางอย่าง) เกี่ยวกับสิ่งที่ซับซ้อน Cyclomatic สำหรับรหัสด้านล่าง

public static void main(String[] args) {
    try {
        thro();
        thro();
        thro();
        thro();
        thro();
        thro();
        thro();
    }
    catch (NullPointerException e) {
    }
}

private static Random random = new Random();

public static void thro() throws NullPointerException {
    if (random.nextBoolean())
        throw new NullPointerException();
    System.out.println("No crash this time");
}

เมื่อเขียนโค้ดนี้ใน Eclipse และใช้ปลั๊กอินตัวชี้วัด Eclipseมันจะบอกฉันว่า McCabe Cyclomatic Complexity สำหรับวิธีหลักคือ 2 และสำหรับthroวิธีที่มันบอกว่า 2

อย่างไรก็ตามมีคนอื่นบอกฉันว่าความซับซ้อนของการโทรthroหลายครั้งคือnumber of calls * method complexityและดังนั้นจึงอ้างว่าความซับซ้อนของวิธีการหลักคือ 7 * 2 = 14

เราวัดสิ่งต่าง ๆ หรือไม่? เราทั้งคู่สามารถแก้ไขได้ไหม? หรือความซับซ้อนตามวัฏจักรจริงคืออะไรที่นี่?


5
CC ของฟังก์ชันคือสองเนื่องจากมีเพียงสองเส้นทางผ่าน CC ของโปรแกรมสูงขึ้น นี่คือการแทงแบบสมบูรณ์ในที่มืด แต่ฉันคิดว่าซอฟต์แวร์การวิเคราะห์รหัสใช้แต่ละฟังก์ชั่นเป็นกล่องดำแยกต่างหากเนื่องจากความไม่สามารถในการคำนวณ CC ของแอปพลิเคชันที่ซับซ้อนทั้งหมดในครั้งเดียว
Phoshi

@Phoshi หากคุณจะเขียนว่าเป็นคำตอบและ (ถ้าเป็นไปได้) ให้ลิงค์ที่แสดงว่ามีการแยกของทั้งสองฉันยินดีที่จะยอมรับคำตอบนั้น
Simon Forsberg

หากคุณนับเส้นทางทั้งหมดที่เกิดจากข้อยกเว้นที่เป็นไปได้ในการวัดค่า CC พระเจ้าช่วยให้ผู้ที่ถามคำถามเกี่ยวกับการเปลี่ยนรหัสเล็กน้อยเพื่อรับหมายเลขที่ต่ำกว่า 10
mattnz

คำตอบ:


9

เมื่อฉันเข้าใจสิ่งนี้อย่างถูกต้องความซับซ้อน Cyclomaticของmainคือ 8 - นั่นคือจำนวนของเส้นทางที่เป็นอิสระเชิงเส้นผ่านรหัส คุณอาจได้รับข้อยกเว้นหนึ่งในเจ็ดบรรทัดหรือไม่มีเลย แต่ไม่มีมากกว่าหนึ่งบรรทัด แต่ละ "จุดยกเว้น" ที่เป็นไปได้นั้นสอดคล้องกับเส้นทางที่แตกต่างกันหนึ่งเส้นทางผ่านรหัส

ฉันเดาว่าเมื่อ McCabe คิดค้นเมตริกนั้นเขาไม่มีภาษาการเขียนโปรแกรมยกเว้นการจัดการในใจ


แต่มันเป็นสิ่งสำคัญจริง ๆ ของบรรทัดที่โยนข้อยกเว้นหรือไม่
Simon Forsberg

5
@ SimonAndréForsberg: ใช่แล้ว คิดว่า "thro" มีผลข้างเคียงที่จะเพิ่มตัวนับทั่วโลกเมื่อมันถูกเรียก (ที่จะไม่เปลี่ยนเส้นทางที่เป็นไปได้ผ่านรหัส) ผลลัพธ์ที่เป็นไปได้ของตัวนับนั้นคือ 0 ถึง 7 ดังนั้นนี่จึงพิสูจน์ว่า CC นั้นอย่างน้อย 8
Doc Brown เมื่อ

คุณจะบอกว่าปลั๊กอินตัวชี้วัดที่ฉันใช้กำลังรายงานค่าที่ไม่ถูกต้องสำหรับmainวิธีการหรือไม่
Simon Forsberg

@ SimonAndréForsberg: ดีฉันไม่รู้จักปลั๊กอินตัวชี้วัดของคุณ แต่ 2 ไม่ชัดเจน 8
Doc Brown

มีการเชื่อมโยงตัวชี้วัดเป็นปลั๊กอินในคำถามของฉัน ....
ไซมอน Forsberg

6

เป็น 'คนอื่น' ฉันจะตอบที่นี่และแม่นยำเกี่ยวกับสิ่งที่ฉันพูด (ซึ่งฉันไม่แม่นยำโดยเฉพาะกับรูปแบบอื่น ๆ )

จากการใช้ตัวอย่างรหัสด้านบนฉันคำนวณความซับซ้อนของวัฏจักรเป็น 8 และฉันมีความคิดเห็นในรหัสเพื่อแสดงวิธีการคำนวณ เพื่ออธิบายเส้นทางฉันจะพิจารณาการวนลูปที่สำเร็จผ่านการเรียกทั้งหมดthro()เป็น 'main' 'code path' (หรือ 'CP = 1'):

public static void main(String[] args) {
  try {
             // This is the 'main' Code Path: CP = 1
    thro();  // this has a branch, can succeed CP=1 or throw CP=2
    thro();  // this has a branch, can succeed CP=1 or throw CP=3
    thro();  // this has a branch, can succeed CP=1 or throw CP=4
    thro();  // this has a branch, can succeed CP=1 or throw CP=5
    thro();  // this has a branch, can succeed CP=1 or throw CP=6
    thro();  // this has a branch, can succeed CP=1 or throw CP=7
    thro();  // this has a branch, can succeed CP=1 or throw CP=8
  }
  catch (NullPointerException e) {
  }
}

ดังนั้นฉันนับ 8 เส้นทางรหัสในวิธีการหลักนี้ซึ่งสำหรับฉันคือความซับซ้อน Cyclomatic ของ 8

ในแง่ของจาวาแต่ละกลไกสำหรับการออกจากฟังก์ชั่นจะนับว่ามีความซับซ้อนดังนั้นวิธีการที่มีสถานะความสำเร็จและอาจเกิดข้อยกเว้นได้ถึง 3 ข้อยกเว้นมี 4 เส้นทางที่มีการบันทึกไว้

ความซับซ้อนของวิธีการที่เรียกใช้ฟังก์ชันดังกล่าวคือ:

CC(method) = 1 + sum (methodCallComplexity - 1)

ฉันคิดว่าสิ่งอื่น ๆ ที่ต้องพิจารณาคือในความคิดของฉันcatchประโยคไม่ได้มีส่วนช่วยในความซับซ้อนของวิธีการcatchนั้นเป็นเพียงเป้าหมายของthrowsสาขาและทำให้บล็อกที่เป็นเป้าหมายของการthrowนับหลายครั้ง 1 สำหรับแต่ละคนthrowและไม่ใช่แค่ครั้งเดียวสำหรับทุกสิ่ง


คุณนับสาขาที่เป็นไปได้สำหรับ OutOfMemoryExceptions ด้วยหรือไม่ ฉันหมายถึงคนอวดดีที่พวกเขาสามารถทำให้เกิดรหัสสาขา แต่ไม่มีใครนับพวกเขาในขณะที่พวกเขาเจือจางประโยชน์ของการวัด
Telastyn

ไม่ฉันไม่ใช่ ... และคุณพูดถูก แต่ในบริบทของการโต้เถียงฉันนับเฉพาะข้อยกเว้นที่มีการประกาศวิธีการโยน นอกจากนี้หากวิธีหนึ่งประกาศข้อยกเว้นสามข้อ แต่รหัส callinch นั้นเป็นวิธีที่catch (Throwable t) {...ฉันคิดว่ามันไม่สำคัญว่าจะมีข้อยกเว้นจำนวนเท่าใดที่ประกาศว่าจะโยน
rolfl
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.