ทำความเข้าใจกับความซับซ้อนของวัฏจักร


11

ฉันเพิ่งเจอCyclomatic Complexityและฉันต้องการพยายามทำความเข้าใจให้ดีขึ้น

อะไรคือตัวอย่างการเขียนโปรแกรมเชิงปฏิบัติของปัจจัยต่าง ๆ ที่นำไปสู่การคำนวณความซับซ้อน โดยเฉพาะสำหรับสมการวิกิพีเดียM = E − N + 2Pฉันต้องการเข้าใจความหมายของคำศัพท์แต่ละข้อต่อไปนี้ให้ดีขึ้น:

  • E = จำนวนขอบของกราฟ
  • N = จำนวนโหนดของกราฟ
  • P = จำนวนขององค์ประกอบที่เชื่อมต่อ

ฉันสงสัยว่าทั้งEหรือNอาจเป็นจำนวนคะแนนการตัดสินใจ (ถ้า, ถ้า, สำหรับ, foreach, ฯลฯ ) ในบล็อกของรหัส แต่ฉันไม่แน่ใจว่าที่ใดหรือสิ่งอื่น ๆ ที่มีความหมาย ฉันเดาด้วยว่าPหมายถึงการเรียกใช้ฟังก์ชั่นและอินสแตนซ์ของคลาส แต่ไม่มีคำจำกัดความที่ชัดเจนที่ฉันเห็น หากใครบางคนสามารถส่องแสงเพิ่มอีกนิดด้วยตัวอย่างโค้ดที่ชัดเจนของแต่ละอันมันจะช่วยได้

จากการติดตาม Cyclomatic Complexity มีความสัมพันธ์โดยตรงกับจำนวนการทดสอบหน่วยที่จำเป็นสำหรับการครอบคลุมเส้นทาง 100% หรือไม่? ตัวอย่างเช่นวิธีการที่มีความซับซ้อน 4 บ่งบอกว่าจำเป็นต้องมีการทดสอบ 4 บทเพื่อครอบคลุมวิธีการดังกล่าวหรือไม่?

ในที่สุดการแสดงออกปกติส่งผลกระทบต่อความซับซ้อนของวัฏจักรและถ้าเป็นเช่นนั้นได้อย่างไร


ฉันพบว่าคุณสามารถรับเอกสารต้นฉบับโดย McCabe จาก Wikipedia และ Google Books จะให้หนังสือที่ McCabe ใช้สำหรับบทความต้นฉบับของเขา ที่น่าสนใจคุณจะพบว่า McCabe ใช้ทฤษฎีบทเดิมอย่างผิด ๆ (และอธิบายอย่างสับสนในขณะที่เขาควรเริ่มต้นด้วยกราฟที่ไม่ได้บอกทิศทางและไม่จำเป็นต้องเชื่อมโยงอย่างแน่นหนาในตอนแรก) แต่ตัวเลขออกมาอย่างถูกต้องแล้ว ( สูตรที่ถูกต้องน่าจะเป็น M = E + 1-N + P แต่เมื่อ P อยู่เสมอ 1 มันเข้ากันได้ ... ) ความคิดที่เกิดขึ้นในปัจจุบัน "การจัดการข้อยกเว้น" ขว้างประแจเข้าไปในผลงานของตัวชี้วัดนั้น
David Tonhofer

... และสิ่งที่เกี่ยวกับการโทรซ้ำ (อาจผ่านฟังก์ชั่นโซ่) กราฟฟิคชั่นหนึ่งทำงานหรือไม่? แล้วโอเปอเรเตอร์บูลีนที่ลัดวงจรก็เช่น "&&" ผู้ประกอบการที่ได้รับการปกป้องเช่น "ref? .x" ซึ่งให้ผลเป็น Null หากอ้างอิงเป็น Null โอ้มันเป็นเพียงการวัดอื่น แต่มีงานบางอย่างสำหรับโครงการมหาวิทยาลัยเล็ก ๆ ที่นี่
David Tonhofer

คำตอบ:


8

เกี่ยวกับสูตร: โหนดแสดงสถานะขอบแทนการเปลี่ยนแปลงสถานะ ในทุกโปรแกรมข้อความสั่งจะมีการเปลี่ยนแปลงในสถานะของโปรแกรม แต่ละคำสั่งที่ต่อเนื่องกันจะถูกแทนด้วยขอบและสถานะของโปรแกรมหลังจาก (หรือก่อนหน้า ... ) การดำเนินการของคำสั่งนั้นคือโหนด

หากคุณมีคำสั่งการแยกสาขา ( ifเช่น) - คุณมีสองโหนดที่ออกมาเนื่องจากสถานะสามารถเปลี่ยนแปลงได้สองวิธี

