มันสมเหตุสมผลหรือไม่ที่ refactor จะจบลงด้วย LOC ที่สูงขึ้น? [ปิด]


25

มีกรณีที่รหัส verbose เพิ่มเติม (ในงบตรรกะมากขึ้น) จะสะอาดกว่ารหัสรัดกุมมากขึ้น?



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

5
"รหัสกระชับมากขึ้น"? ฉันเกลียดความเชื่อที่เข้าใจผิดว่าการนับบรรทัดที่น้อยกว่าหมายถึงรหัส "ดีกว่า" มันไม่ได้ ในความเป็นจริงมันมักจะตรงกันข้าม มีจุดมาถึงแล้ว - และมันก็มาถึงเร็วมาก - ซึ่งการยัดเยียดความหมายมากขึ้นเรื่อย ๆ เข้าไปในพื้นที่ที่น้อยลงทำให้รหัสนั้นยากที่จะเข้าใจ ในความเป็นจริงมีการแข่งขันทั้งหมด - การประกวด C International Obfuscated Cซึ่งผู้ชนะหลายคนใช้ข้อ จำกัด ของความเข้าใจของมนุษย์ในการเขียนรหัสที่ไม่ยอมรับ
Andrew Henle

1
ชื่อคำถามและคำถามของคุณเองกำลังถามคำถามที่แตกต่างกัน ตัวอย่างเช่นคำสั่ง if สามารถเปลี่ยนเป็นนิพจน์ประกอบไปด้วยซึ่งเป็นเหตุผลเดียวกัน แต่มีเพียง 1 บรรทัด
Captain Man

1
-1 *** รหัส verbose มากขึ้น (ในงบตรรกะเพิ่มเติม) *** verbosity และจำนวนงบตรรกะเป็นสองสิ่งที่ไม่เกี่ยวข้อง รูปแบบที่ไม่ดีคือการเปลี่ยนคำจำกัดความ
Pieter B

คำตอบ:


71

เพื่อที่จะตอบคำถามนี้ขอยกตัวอย่างโลกแห่งความจริงที่เกิดขึ้นกับฉัน ใน C # ห้องสมุดที่ฉันรักษาฉันมีรหัสต่อไปนี้:

TResult IConsFuncMatcher<T, TResult>.Result() =>
    TryCons(_enumerator) is var simpleMatchData && !simpleMatchData.head.HasValue
        ? _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
        : _recursiveConsTests.Any() 
            ? CalculateRecursiveResult() 
            : CalculateSimpleResult(simpleMatchData);

การอภิปรายเรื่องนี้กับเพื่อนร่วมงานผู้ตัดสินเป็นเอกฉันท์ก็คือการแสดงออกที่ไตรภาคซ้อนกันควบคู่ไปกับการใช้ "ฉลาด" ของis varผลในการกระชับ แต่ยากที่จะอ่านรหัส

ดังนั้นฉัน refactored มันไปที่:

TResult IConsFuncMatcher<T, TResult>.Result()
{
    var simpleMatchData = TryCons(_enumerator);

    if (!simpleMatchData.head.HasValue)
    {
        return _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
    }

    return _recursiveConsTests.Any() 
        ? CalculateRecursiveResult() 
        : CalculateSimpleResult(simpleMatchData);
}

returnรุ่นเดิมที่มีอยู่เพียงหนึ่งการแสดงออกของสารประกอบที่มีนัย รุ่นใหม่ในขณะนี้มีการประกาศตัวแปรอย่างชัดเจนเป็นคำสั่งและสองอย่างชัดเจนif returnsมันมีงบมากขึ้นและบรรทัดของรหัสมากขึ้น แต่ทุกคนที่ฉันปรึกษาพิจารณาว่าอ่านง่ายและมีเหตุผลซึ่งเป็นประเด็นสำคัญของ "โค้ดที่ชัดเจน"

ดังนั้นคำตอบสำหรับคำถามของคุณคือการเน้นว่า "ใช่" verbose มากขึ้นสามารถสะอาดกว่ารหัสรัดกุมและจึงเป็น refactoring ที่ถูกต้อง


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

2
@anaximander เห็นด้วยอย่างยิ่ง เขียนโค้ดเพื่อให้ผู้อื่นอ่านก่อนและคอมไพเลอร์ที่สอง นี่คือเหตุผลที่ฉันพบว่ามีประโยชน์ที่จะให้คนอื่นตรวจสอบรหัสของฉันแม้ว่าฉันจะเป็นคนเดียวที่พัฒนามัน
David Arno

