วิธีการวนซ้ำลดความซับซ้อนของวงจรและปรับปรุงการสนับสนุนหรือไม่


11

วิธีการทำซ้ำอย่างเช่นพบได้ทั่วไปในภาษาสมัยใหม่เช่น C #, JavaScript และ (หวังว่า) ใน Java 8 ลดความซับซ้อนของวงจรที่มีต่อความเข้าใจและการสนับสนุนของโค้ดหรือไม่?

ตัวอย่างเช่นใน C # เราอาจมีรหัสต่อไปนี้:

List<String> filteredList = new List<String>();

foreach (String s in originalList){
   if (matches(s)){
      filteredList.add(s);
   }
}

สิ่งนี้มีความซับซ้อนตามวัฏจักรของ 2

เราสามารถเขียนใหม่นี้ได้อย่างง่ายดายในฐานะ:

List<String> filteredList = originalList.where(s => matches(s));

ซึ่งมีความซับซ้อนตามวัฏจักรของ 0

สิ่งนี้ส่งผลให้มีรหัสที่สนับสนุนได้จริงหรือไม่ มีการวิจัยจริงในหัวข้อนี้หรือไม่?


2
ชื่อของคุณถามเกี่ยวกับการลดความซับซ้อนของวัฏจักร แต่ข้อความของคุณถือว่าเป็นการลด CC และถามเกี่ยวกับการบำรุงรักษา นี่เป็นโอกาสที่จะเป็นคำถามที่มีค่าคุณสามารถแก้ไขชื่อให้มีความแม่นยำมากขึ้นได้หรือไม่
Kilian Foth

@KilianFoth ดีกว่าเหรอ?
C. Ross

ฉันจะเชื่อมโยงวิธีการวนซ้ำกับ metodologies ที่พัฒนาซ้ำ ๆ ฉันคิดว่าคำที่ดีกว่านี้จะเป็นฟังก์ชันที่มีลำดับสูงกว่า (และนอกเหนือจากกันเมธอดไม่มีชนิด return / void ขณะที่ฟังก์ชันส่งคืนบางสิ่ง)
โยฮันเนสรูดอล์ฟ

@JohannesRudolph "method ไม่มีประเภท return / void ในขณะที่ฟังก์ชั่นคืนค่าบางอย่าง" - ภาษานี้เป็นจริงหรือไม่? ฉันไม่เคยได้ยินสิ่งนี้ ในความเป็นจริงความแตกต่างที่แท้จริงเพียงอย่างเดียวที่ฉันเคยได้ยินคือวิธีการที่เกี่ยวข้องกับชั้นเรียนฟังก์ชั่นไม่ได้
ตกลง

คำตอบ:


14

ฉันเดาว่าคุณเพิ่งแบ่ง / ย้ายความซับซ้อน มันลดลงเพราะคุณไม่ได้นับการติดตั้ง.where()ใน CC ของคุณ

CC โดยรวมยังไม่ได้ย้ายจริงๆ CC ของตัวคุณเองลดลงเพราะตอนนี้มันถูกย้ายไปที่รหัสของเฟรมเวิร์ก

ฉันว่ามันบำรุงรักษาได้ดีกว่า เมื่อเป็นคุณสมบัติของภาษาให้ใช้ มันไม่ใช่"โอ๊ะฉันเข้าใจแล้วมันเป็นกลอุบายที่ฉลาด"ที่คุณใช้อยู่มีเพียงฟังก์ชั่นลดค่าอินไลน์ที่เรียบง่าย


11

สิ่งที่คุณกำลังทำอยู่คือการเน้นข้อบกพร่องในความซับซ้อนตามวัฏจักรเป็นตัวชี้วัดความซับซ้อนของรหัสไม่ได้เปลี่ยนไป คุณมีสาขาที่ชัดเจนในตัวอย่างแรกและต้องเข้าใจว่ามีสาขาที่ส่อให้เห็นในครั้งที่สอง ข้อที่สองชัดเจนและเข้าใจง่ายกว่าหากคุณเข้าใจไวยากรณ์และเนื่องจากใช้ไวยากรณ์พื้นฐานที่น้อยกว่าที่อาจเป็นปัญหา