อีกวิธีหนึ่งในการคำนวณ Cyclomatic Complexity Number (CCN) คือการคำนวณ "ภูมิภาค" ในกราฟการดำเนินการที่คุณมี (โดยที่ "ภูมิภาคอิสระ" เป็นวงกลมที่ไม่มีวงกลมอื่น) ในกรณีนี้ CCN จะเป็นหมายเลขของภูมิภาคอิสระบวก 1 (ซึ่งจะเป็นหมายเลขเดียวกับสูตรก่อนหน้านี้ที่ให้คุณ)

CCN ใช้สำหรับการครอบคลุมการแยกย่อยหรือการครอบคลุมพา ธซึ่งเหมือนกัน CCN เท่ากับจำนวนของการแยกเส้นทางที่แตกต่างกันตามเหตุผลทางทฤษฎีที่เป็นไปได้ในแอปพลิเคชันเธรดเดียว (ซึ่งอาจรวมถึงสาขาเช่น " if x < 2 and x > 5 then" แต่ควรถูกคอมไพเลอร์ที่ดีเป็นรหัสที่เข้าถึงไม่ได้) คุณต้องมีอย่างน้อยจำนวนกรณีทดสอบที่แตกต่างกัน (อาจมากกว่าเพราะกรณีทดสอบบางกรณีอาจทำซ้ำเส้นทางที่ครอบคลุมโดยก่อนหน้านี้ แต่ไม่น้อยกว่าสมมติว่าแต่ละกรณีครอบคลุมเส้นทางเดียว) ถ้าคุณไม่สามารถครอบคลุมเส้นทางกับกรณีทดสอบที่เป็นไปได้ใด ๆ - คุณพบรหัสเข้าไม่ถึง (แม้ว่าคุณจะต้องจริงพิสูจน์กับตัวเองว่าทำไมมันเป็นเรื่องที่ไม่สามารถเข้าถึงอาจจะเป็นบางอย่างที่ซ้อนกันx < 2 and x > 5ที่ซุ่มซ่อนอยู่ที่ไหนสักแห่ง)

สำหรับนิพจน์ทั่วไป - แน่นอนว่ามันมีผลกับโค้ดอื่น ๆ อย่างไรก็ตาม CCN ของโครงสร้าง regex อาจสูงเกินกว่าที่จะครอบคลุมในการทดสอบหน่วยเดียวและคุณสามารถสันนิษฐานได้ว่าเอ็นจิ้น regex ได้รับการทดสอบแล้วและไม่สนใจศักยภาพการแยกสาขาของนิพจน์สำหรับความต้องการในการทดสอบของคุณ แน่นอนว่า regex engine)


2
+1: จริง ๆ แล้วคุณต้องเชื่อมั่นว่าเครื่องมือ regex ได้รับการทดสอบแล้ว ถ้าคุณไม่ไว้วางใจได้รับหนึ่งที่คุณทำไว้วางใจ
S.Lott

"การ CCN เท่ากับจำนวนเส้นทางการดำเนินการที่แตกต่างกันไปได้ในการประยุกต์ใช้เกลียวเดียว"นี้เป็นธรรมเป็น CCN จะขึ้นอยู่เพียงแค่ในรหัสของโครงสร้างที่ไม่ได้อยู่ในระดับที่มีความหมาย เปอร์เซ็นต์ที่ดีของเส้นทางเหล่านี้อาจเป็นไปไม่ได้ที่จะออกกำลังกายเนื่องจากพวกเขาต้องการสถานะอินพุตที่ไม่สามารถตั้งค่าได้ ( ตัวอย่างเช่นxบาง5 และน้อยกว่า 2 ตัวอย่าง) ตรงไปตรงมาฉันคิดว่าการใช้ CCN ในการตัดสินใจเกี่ยวกับกรณีทดสอบเพื่อเรียกใช้นั้นเป็นสิ่งที่ผิดปกติ CCN เป็นตัวเลขที่บอกนักพัฒนา "คุณอาจไปที่นี่มากเกินไปโปรดพิจารณาการปรับโครงสร้างใหม่" และถึงตอนนั้นอาจมีเหตุผลที่ดีสำหรับ CCN ที่สูง
David Tonhofer

1
@David ได้เพิ่มประโยคเพื่อพูดว่า CCN เป็นสาขาครอบคลุมและไม่มีเหตุผลที่ดีสำหรับ CCN สูงในระดับที่ต่ำกว่า (โดยทั่วไปฉันขอแนะนำให้บังคับใช้ต่อฟังก์ชันแต่ละฟังก์ชัน)
littleadv

ความครอบคลุมสาขาและความครอบคลุมเส้นทางไม่เหมือนกัน ครอบคลุมสาขาทั้งหมดครอบคลุมทุกสาขาในขณะที่ครอบคลุมเส้นทางทั้งหมดครอบคลุมสาขาทั้งหมด
mouviciel

13

