หาก - อื่น ๆ บันไดที่ควรจะจับเงื่อนไขทั้งหมด - ควรเพิ่มประโยคสุดท้ายซ้ำซ้อน?


10

นี่คือสิ่งที่ฉันทำมากเมื่อเร็ว ๆ นี้

ตัวอย่าง:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

บ่อยครั้งที่บันได if / else มีความซับซ้อนมากกว่านี้ ...

ดูข้อสุดท้าย? มันซ้ำซ้อน บันไดควรจะจับเงื่อนไขที่เป็นไปได้ในท้ายที่สุด ดังนั้นจึงสามารถเขียนใหม่เช่นนั้น:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

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

อย่างไรก็ตาม:

  • การเขียนเงื่อนไขสุดท้ายที่ครบถ้วนสมบูรณ์เป็นความคิดของฉันอย่างชัดเจนและฉันมีประสบการณ์ที่ไม่ดีกับความคิดของตัวเอง - โดยปกติแล้วคนมักจะตะโกนใส่ฉันเกี่ยวกับสิ่งที่น่ากลัวที่ฉันทำอยู่ - และ (บางครั้งมาก) ในภายหลัง ก่อให้เกิดผลลัพธ์;
  • หนึ่งคำใบ้ว่าทำไมนี่อาจเป็นความคิดที่ไม่ดี: ไม่สามารถใช้ได้กับ Javascript แต่ในภาษาอื่น ๆ คอมไพเลอร์มักจะออกคำเตือนหรือแม้กระทั่งข้อผิดพลาดเกี่ยวกับการควบคุมการเข้าถึงจุดสิ้นสุดของฟังก์ชั่น การให้คำแนะนำบางอย่างเช่นนั้นอาจไม่ได้รับความนิยมมากเกินไปหรือฉันทำผิด
    • คอมไพเลอร์ทำให้บางครั้งฉันเขียนเงื่อนไขสุดท้ายในความคิดเห็น แต่ฉันคิดว่าการทำเช่นนั้นน่ากลัวเพราะความคิดเห็นซึ่งแตกต่างจากรหัสไม่มีผลต่อความหมายของโปรแกรมจริง:
    } else { // i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }

ฉันพลาดอะไรไปรึเปล่า? หรือว่าตกลงที่จะทำสิ่งที่ฉันอธิบายหรือมันเป็นความคิดที่ไม่ดี?


+1 สำหรับ @ Christophe คำตอบผู้บริหารที่ซ้ำซ้อนในรหัสเพิ่มโอกาสสำหรับข้อบกพร่อง นอกจากนี้ยังมีปัญหาเรื่องประสิทธิภาพที่น้อยกว่ามาก ในการขยายในนั้นเกี่ยวกับตัวอย่างโค้ดที่เป็นปัญหาเราสามารถเขียนชุดของ if-else - if แยกออกจาก if โดยไม่มี elses แต่โดยทั่วไปเราจะไม่นับตั้งแต่ if-else ให้ผู้อ่านมีความคิดเกี่ยวกับทางเลือกพิเศษ มากกว่าชุดของเงื่อนไขที่เป็นอิสระ (ซึ่งก็จะมีประสิทธิภาพน้อยลงเนื่องจากที่บอกว่าเงื่อนไขทั้งหมดควรได้รับการประเมินแม้หลังจากหนึ่งนัด)
Erik Eidt

@ErikEidt> เนื่องจากระบุว่าเงื่อนไขทั้งหมดควรได้รับการประเมินแม้จะมีการจับคู่หนึ่งครั้งยกเว้นว่าคุณกลับมาจากฟังก์ชั่นหรือ "แยก" จากลูป (ซึ่งไม่ใช่กรณีในตัวอย่างด้านบน)
Darek Nędza

1
+1, คำถามที่ดี นอกจากนี้คุณอาจสนใจว่าการมี NaN นั้นเป็นตัวอย่างที่ไม่ครบถ้วนสมบูรณ์
monocell

คำตอบ:


6

ทั้งสองวิธีนี้ถูกต้อง แต่เรามาดูข้อดีข้อเสียกันอย่างใกล้ชิด

สำหรับif-chain ที่มีเงื่อนไขเล็กน้อยเช่นที่นี่มันไม่สำคัญ:

  • สุดท้ายelseก็เป็นที่ชัดเจนสำหรับผู้อ่านที่จะหาในสภาพที่อื่นจะถูกเรียก;
  • ในที่สุดelse ifก็เป็นที่ชัดเจนสำหรับผู้อ่านที่ไม่elseจำเป็นต้องมีเพิ่มเติมตั้งแต่คุณครอบคลุมมันทั้งหมด

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

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

ดังนั้นเงื่อนไขสุดท้ายที่ซ้ำซ้อนจึงเป็นแหล่งของความเสี่ยง elseนี่คือเหตุผลที่ฉันอยากจะแนะนำให้ไปเป็นครั้งสุดท้าย

แก้ไข: การเข้ารหัสความน่าเชื่อถือสูง

หากคุณกำลังพัฒนาที่มีความน่าเชื่อถือสูงในใจคุณอาจสนใจตัวแปรอื่น: ดำเนินการขั้นตอนสุดท้ายซ้ำซ้อนอย่างชัดเจนelse ifด้วยขั้นตอนสุดท้ายelseเพื่อให้ทันสถานการณ์ที่ไม่คาดคิด

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


7
จะเกิดอะไรขึ้นหากหลังจากเงื่อนไขการทำซ้ำซ้อนสุดท้ายฉันจะเพิ่มสิ่งอื่นที่มักจะเกิดข้อยกเว้นขึ้นมาซึ่งกล่าวว่า "คุณไม่ควรจะไปถึงฉัน!" - มันจะช่วยบรรเทาปัญหาของวิธีการของฉันได้หรือไม่?
gaazkam

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

@gaazkam ฉันได้แก้ไขคำตอบของฉันไปยังที่อยู่ความคิดเพิ่มเติมของคุณกล่าวถึงในความคิดเห็นของคุณ
Christophe

1
@gaazkam การยกเว้นเป็นสิ่งที่ดี ถ้าคุณทำอย่าลืมที่จะรวมค่าที่ไม่คาดคิดในข้อความ มันอาจจะยากที่จะทำซ้ำและค่าที่ไม่คาดคิดอาจให้เบาะแสเกี่ยวกับแหล่งที่มาของปัญหา
Martin Maat

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

5

สิ่งที่หายไปจากคำตอบจนถึงขณะนี้คือเรื่องของความล้มเหลวที่เป็นอันตรายน้อยกว่า

หากตรรกะของคุณดีไม่สำคัญว่าคุณจะทำอะไรกรณีที่สำคัญคือสิ่งที่จะเกิดขึ้นหากคุณมีข้อบกพร่อง

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

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

คุณเพิ่มเงื่อนไขสุดท้ายและข้อยกเว้น: มันจะพ่น

คุณต้องตัดสินใจว่าตัวเลือกใดดีที่สุด ในรหัสการพัฒนาฉันคิดว่านี่ไม่ใช่เกมง่ายๆ - นำกรณีที่สาม อย่างไรก็ตามฉันอาจตั้งค่า circle.src เป็นภาพข้อผิดพลาดและ circle.alt เป็นข้อความแสดงข้อผิดพลาดก่อนที่จะโยน - ในกรณีที่มีคนตัดสินใจปิดการยืนยันในภายหลังสิ่งนี้ทำให้มันล้มเหลวอย่างไม่เป็นอันตราย

สิ่งอื่นที่ควรพิจารณา - ตัวเลือกการกู้คืนของคุณคืออะไร? บางครั้งคุณไม่มีเส้นทางการกู้คืน สิ่งที่ฉันคิดว่าเป็นตัวอย่างที่ดีที่สุดของเรื่องนี้คือการเปิดตัวจรวด Ariane V เป็นครั้งแรก มีข้อผิดพลาดที่ไม่ถูกจับ / 0 (อันที่จริงแล้วเป็นการหารเกิน) ซึ่งส่งผลให้เกิดการทำลายของบูสเตอร์ ในความเป็นจริงแล้วรหัสที่ล้มเหลวไม่ได้มีจุดประสงค์ใด ๆ ณ จุดนั้นมันกลายเป็นสิ่งที่ทำให้สายคล้องคอติดขึ้นสว่างขึ้นทันที เมื่อพวกเขาเห็นว่ามันเป็นวงโคจรหรือบูมคุณจะทำสิ่งที่ดีที่สุดได้ไม่อนุญาตให้มีข้อผิดพลาด (ถ้าจรวดพุ่งออกมาเนื่องจากสิ่งนี้ผู้ที่อยู่ในระยะปลอดภัยจึงเปลี่ยนกุญแจของเขา)


4

สิ่งที่ฉันแนะนำคือการใช้assertคำสั่งในขั้นสุดท้ายของคุณในสองรูปแบบเหล่านี้:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        assert i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

หรือยืนยันรหัสที่ตายแล้ว:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    } else {
        assert False, "Unreachable code"
    }
}

