แนวปฏิบัติบูลีนที่ดีที่สุด [ปิด]


10

ฉันเจอเงื่อนไขต่อไปนี้ในโปรแกรมที่ฉันได้ยึดครองจากผู้พัฒนารายอื่น:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

ฉันเชื่อว่ารหัสนี้ซ้ำซ้อนและน่าเกลียดดังนั้นฉันจึงเปลี่ยนเป็นสิ่งที่ฉันคิดว่าเป็นการมอบหมายบูลีนอย่างง่ายจากการเปรียบเทียบ:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

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

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE) ? true : false;

เหตุผลของเขาคือการทำบางสิ่งด้วยวิธีที่รัดกุมที่สุดนั้นไม่คุ้มค่าถ้ามันทำให้ผู้พัฒนารายอื่นต้องหยุดและไขปริศนาสิ่งที่คุณทำ

คำถามจริงที่นี่คือวิธีใดในสามวิธีในการกำหนดค่าให้กับบูลีนobj.NeedsChangeที่ชัดเจนที่สุดและสามารถบำรุงรักษาได้มากที่สุด


25
รูปแบบที่สามไร้สาระ; มันเป็นเพียงการระบุสิ่งที่ควรมีความชัดเจนในรูปแบบที่สอง
Robert Harvey

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

3
@scriptin 5-8 บรรทัด v 1 บรรทัดเป็นมากกว่าความต้องการซับ 5-8 มักจะชัดเจนและดีกว่าสำหรับมัน ในตัวอย่างง่าย ๆ นี้ฉันชอบ 1 บรรทัด แต่โดยทั่วไปฉันเคยเห็น 10 liners มากเกินไปที่ทำให้งงเป็น 1-liners เพื่อความสะดวกสบาย จากที่ฉันไม่เคยบ่นเกี่ยวกับตัวแปร 1 มันอาจไม่สวย แต่ทำงานได้อย่างชัดเจนและชัดเจน
gbjbaanb

4
ตัวเลือกที่ 1 และ 3 พูดกับฉันว่า "ผู้เขียนไม่เข้าใจตรรกะบูลีน"
17 ของ 26

2
Variant 1 อาจมีประโยชน์หากคุณจำเป็นต้องตั้งเบรกพอยต์ที่ขึ้นอยู่กับค่า
เอียน

คำตอบ:


39

ฉันชอบ 2 แต่ฉันอาจจะปรับเล็กน้อย:

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

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


4
นี่คือคำตอบที่ถูกต้อง - ถึงแม้ว่ารหัสในคำถามนั้นถูกต้อง แต่การเพิ่มวงเล็บจะบอกผู้อ่านว่าไม่ได้รับมอบหมาย หากคุณดูรหัสอย่างรวดเร็ววงเล็บจะให้ข้อมูลเพิ่มเติมทันทีที่หยุดไม่ให้คุณมองใกล้เพื่อดูว่ารหัสนั้นเป็นเช่นนั้นหรือไม่และไม่ใช่ข้อผิดพลาดโดยไม่ตั้งใจ ยกตัวอย่างเช่นลองนึกดูว่าบรรทัดนั้นa = b == cคุณหมายถึงมอบหมายบูลหรือคุณหมายถึงมอบหมาย c ให้ทั้ง b และ a
gbjbaanb

วงเล็บจะป้องกันการมอบหมายสองครั้งใน Python แม้ในภาษาที่พวกเขาไม่ได้ป้องกันการมอบหมายสองครั้งวงเล็บก็ช่วยระบุว่าคุณกำลังดำเนินการสองประเภท
user2357112 รองรับ Monica

23

ตัวแปร 1 เข้าใจได้ง่าย แต่นั่นเป็นข้อได้เปรียบเพียงอย่างเดียว ฉันสันนิษฐานโดยอัตโนมัติว่าใครก็ตามที่เขียนแบบนี้ไม่เข้าใจว่าบูลีนเกี่ยวกับอะไรจริง ๆ และจะเขียนรหัสเด็กที่คล้ายกันในแง่อื่น

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

Variant 3 รวมข้อเสียของทั้ง 1 และ 2 เข้าด้วยกัน


ทีนี้ตัวแปร 1 แบ่งปันความได้เปรียบกับตัวแปร 2 ...
Deduplicator