1
ใคร ๆ ก็เถียงว่าความซับซ้อนของรหัสของตัวเองลดลงที่นี่เนื่องจากwhereที่นี่น่าจะมาจากกรอบ ฉันคิดว่าความซับซ้อนตามวัฏจักรในฐานะที่เป็นตัวชี้วัดมีประโยชน์แม้ที่นี่เพราะในขณะที่การแบ่งฟังก์ชั่นออกเป็นหลาย ๆ อย่างนั้นไม่ได้ลดความซับซ้อนโดยรวมของระบบ (แน่นอนมันเพิ่มบ่อยเพียงเล็กน้อย ชิ้นส่วนของระบบมีความซับซ้อนมากเกินไปและจำเป็นต้องถูกทำลายลง
ตกลง

6

เพื่อที่จะตอบคำถามอย่างเป็นกลางเราต้องการตัวชี้วัดบางอย่างเพื่อการบำรุงรักษา ความซับซ้อนตามวัฏจักรนั้นไม่ได้วัดจากความสามารถในการบำรุงรักษา แต่เป็นองค์ประกอบของตัวชี้วัดบางอย่างที่มีจุดประสงค์เพื่อวัดความสามารถในการบำรุงรักษา ตัวอย่างเช่นสูตรสำหรับดัชนีการบำรุงรักษาคือ:

MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC)

ที่Gเป็นความซับซ้อน cyclomatic ของรหัสในคำถาม ดังนั้นการลดความซับซ้อนของ cyclomatic ของชิ้นส่วนของรหัสทำได้โดยการนิยามปรับปรุงดัชนี Maintainability ของรหัสและตัวชี้วัดอื่น ๆ ที่คล้ายกันใช้ความซับซ้อนของวงจร

มันยากที่จะบอกได้ว่าชนิดของการเปลี่ยนแปลงที่คุณนำเสนอทำให้โปรแกรมดูเหมือนการบำรุงรักษามากขึ้นในการเขียนโปรแกรม; ที่น่าจะขึ้นอยู่กับวิธีที่คุ้นเคยพวกเขาจะมี (ในกรณีของคุณ) whereวิธี


คำเตือน: ตัวเลขเวทย์! (>_<)
Izkata

มีเพียงปัญหาเล็กน้อยเพียงข้อเดียวที่มีกับดัชนีการบำรุงรักษา ส่วนประกอบสามอย่างของมันคือ Halstead Volume, Cyclomatic Complexity และ Lines of Code ทั้ง Halstead Volume และ Cyclomatic Complexity นั้นมีความสัมพันธ์อย่างมากกับ Lines of Code ซึ่งหมายความว่าสมการทางเลือกโดยประมาณสำหรับดัชนีการบำรุงรักษาที่ขึ้นอยู่กับบรรทัดของรหัสเท่านั้นที่สามารถได้มาซึ่งเกือบจะแม่นยำเท่ากับต้นฉบับโดยมีความยากในการคำนวณน้อยกว่ามาก
John R. Strohm

@ JohnR.Strohm ฉันคิดว่าคุณจะได้รับผลลัพธ์ที่คล้ายกันแม้ว่าคุณจะใช้ LOC เป็นตัวชี้วัดการบำรุงรักษา การเปลี่ยนแปลงของ OP ลด LOC เป็น 1 จาก 4 และการเปลี่ยนแปลงอื่น ๆ ที่ลดความซับซ้อนของวัฏจักรมีแนวโน้มคล้ายกันที่จะลด LOC เช่นกัน ไม่ว่าจะด้วยวิธีใดมันจะลงมาถึงวิธีที่คุณกำหนดและวัดความสามารถในการบำรุงรักษา
คาเลบ