เครื่องมือครอบคลุมรหัสสามารถกำหนดค่าให้ละเว้นรหัสเช่น "ยืนยันเท็จ" จากรายงานความครอบคลุมได้


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


1
ฉันไม่ชอบตัวเลือกแรกของคุณตัวเลือกที่สองชัดเจนกว่าว่ามันควรจะเป็นไปไม่ได้
Loren Pechtel

0

ฉันกำหนดแมโคร“ ยืนยัน” ซึ่งประเมินเงื่อนไขและในบิลด์การตรวจแก้จุดบกพร่องจะอยู่ในดีบักเกอร์

ดังนั้นถ้าฉัน 100 เปอร์เซ็นต์แน่ใจว่าหนึ่งในสามเงื่อนไขต้องเป็นจริงฉันเขียน

If condition 1 ...
Else if condition 2 .,,
Else if asserted (condition3) ...

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


-2

ผมขอแนะนำให้หลีกเลี่ยงการอื่นทั้งหมด ใช้ifเพื่อประกาศสิ่งที่บล็อกของรหัสควรจะจัดการและสิ้นสุดบล็อกโดยออกจากฟังก์ชั่น

ผลลัพธ์นี้ในรหัสที่ชัดเจนมาก:

setCircle(circle, i, { current })
{
    if (i == current)
    {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
        return
    }
    if (i < current)
    {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
        return
    }
    if (i > current)
    {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
        return
    }
    throw new Exception("Condition not handled.");
}