1
+1 สำหรับรหัสเด็ก ฉันดูรหัสดังกล่าวมาหลายปีแล้วฉันแค่ขาดคำที่ถูกต้องในการระบุ
Lilienthal

1
ข้อสันนิษฐานแรกของฉันที่มีรหัสเช่น Variant 1 คือทั้งสองสาขา ณ จุดหนึ่งในอดีตมีความซับซ้อนมากขึ้นและมีคนไม่สนใจเมื่อทำการปรับโครงสร้างใหม่ ถ้าเป็นเช่นนั้นเมื่อมันถูกเขียนครั้งแรกฉันเห็นด้วยกับ "ไม่เข้าใจบูลีน"
Izkata

13

รหัสเวลามีความซับซ้อนมากกว่าที่จะต้องเรียก "สิ่งนี้ควรจะทำอย่างไร" กลิ่นในเครื่องอ่าน

ตัวอย่างเช่นตัวอย่างแรกทำให้ฉันสงสัยว่า "มีฟังก์ชั่นอื่น ๆ ในคำสั่ง if / else ณ จุดที่ถูกลบไปแล้วหรือไม่"

ตัวอย่าง (2) ง่ายชัดเจนและทำสิ่งที่ต้องการ ฉันอ่านและเข้าใจในทันทีว่าโค้ดทำอะไร

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


2

เป็นเรื่องง่ายที่จะเห็นว่า Variant 2 และ Variant 1 มีความเกี่ยวข้องผ่านชุดของการปรับโครงสร้างที่ชัดเจนและเรียบง่าย:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

ที่นี่เรามีการทำสำเนารหัสที่ไม่จำเป็นเราสามารถแยกการกำหนด:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE)
{
    true
}
else
{
    false
}

หรือเขียนรัดกุมมากขึ้น:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE) true else false

ตอนนี้มันควรจะชัดเจนทันทีว่าสิ่งนี้จะกำหนดเป็นจริงหากเงื่อนไขเป็นจริงและกำหนดเป็นเท็จหากเงื่อนไขเป็นเท็จ IOW เพียงแค่จะกำหนดมูลค่าของเงื่อนไขนั่นคือเทียบเท่ากับ

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE

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


ฉันจะเพิ่มของคุณถ้า (... ) ... ส่วนเท็จเป็นความคิดเห็นก่อนที่จะดีคุณจะได้รับการสแกนง่ายผ่านความคมชัดของรหัสและรหัสที่ดีกว่า
DaveM

2

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

หนึ่งในนั้นคือไวยากรณ์ของภาษาที่เขาใช้

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

มีความชัดเจนมากสำหรับผู้ที่รู้จักไวยากรณ์ C / C ++ / C # / Java / Javascript

นอกจากนี้ยังสามารถอ่านได้มากกว่า 8 บรรทัด

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

และมีแนวโน้มที่จะผิดพลาดน้อยลง

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.Needschange = false;
}

และมันดีกว่าการเพิ่มตัวละครที่ไม่จำเป็นราวกับว่าคุณลืมไวยากรณ์ของภาษา:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE ? true : false;

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE);

ฉันคิดว่ามีความผิดพลาดอย่างมากเกี่ยวกับไวยากรณ์แบบ C ของหลายภาษา: ลำดับการดำเนินการที่ไม่สอดคล้องกัน, ความสัมพันธ์ด้านซ้าย / ขวาที่ไม่สอดคล้องกัน, การใช้สัญลักษณ์มากเกินไป, การทำซ้ำเครื่องหมายวงเล็บ / เยื้อง, ตัวดำเนินการประกอบ

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


โดยทั่วไปสิ่ง # 1 ที่ทำให้รหัสReal World TMไม่สามารถอ่านได้คือจำนวนของมัน

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


1

นักพัฒนาส่วนใหญ่จะสามารถเข้าใจรูปแบบที่ 2 ได้อย่างรวดเร็ว ในความเห็นของฉันเกี่ยวกับการทำให้เข้าใจง่ายเหมือนในรูปแบบที่ 1 นั้นไม่จำเป็น

คุณสามารถปรับปรุงความสามารถในการอ่านโดยการเพิ่มช่องว่างและเครื่องหมายปีกกาเช่น:

obj.NeedsChange =    obj.Performance <= LOW_PERFORMANCE;

หรือ

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

ตามที่กล่าวไว้โดย Jacob Raihle

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