1
@Caleb: เห็นด้วย ประเด็นที่ฉันพยายามทำก็คือคนมักจะไปหาตัวชี้วัดที่ซับซ้อนจริง ๆ เหล่านี้และการรวมตัวชี้วัดต่าง ๆ โดยไม่รู้ตัวว่าพวกเขาทั้งหมดได้แสดงให้เห็นว่ามีความสัมพันธ์อย่างมากกับรหัสจริงกับบรรทัดเก่าของ LOC และดังนั้นจึงไม่มีค่าการทำนายหรืออธิบายมากกว่า LOC
John R. Strohm

3

เนื่องจากมันแสดงให้เห็นว่าความซับซ้อนของวงจร (CC) มีความสัมพันธ์อย่างมากกับขนาดรหัส "มากจน CC สามารถพูดได้ว่าไม่มีพลังในการอธิบายของตัวเอง" สิ่งที่คุณถามจริงๆคือ "วิธีการวนซ้ำเช่นที่พบได้ทั่วไปในภาษาสมัยใหม่เช่น C #, JavaScript และ (หวังว่า) ใน Java 8 จะลดผลกระทบของขนาดรหัสที่มีต่อความเข้าใจและการสนับสนุนของรหัส"

ณ จุดนี้ใครจะหวังว่าคำตอบจะชัดเจน เป็นที่ทราบกันมานานหลายทศวรรษแล้วว่ารหัสที่สั้นกว่านั้นโดยทั่วไปนั้นง่ายต่อการเข้าใจบำรุงรักษาและสนับสนุน


2

หากคุณกำลังพูดถึงสถิติดิบของ Cyclomatic Complexity แน่นอน คุณเพิ่ง nuked จาก 2 ถึง 0 ถ้าคุณไปโดยตัวเลขกำไรบริสุทธิ์ตลอดทาง

จากมุมมองที่ใช้งานได้จริง (อ่าน: มนุษย์) ฉันขอยืนยันว่าคุณเพิ่มความซับซ้อนได้จริง ๆ2 จุดหนึ่งที่มาจากความจริงที่ว่าตอนนี้โปรแกรมเมอร์อื่น ๆ บางคนต้องนำหรือรับความรู้เกี่ยวกับไวยากรณ์ได้อย่างคล่องแคล่ว LINQ รหัส.

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

กรณีนี้การใช้งานa.where(x => matches(x, arg))ไม่น่ากลัวและในความซื่อสัตย์เป็นวิธีที่ดีในการให้ผู้ร่วมงานได้เห็นและทำงานกับการแสดงออกของ LINQ และแลมบ์ดาเป็นครั้งแรก และชุดโค้ดอื่น ๆ เพื่อผลที่ยอดเยี่ยม) อย่างไรก็ตามการใช้สิ่งเหล่านี้ต้องการความรู้บางอย่าง

ฉันขอแนะนำอย่างระมัดระวังเพราะฉันเห็นกรณีที่ LINQ refactor นั้นแย่กว่าการอ่านมากกว่าforeachลูปนั้น


1

มันขึ้นอยู่กับผู้ชมผู้พัฒนาหากพวกเขาเข้าใจการแสดงออกแลมบ์ดาแล้ว

List<String> filteredList = originalList.where(s => matches(s));

เข้าใจได้เร็วกว่าและง่ายกว่าเล็กน้อย ฉันจะกังวลมากขึ้นเกี่ยวกับการใช้ s และการจับคู่ () ไม่สามารถอธิบายตัวเองได้

List<String> filteredList = 
    originalList.where(stringToBeTested => matchesNameTest(stringToBeTested));

หรือ

List<String> filteredList = 
        originalList.where(originalListString => matchesNameTest(originalListString));

ช่วยให้นักพัฒนามีข้อมูลที่มีความหมายมากขึ้นและง่ายต่อการวิเคราะห์โดยไม่ต้องดำน้ำในฟังก์ชั่นการจับคู่ () เพื่อกำหนดว่าจะทำการแข่งขันใด

ความสามารถในการบำรุงรักษาไม่เพียง แต่เกี่ยวกับความสามารถในการเข้าใจรหัสเท่านั้น แต่ยังเกี่ยวกับความเร็วและความแม่นยำซึ่งส่วนใหญ่สามารถเข้าใจรหัสได้


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