สุดท้ายifคือการซ้ำซ้อนแน่นอน ... วันนี้ มันอาจกลายเป็นความคิดที่สำคัญมากหาก / เมื่อนักพัฒนาในอนาคตบางคนจัดบล็อกใหม่ ดังนั้นมันจะมีประโยชน์ที่จะทิ้งไว้ในนั้น


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

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

@ gnasher729 ฉันเข้าใจปฏิกิริยาของคุณโดยสิ้นเชิง ฉันรู้ว่าคนฉลาดบางคนที่มีปัญหากับ "หลีกเลี่ยงอื่น" และ "กลับเร็ว" ... ตอนแรก ฉันขอแนะนำให้คุณใช้เวลาสักครู่เพื่อทำความคุ้นเคยกับความคิดและมองมัน - เพราะความคิดเหล่านี้ทำอย่างเป็นกลางและวัดผลได้ลดความซับซ้อน การคืนต้นจะระบุถึงจุดแรกของคุณ (จำเป็นต้องพิจารณาว่าสาขาอาจเปลี่ยนการทดสอบอื่นหรือไม่) และ "ความเป็นไปได้ที่ไม่มีเงื่อนไขเป็นจริง" ยังคงมีอยู่โดยไม่คำนึงถึง ด้วยสไตล์นี้คุณจะได้รับข้อยกเว้นที่ชัดเจนมากกว่าข้อบกพร่องทางตรรกะที่ซ่อนอยู่
John Wu

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