4
หากฉันกำลังตรวจสอบสิ่งนั้นฉันจะแนะนำให้ย้อนกลับลำดับของข้อความสั่งการส่งคืนและนำ!เงื่อนไขออก elseฉันยังอยากจะแนะนำให้ใส่ผลตอบแทนที่สองใน แต่ถึงกระนั้นมันก็เป็นการปรับปรุงที่ยิ่งใหญ่
Martin Bonner สนับสนุนโมนิก้า

2
@DavidArno ฉันเห็นว่าตรรกะและถ้าif (!foo.HasValue)เป็นสำนวนในรหัสของคุณมากยิ่งขึ้นดังนั้น แต่ifไม่ได้จริงๆทางออกต้น - มันเป็น "การทำเช่นนี้หรือว่าขึ้นอยู่."
Martin Bonner สนับสนุนโมนิก้า

2
@fabric การเปรียบเทียบค่าบูลีนเป็นสิ่งที่อันตราย ฉันหลีกเลี่ยงมันให้มากที่สุด
Martin Bonner สนับสนุน Monica

30

1. การขาดความสัมพันธ์ระหว่าง LOC และคุณภาพของรหัส

เป้าหมายของการปรับโครงสร้างใหม่คือการปรับปรุงคุณภาพของรหัส

LOC เป็นตัวชี้วัดพื้นฐานที่บางครั้งมีความสัมพันธ์กับคุณภาพของรหัส: ตัวอย่างเช่นวิธีการที่มี LOC สองสามพันคนน่าจะมีปัญหาด้านคุณภาพ อย่างไรก็ตามควรสังเกตว่า LOC ไม่ใช่ตัวชี้วัดเพียงอย่างเดียวและในหลายกรณีขาดความสัมพันธ์กับคุณภาพ ตัวอย่างเช่นวิธี 4 LOC ไม่จำเป็นต้องสามารถอ่านได้มากกว่าหรือสามารถบำรุงรักษาได้มากกว่าวิธี 6 LOC

2. เทคนิคการสร้างโครงสร้างใหม่ประกอบด้วยการเพิ่ม LOCs

หากคุณใช้รายการของเทคนิคการรีแฟคเตอร์คุณสามารถมองเห็นเทคนิคที่รวมอยู่ในการเพิ่ม LOCs โดยเจตนา ตัวอย่าง:

  • แทนที่เวทย์จำนวนที่มีสัญลักษณ์คง
  • สารสกัดจากตัวแปร

ทั้งสองเป็นเทคนิคการรีแฟคเตอร์ที่มีประโยชน์มากและผลกระทบต่อ LOC นั้นไม่เกี่ยวข้องอย่างสมบูรณ์เมื่อพิจารณาว่าจะใช้หรือไม่

หลีกเลี่ยงการใช้ LOC

LOC เป็นตัวชี้วัดที่อันตราย ง่ายต่อการวัดและยากที่จะตีความอย่างถูกต้อง

จนกว่าคุณจะคุ้นเคยกับเทคนิคการวัดคุณภาพของรหัสให้พิจารณาหลีกเลี่ยงการวัด LOC ตั้งแต่แรก ส่วนใหญ่คุณจะไม่ได้รับอะไรที่เกี่ยวข้องและอาจมีบางกรณีที่จะทำให้คุณเข้าใจผิดในการลดคุณภาพของรหัสของคุณ


คุณ refactored คำตอบของคุณและปรับปรุงคุณภาพโดยการเพิ่มมากขึ้น (บรรทัดของข้อความ): p
grinch

12

หากคุณต้องการที่จะเห็นผลที่ดีที่สุดเพียงแค่การลดจำนวนไบต์หรือนับ LoC ของรหัสที่มาของคุณไปมีลักษณะที่ส่งไปที่เว็บไซต์กอง Exchange Code กอล์ฟ

หากซอร์สโค้ดของคุณลดน้อยลงในลักษณะนี้คุณจะพบกับความยุ่งเหยิง แม้ว่าคุณจะเป็นคนที่เขียนรหัสดังกล่าวและเข้าใจมันอย่างเต็มที่ในเวลานั้นคุณจะมีประสิทธิภาพแค่ไหนเมื่อคุณกลับมาในอีกหกเดือนข้างหน้า? ไม่มีหลักฐานว่ารหัสขั้นต่ำสุดดังกล่าวสามารถดำเนินการใด ๆ ได้เร็วขึ้น

ควรเขียนโค้ดในลักษณะที่สมาชิกในทีมของคุณสามารถดูได้และเข้าใจสิ่งที่กำลังทำอยู่ในทันที


อาจซ้ำซ้อน แต่เพียงเพื่อสะกดออก; ถ้าคุณ refactor golfed code เพื่อให้อ่านง่ายคุณจะได้พบกับ
LoC