ข้อสังเกตบางอย่างเกี่ยวกับเรื่องนี้ที่ฉันเขียนขึ้นอย่างเฉยเมย ...

โดยเฉพาะสำหรับสมการวิกิพีเดียของ M = E - N + 2P

สมการที่เป็นมากผิดปกติ

ด้วยเหตุผลบางอย่าง McCabe ใช้มันจริงในกระดาษต้นฉบับของเขา("การวัดความซับซ้อน", ธุรกรรม IEEE ในวิศวกรรมซอฟต์แวร์, Vo .. SE-2, ฉบับที่ 4, ธันวาคม 1976) แต่ไม่มีเหตุผลที่เหมาะสมและหลังจากอ้างถึงความถูกต้องจริง สูตรในหน้าแรกซึ่งก็คือ

v (G) = e - v + p

(ที่นี่องค์ประกอบสูตรได้รับการติดฉลากใหม่)

โดยเฉพาะ McCabe อ้างอิงหนังสือC.Berge, กราฟและไฮเปอร์กราฟ (ตัวย่อด้านล่างเพื่อ G&HG) โดยตรงจากหนังสือเล่มนั้น :

คำจำกัดความ (หน้า 27 ด้านล่างของ G&HG):

หมายเลข cyclomatic v (G) ของกราฟ (undirected) G (ซึ่งอาจมีส่วนประกอบที่ไม่ได้เชื่อมต่ออยู่หลายตัว) ถูกกำหนดเป็น:

v (G) = e - v + p

โดยที่ e = จำนวนของขอบ, v = จำนวนของจุดยอด, p = จำนวนของส่วนประกอบที่เชื่อมต่อ

ทฤษฎีบท (หน้า 29 บนของ G&HG) (ไม่ได้ใช้โดย McCabe):

จำนวนรอบที่ v (G) ของกราฟ G เท่ากับจำนวนรอบสูงสุดที่เป็นอิสระ

วงจรเป็นลำดับของจุดเริ่มต้นและสิ้นสุดที่จุดสุดยอดเดียวกันกับแต่ละจุดสองติดต่อกันในลำดับที่อยู่ติดกับแต่ละอื่น ๆ ในกราฟ

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

ทฤษฎีบท (หน้า 29 กลางของ G&HG) (ตามที่ใช้โดย McCabe):

ในกราฟที่เชื่อมต่ออย่างยิ่ง G หมายเลข cyclomatic เท่ากับจำนวนสูงสุดของวงจรอิสระเชิงเส้น

วงจรคือวงจรที่ไม่มีการเกิดซ้ำของจุดและขอบได้รับอนุญาต

กราฟที่บอกทิศทางได้รับการกล่าวถึงว่ามีการเชื่อมต่ออย่างแน่นหนาหากจุดสุดยอดทุกจุดสามารถเข้าถึงได้จากจุดสุดยอดอื่น ๆ ทุกจุดโดยผ่านขอบในทิศทางที่กำหนด

โปรดทราบว่าที่นี่เราส่งผ่านจากกราฟไม่มีทิศทางที่จะกราฟเชื่อมต่ออย่างยิ่ง (ซึ่งเป็นผู้กำกับ ... แบร์กไม่ได้ทำเรื่องนี้ให้ชัดเจน)

McCabe ใช้ทฤษฎีบทข้างต้นเพื่อหาวิธีง่าย ๆ ในการคำนวณ“ McCabe Cyclomatic Complexity Number” (CCN) ดังนี้:

กำหนดกราฟเป็นตัวแทนของ“กระโดดโครงสร้าง” ของกระบวนการ (กราฟการเรียนการสอนการไหล) กับจุดสุดยอดที่กำหนดเป็นตัวแทนของที่ไม่ซ้ำกันจุดเริ่มต้นและจุดสุดยอดที่กำหนดเป็นตัวแทนของที่ไม่ซ้ำกันออกจากจุด (จุดจุดสุดยอดทางออกอาจต้องมีการ“สร้าง” โดยการเพิ่มในกรณีที่มีการส่งคืนหลายครั้ง) สร้างกราฟที่เชื่อมต่ออย่างยิ่งโดยการเพิ่มขอบกำกับจากจุดยอดออกไปยังจุดเข้าจุดสุดยอดจึงทำให้จุดยอดสามารถเข้าถึงได้จากจุดสุดยอดอื่น ๆ

ตอนนี้ McCabe posits (ค่อนข้างสับสนฉันอาจจะบอกว่า) จำนวนรอบของกราฟการไหลของคำสั่งที่ปรับเปลี่ยน "สอดคล้องกับแนวคิดที่เข้าใจง่ายของเราเกี่ยวกับ 'จำนวนเส้นทางขั้นต่ำ'" และเราจะใช้จำนวนนั้นเป็นมาตรวัดความซับซ้อน