1

ใช่การเปลี่ยนโครงสร้างใหม่อาจส่งผลให้มีโค้ดมากกว่าหนึ่งบรรทัด

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

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

ตัวอย่างเช่นนี่เป็นสถานการณ์ทั่วไปที่เกิดขึ้นกับนักพัฒนาซอฟต์แวร์ทุกคน:

  • ผลิตภัณฑ์ของคุณต้องการคุณสมบัติใหม่เร่งด่วนที่มีความสำคัญสูงหรือการแก้ไขข้อบกพร่องหรือการปรับปรุงในสองสัปดาห์ (หรือกรอบเวลาใดที่ถือว่าเป็นเรื่องเร่งด่วนสำหรับโครงการขนาด / บริษัท ขนาด / ฯลฯ )
  • คุณทำงานหนักและส่งมอบตรงเวลาให้กับ XYZ และใช้งานได้ ขอแสดงความยินดี! เยี่ยมมาก!
  • ในขณะที่คุณกำลังพัฒนา XYZ การออกแบบ / การนำรหัสที่มีอยู่ของคุณไม่ได้สนับสนุน XYZ แต่คุณสามารถใช้ XYZ ใน codebase ได้
  • ปัญหาคือ shim นั้นน่าเกลียดและมีโค้ดกลิ่นแย่มากเพราะคุณทำสิ่งที่ยุ่งยาก / ฉลาด / น่าเกลียด / แย่ - ฝึกหัด แต่สิ่งที่ทำงาน
  • เมื่อคุณหาเวลาในภายหลังคุณจะสร้างรหัสใหม่ซึ่งอาจเปลี่ยนคลาสจำนวนมากหรือเพิ่มเลเยอร์ใหม่ของชั้นเรียนและวิธีแก้ปัญหาใหม่ของคุณคือ "ทำถูกต้อง" และไม่มีกลิ่นรหัสที่ไม่ดีอีกต่อไป ... "ทางที่ถูกต้อง" ตอนนี้ใช้สายโค้ดมากขึ้น

ตัวอย่างที่เป็นรูปธรรมบางอย่างที่ทำให้ฉันหลุดจากหัวของฉัน:

  • สำหรับอินเตอร์เฟสบรรทัดคำสั่งคุณสามารถมีโค้ด if / else- if 5,000 บรรทัดหรือคุณสามารถใช้ callbacks ... การโทรกลับแต่ละครั้งจะมีขนาดเล็กกว่ามากและง่ายต่อการอ่าน / ทดสอบ / ตรวจสอบ / ตรวจสอบ / debug / ฯลฯ มากขึ้น โค้ดน่าเกลียด 5,000 บรรทัดถ้า / else- ถ้ารหัสอาจจะมีขนาดเล็กลง
  • สำหรับชิ้นส่วนของการประมวลผลของรหัสที่รองรับวิธีการประมวลผล Nคุณสามารถใช้อีกครั้งถ้าคำสั่ง / อื่นซึ่งจะดูน่าเกลียดที่สุด ...
    • หรือคุณสามารถเปลี่ยนไปใช้การโทรกลับซึ่งจะดีกว่า แต่ดีกว่า แต่การโทรกลับใช้รหัสอีกหลายบรรทัด (ยังคงคอมไพล์เวลา)
    • หรือคุณสามารถสรุปเพิ่มเติมและทำปลั๊กอินที่สามารถเปลี่ยนแปลงได้ในขณะทำงาน ปลั๊กอินนั้นดีเพราะคุณไม่ต้องคอมไพล์ผลิตภัณฑ์หลักใหม่สำหรับแต่ละปลั๊กอินใหม่หรือการดัดแปลงเป็นปลั๊กอินที่มีอยู่ และคุณสามารถเผยแพร่ API เพื่อให้ผู้อื่นสามารถขยายผลิตภัณฑ์ได้ แต่อีกครั้งวิธีใช้ปลั๊กอินใช้บรรทัดของรหัสเพิ่มเติม
  • สำหรับ GUI คุณสร้างเครื่องมือใหม่ที่ยอดเยี่ยม
    • คุณหรือผู้ร่วมงานตั้งข้อสังเกตว่าวิดเจ็ตใหม่จะยอดเยี่ยมสำหรับ XYZ และ ABC แต่ตอนนี้วิดเจ็ตถูกรวมเข้าด้วยกันอย่างแน่นหนาเพื่อใช้งานกับ XYZ
    • คุณปรับแต่งวิดเจ็ตเพื่อทำงานทั้งคู่ แต่ตอนนี้จำนวนบรรทัดของโค้ดเพิ่มขึ้น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.