เจ๋งดังนั้น:

จำนวนความซับซ้อนตามวัฏจักรของกราฟการสอนที่ปรับเปลี่ยนสามารถกำหนดได้โดยการนับวงจร "ที่เล็กที่สุด" ในกราฟที่ไม่ได้บอกทิศทาง นี่ไม่ใช่เรื่องยากที่จะทำโดยคนหรือเครื่องจักร แต่การใช้ทฤษฎีบทข้างต้นทำให้เรามีวิธีที่ง่ายยิ่งขึ้นในการพิจารณา:

v (G) = e - v + p

ถ้าใครไม่สนใจทิศทางของขอบ

ในทุกกรณีเราเพียงแค่พิจารณาขั้นตอนเดียวดังนั้นจึงมีองค์ประกอบเชื่อมต่อเพียงหนึ่งเดียวในกราฟทั้งหมดและดังนั้น:

v (G) = e - v + 1

ในกรณีที่พิจารณากราฟต้นฉบับโดยไม่มีขอบ "exit-to-entry" ที่เพิ่มเข้ามาหนึ่งจะได้รับเพียง:

ṽ (G) = ẽ - v + 2

เป็นẽ = e - 1

ลองอธิบายโดยใช้ตัวอย่างของ McCabe จากกระดาษของเขา:

ตัวอย่างของ McCabe

ที่นี่เรามี:

  • e = 10
  • v = 6
  • p = 1 (องค์ประกอบเดียว)
  • v (G) = 5 (เรานับอย่างชัดเจน 5 รอบ)

สูตรสำหรับหมายเลขที่เป็นวงกลมกล่าวว่า:

v (G) = e - v + p

ซึ่งให้ผลตอบแทน 5 = 10 - 6 + 1 และถูกต้อง!

"จำนวนความซับซ้อนของวัฏจักร McCabe" ตามที่ระบุในเอกสารของเขาคือ

5 = 9 - 6 + 2 (ไม่มีคำอธิบายเพิ่มเติมในบทความเกี่ยวกับวิธีการ)

ซึ่งเกิดขึ้นถูกต้อง (ให้ผล v (G)) แต่ด้วยเหตุผลที่ไม่ถูกต้องนั่นคือเราใช้:

ṽ (G) = ẽ - v + 2

ดังนั้นṽ (G) = v (G) ... วุ้ย!

แต่นี่เป็นการวัดที่ดีหรือไม่?

ในสองคำ: ไม่มาก

  • ยังไม่ชัดเจนว่าจะสร้าง "กราฟการไหลของคำสั่ง" ของกระบวนการได้อย่างไรโดยเฉพาะอย่างยิ่งหากมีข้อยกเว้นในการจัดการและการเรียกซ้ำเข้าไปในรูปภาพ โปรดทราบว่า McCabe ใช้แนวคิดของเขาในการเขียนโค้ดในFORTRAN 66ซึ่งเป็นภาษาที่ไม่มีการเรียกซ้ำไม่มีข้อยกเว้นและโครงสร้างการดำเนินการที่ตรงไปตรงมา
  • ความจริงที่ว่ากระบวนการที่มีการตัดสินใจและขั้นตอนที่มีการวนซ้ำทำให้ CCN เดียวกันนั้นไม่ใช่สัญญาณที่ดี

ป้อนคำอธิบายรูปภาพที่นี่


1
@ JayElston จับได้ดี แน่นอนฉันทำ แก้ไขแล้ว!
David Tonhofer

1
+1 ยิ่งใหญ่สำหรับการเชื่อมโยงไปยังกระดาษต้นฉบับ เอกสารจำนวนมากที่เขียนในเวลานั้นสามารถอ่านได้สำหรับโปรแกรมเมอร์ระดับกลางและควรอ่าน
Daniel T.

1

จากการติดตาม Cyclomatic Complexity มีความสัมพันธ์โดยตรงกับจำนวนการทดสอบหน่วยที่จำเป็นสำหรับการครอบคลุมเส้นทาง 100% หรือไม่?

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

ในที่สุดการแสดงออกปกติส่งผลกระทบต่อความซับซ้อนของวัฏจักรและถ้าเป็นเช่นนั้นได้อย่างไร

ใช่ถ้าคุณต้องการที่จะแน่นอนแม้ว่าเครื่องมือวิเคราะห์รหัสส่วนใหญ่จะไม่นำมาพิจารณาด้วยวิธีการดังกล่าว นิพจน์ปกติเป็นเพียงเครื่อง จำกัด แน่นอนดังนั้นฉันเดาว่า CC ของพวกเขาสามารถคำนวณได้จากกราฟ FSM แต่มันจะค่อนข้างมาก


+1 - ฉันเดาว่าการคำนวณ CC สำหรับ RegExes ไม่ใช่เรื่องสนุก
VirtuosiMedia
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.