นักพัฒนายืนยันว่าคำสั่งไม่ควรมีเงื่อนไขที่ไม่สนใจและควรมีบล็อกอื่นอยู่เสมอ


169

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

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

if(condition) 
{
    doStuff();
    return whatever;
}
else
{
}

ประการที่สองจะเป็นการดีกว่าที่จะทดสอบค่าจริงแทนที่จะเป็นเท็จ นั่นหมายความว่าเป็นการดีกว่าที่จะทดสอบตัวแปร 'doorClosed' แทนที่จะเป็นตัวแปร '! doorOpened'

เหตุผลของเขาคือทำให้ชัดเจนว่ารหัสกำลังทำอะไร

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

if(condition)
{
}
else
{
    doStuff();
    return whatever;
}

ความรู้สึกของฉันเกี่ยวกับเรื่องนี้ก็คือมันน่าเกลียดมากและ / หรือว่าการปรับปรุงคุณภาพถ้ามีมีเล็กน้อย แต่ในฐานะรุ่นน้องฉันมักจะสงสัยสัญชาตญาณของตัวเอง

ดังนั้นคำถามของฉันคือ: มันเป็นการปฏิบัติที่ดี / ไม่ดี / "ไม่สำคัญ"? มันเป็นเรื่องธรรมดา



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

11
คู่มือสไตล์รหัส บริษัท ของคุณพูดว่าอะไร
Thorbjørn Ravn Andersen

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

9
Resharper มีบางสิ่งที่จะบอกเพื่อนของคุณตามบรรทัด "รหัสของคุณซ้ำซ้อนและไร้ประโยชน์คุณต้องการให้ฉันลบ / refactor หรือไม่"
BgrWorker

คำตอบ:


184

elseบล็อกที่ชัดเจน

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

ฉันไม่ได้พูดถึงความจริงที่ว่าifคำสั่งไม่ได้ตามจำเป็นโดยทั้งelseหรือไม่มีอะไร: มันอาจจะตามด้วยหนึ่งหรือมากกว่าelifs เกินไป

การปรากฏตัวของreturnคำสั่งทำให้สิ่งต่าง ๆ แย่ลง แม้ว่าคุณจะมีรหัสเพื่อดำเนินการภายในelseบล็อกจริง ๆ มันก็จะสามารถอ่านได้ง่ายขึ้นเช่นนี้:

if (something)
{
    doStuff();
    return whatever;
}

doOtherThings();
return somethingElse;

สิ่งนี้ทำให้โค้ดใช้เวลาน้อยกว่าสองบรรทัดและยกเลิกการelseบล็อกบล็อก ส่วนคำว่าการ์ดล้วนเกี่ยวกับเรื่องนั้น

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

if (something)
{
}
if (other)
{
}
else
{
}

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

ทดสอบเพื่อtrueไม่ใช่false

กฎข้อที่สองอาจเข้าท่า แต่ไม่ใช่ในรูปแบบปัจจุบัน

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

if (!this.IsMaster || (!this.Ready && !this.CanWrite))

เพื่อแก้ปัญหาที่แทนการเพิ่มบล็อกที่ว่างเปล่าสร้างคุณสมบัติเพิ่มเติมเมื่อมีความเกี่ยวข้องหรือตัวแปรท้องถิ่น

เงื่อนไขข้างต้นสามารถอ่านได้ค่อนข้างง่าย:

if (this.IsSlave || (this.Synchronizing && this.ReadOnly))

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

50
@Neil การลบเงื่อนไขไม่จำเป็นต้องใช้เวลา CPU เพิ่มเติมใด ๆ C รวบรวมเพื่อ x86 ก็สามารถสลับการเรียนการสอนการกระโดดจากJZ(กระโดดถ้าศูนย์) สำหรับif (foo)การJNZ(กระโดดถ้าไม่เป็นศูนย์) if (!foo)สำหรับ
8bittree

71
" สร้างคุณสมบัติเพิ่มเติมด้วยชื่อที่ชัดเจน ": หากคุณไม่มีการวิเคราะห์โดเมนที่ลึกซึ้งยิ่งขึ้นสิ่งนี้อาจเปลี่ยนแปลงขอบเขตทั่วโลก (คลาสดั้งเดิม) เพื่อแก้ไขปัญหาในท้องถิ่น (แอปพลิเคชันของกฎธุรกิจเฉพาะ) สิ่งหนึ่งที่สามารถทำได้ที่นี่คือการสร้างบูลีนท้องถิ่นด้วยสถานะที่ต้องการเช่น "var isSlave =! this.IsMaster" และใช้กับบูลีนท้องถิ่นแทนการสร้างคุณสมบัติอื่น ๆ ดังนั้นใช้คำแนะนำกับเกลือเม็ดและใช้เวลาในการวิเคราะห์โดเมนก่อนที่จะสร้างคุณสมบัติใหม่
Machado

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

15
@ Mark ที่ชัดเจนน้อยกว่าแม้จะมีความคิดเห็นมากกว่าที่if (!commonCase) { handle the uncommon case },จะพูด
Paul

62

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

if(condition) 
{
    doStuff();
    return whatever;
}

doSomethingElse(); // no else needed
return somethingelse;

เมื่อพิจารณาถึงจุดที่สองคุณควรหลีกเลี่ยงชื่อบูลีนที่มีค่าลบ:

bool doorNotOpen = false; // a double negative is hard to reason
bool doorClosed = false; // this is much clearer

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

if(!condition)
{
    doStuff();
    return whatever;
}

120
ดังนั้น ... คุณสามารถพูดได้ว่าการลบสองเท่านั้นเป็นไม่เลย? ;)
Patsuan

6
@ Patuan ฉลาดมาก ฉันชอบมัน. :)
David Arno

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

6
เห็นได้ชัดว่าif (!doorNotOpen)มันน่ากลัว ดังนั้นชื่อควรเป็นบวกที่สุด if (! doorClosed)ดีอย่างสมบูรณ์แบบ
David Schwartz

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

45

1. การโต้แย้งในelseข้อความที่ว่างเปล่า

ฉันมักจะใช้ (และโต้แย้ง) สิ่งที่คล้ายกับการสร้างครั้งแรกที่ว่างเปล่าอื่น มันส่งสัญญาณไปยังผู้อ่านของรหัส (ทั้งมนุษย์และเครื่องมือวิเคราะห์อัตโนมัติ) ที่โปรแกรมเมอร์ได้นำความคิดบางอย่างมาสู่สถานการณ์ elseข้อความที่ขาดหายไปซึ่งควรมีอยู่ในปัจจุบันได้ฆ่าผู้คนรถชนและค่าใช้จ่ายหลายล้านดอลลาร์ ยกตัวอย่างเช่น MISRA-C ได้รับคำสั่งอย่างน้อยความคิดเห็นที่บอกว่าสิ่งสุดท้ายที่ขาดหายไปนั้นเป็นความตั้งใจในif (condition_1) {do_this;} else if (condition_2) {do_that;} ... else if (condition_n) {do_something_else;}ลำดับ มาตรฐานความน่าเชื่อถือสูงอื่น ๆ ดำเนินต่อไป: มีข้อยกเว้นบางประการไม่มีข้อความอื่นใดที่ถูกห้าม

/* Else not required */ยกเว้นเป็นความเห็นที่เรียบง่ายสิ่งที่ตามสายของ สัญญาณนี้แสดงถึงเจตนาเช่นเดียวกับสามบรรทัดที่ว่างเปล่า อีกข้อยกเว้นที่ไม่จำเป็นต้องมีสิ่งที่ว่างเปล่าอื่น ๆ คือที่ซึ่งมันชัดเจนโจ่งแจ้งต่อผู้อ่านของรหัสและเครื่องมือการวิเคราะห์อัตโนมัติที่ว่างเปล่าอย่างอื่น ยกตัวอย่างเช่นif (condition) { do_stuff; return; }ในทำนองเดียวกันที่ว่างเปล่าอื่นจะไม่จำเป็นต้องใช้ในกรณีของthrow somethingหรือgoto some_label1returnแทนของ

2. อาร์กิวเมนต์สำหรับการเลือกที่มากกว่าif (condition)if (!condition)

นี่คือรายการปัจจัยมนุษย์ ตรรกะบูลีนที่ซับซ้อนเดินทางหลายคนขึ้นไป if (!(complex || (boolean && condition))) do_that; else do_this;แม้จะเป็นโปรแกรมเมอร์เก๋าจะต้องคิดเกี่ยวกับ if (complex || (boolean && condition)) do_this; else do_that;ที่ต่ำสุดที่เขียนนี้เป็น

3. สิ่งนี้ไม่ได้หมายความว่าควรใช้thenข้อความสั่งที่ว่างเปล่า

ส่วนที่สองบอกว่า "ชอบ" มากกว่า "เจ้าจะ" มันเป็นแนวทางมากกว่ากฎ เหตุผลสำหรับแนวทางที่ต้องการifเงื่อนไขที่ดีคือรหัสควรชัดเจนและชัดเจน ประโยคที่ว่างเปล่านั้น (เช่นif (condition) ; else do_something;) ละเมิดสิ่งนี้ มันคือการเขียนโปรแกรมที่สับสนทำให้แม้แต่โปรแกรมเมอร์ที่มีประสบการณ์มากที่สุดในการสำรองข้อมูลและอ่านifเงื่อนไขในรูปแบบที่ถูกทำให้ไร้ผล ดังนั้นให้เขียนมันในรูปแบบที่ถูกปฏิเสธในตอนแรกและละเว้นคำสั่ง else (หรือมีสิ่งอื่นที่ว่างเปล่าหรือแสดงความคิดเห็นกับผลกระทบนั้นหากได้รับคำสั่งให้ทำ)



1ผมเขียนนั้นข้อที่ลงท้ายด้วยreturn, throwหรือgotoไม่จำเป็นต้องมีที่ว่างเปล่าอื่น เห็นได้ชัดว่าไม่จำเป็นต้องใช้ประโยคอื่น แต่เกี่ยวกับgotoอะไร นอกเหนือจากกฎการเขียนโปรแกรมความปลอดภัยที่สำคัญบางครั้งไม่อนุญาตให้กลับมาก่อนและเกือบจะไม่อนุญาตให้มีการยกเว้นข้อยกเว้น อย่างไรก็ตามอนุญาตgotoในรูปแบบที่ถูก จำกัด (เช่นgoto cleanup1;) การใช้งานแบบ จำกัด นี้gotoเป็นวิธีปฏิบัติที่ต้องการในบางสถานที่ ลินุกซ์เคอร์เนลตัวอย่างเช่น chockfull ของgotoคำสั่งดังกล่าว


6
!ยังถูกมองข้ามได้ง่าย มันสั้นเกินไป
Thorbjørn Ravn Andersen

4
เปล่าสิ่งที่ว่างเปล่าไม่ได้ทำให้ชัดเจนว่าโปรแกรมเมอร์ได้คิดอะไรไว้ มันนำไปสู่ความสับสนมากขึ้น "มีการวางแผนบ้างหรือไม่และพวกเขาลืมไปหรือทำไมจึงมีประโยคว่างเปล่า" ความคิดเห็นที่ชัดเจนมากขึ้น
Simon

9
@Simon: รูปแบบทั่วไปคือelse { /* Intentionally empty */ }หรือบางสิ่งบางอย่างตามสายเหล่านั้น ส่วนที่ว่างเปล่าเป็นไปตามตัววิเคราะห์แบบคงที่ซึ่งไม่สนใจการละเมิดกฎ ความคิดเห็นแจ้งให้ผู้อ่านทราบว่าสิ่งอื่นนั้นว่างโดยเจตนา จากนั้นอีกครั้งโปรแกรมเมอร์ที่มีประสบการณ์มักจะละเว้นความคิดเห็นที่ไม่จำเป็น - แต่ไม่ใช่ความว่างเปล่า การเขียนโปรแกรมความน่าเชื่อถือสูงเป็นโดเมนของตัวเอง สิ่งก่อสร้างดูค่อนข้างแปลกสำหรับคนนอก สิ่งก่อสร้างเหล่านี้ใช้เพราะบทเรียนจากโรงเรียนของการเคาะอย่างหนักการเคาะที่ยากมากเมื่อชีวิตและความตายหรือ $$$$$$$$$ อยู่ในมือ
David Hammen

2
ฉันไม่เข้าใจว่าคำสั่งที่ว่างเปล่านั้นเป็นสิ่งที่ไม่ดีหรือเปล่าเมื่อข้ออื่นว่างเปล่าไม่ใช่ (ถ้าเราเลือกสไตล์นั้น) ฉันสามารถเห็นif (target == source) then /* we need to do nothing */ else updateTarget(source)
Bergi

2
@ ThorbjørnRavnAndersen nope notเป็นคีย์เวิร์ดใน C ++ เช่นเดียวกับตัวดำเนินการบิตและตรรกะอื่น ๆ ดูการแสดงประกอบการทางเลือก
Ruslan

31

ฉันใช้เปล่าสาขาอื่น (และบางครั้งว่างเปล่าสาขาถ้า) ในกรณีที่หายากมาก: เมื่อเห็นได้ชัดว่าควรจัดการทั้งส่วนและอื่น ๆ แต่สำหรับเหตุผลที่ไม่น่ารำคาญบางกรณีสามารถจัดการโดย ไม่ได้ทำอะไร. ดังนั้นใครก็ตามที่อ่านโค้ดด้วยการกระทำอื่นที่จำเป็นจะต้องสงสัยทันทีว่ามีบางอย่างขาดหายไปและเสียเวลา

if (condition) {
    // No action needed because ...
} else {
    do_else_action()
}

if (condition) {
    do_if_action()
} else {
    // No action needed because ...
}

แต่ไม่:

if (condition) {
    do_if_action()
} else {
    // I was told that an if always should have an else ...
}

5
นี้. ฉันพบว่าคำสั่งif test succeeds -> no action needed -> else -> action neededนั้นแตกต่างอย่างมากกับคำสั่งif it applies that the opposite of a test outcome is true then an action is neededนั้น ฉันนึกถึงคำพูดของ Martin Fowler: "ทุกคนสามารถเขียนรหัสคอมพิวเตอร์สามารถเข้าใจได้; โปรแกรมเมอร์ที่ดีสามารถเขียนโค้ดที่มนุษย์เข้าใจได้"
Tasos Papastylianou

2
@TasosPapastylianou นั่นคือการโกง ตรงกันข้ามกับ 'ถ้าการทดสอบประสบความสำเร็จ -> ไม่จำเป็นต้องมีการดำเนินการ' คือ 'ถ้าการทดสอบไม่ประสบความสำเร็จ -> จำเป็นต้องมีการดำเนินการ' คุณใช้คำประมาณ 10 คำ
Jerry B

@JerryB มันขึ้นอยู่กับ "การทดสอบ" บางครั้งการปฏิเสธก็คือ (ทางภาษา) ตรงไปตรงมา แต่บางครั้งก็ไม่เป็นเช่นนั้นและจะนำไปสู่ความสับสน ในกรณีเหล่านั้นมันชัดเจนกว่าที่จะพูดคุยเกี่ยวกับ "การปฏิเสธ / ตรงกันข้ามกับผลลัพธ์ที่เป็นจริง" กับ "ผลลัพธ์ที่ไม่เป็นจริง" อย่างไรก็ตามประเด็นก็คือว่ามันจะชัดเจนยิ่งขึ้นที่จะแนะนำขั้นตอน 'ว่าง' หรือพลิกความหมายของชื่อตัวแปร นี่เป็นเรื่องปกติในสถานการณ์ "เดมอร์แกน" เช่นif ((missing || corrupt) && !backup) -> skip -> else do stuffมีความชัดเจนมากขึ้น (+ ความตั้งใจโดยนัยที่แตกต่างกัน) กว่าif ((!missing && !corrupt) || backup) -> do stuff
Tasos Papastylianou

1
@TasosPapastylianou คุณสามารถเขียนหรือดีกว่าif(!((missing || corrupt) && !backup)) -> do stuff if((aviable && valid) || backup) -> do stuff(แต่ในตัวอย่างจริงคุณต้องตรวจสอบว่าการสำรองข้อมูลนั้นถูกต้องก่อนการใช้งานหรือไม่)
12431234123412341234123

2
@TasosPapastylianou ที่ไหนที่ฉันพูดในแง่ลบ แน่นอนว่าถ้าคุณใช้ชื่อที่ไม่ถูกขัดจังหวะเป็นชื่อตัวแปรคุณจะมีจุดชัดเจน แม้ว่าเมื่อคุณใช้ตัวดำเนินการบูลีนแบบผสมมันอาจเป็นการดีกว่าถ้าคุณมีตัวแปรชั่วคราวที่ใช้ในif: file_ok = !missing && !corrupt; if(file_ok || backup) do_stuff();ซึ่งโดยส่วนตัวแล้วฉันรู้สึกว่ามันชัดเจนยิ่งขึ้น
Baldrickk

23

ทุกสิ่งทุกอย่างเท่าเทียมกันชอบความกะทัดรัด

สิ่งที่คุณไม่เขียนไม่มีใครต้องอ่านและเข้าใจ

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


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

นอกจากนี้หลีกเลี่ยงการเขียนสาขาอื่นหากคุณออกจากสาขาโดยตรงโดยตรง

โปรแกรมที่มีประโยชน์ของการชัดแจ้งจะวางความคิดเห็นเมื่อใดก็ตามที่คุณตกผ่านสวิทช์กรณีและการใช้ความคิดเห็นหรือบล็อกที่ว่างเปล่าที่คุณจะต้องเป็นคำสั่งที่ว่างเปล่า// FALLTHRUfor(a;b;c) /**/;


7
// FALLTHRUไม่ได้อยู่ใน SCREAMING CAPS หรือด้วย txtspk abbrevs มิฉะนั้นฉันเห็นด้วยและปฏิบัติตามการปฏิบัตินี้ด้วยตัวเอง
โคดี้เกรย์

7
@CodyGray - นี่เป็นสถานที่แห่งหนึ่งที่มีความคิดที่ดี breakส่วนใหญ่งบสวิทช์จบแต่ละกรณีด้วย ความล้มเหลวที่จะมีที่breakนำไปสู่ความล้มเหลวของซอฟต์แวร์ที่งดงามบางอย่าง ความคิดเห็นที่ตะโกนให้ผู้อ่านรหัสที่การตกลงมานั้นเป็นความตั้งใจเป็นสิ่งที่ดี เครื่องมือวิเคราะห์แบบคงที่นั้นสามารถมองหารูปแบบเฉพาะนี้และไม่บ่นเกี่ยวกับสถานการณ์ที่ล้มลงทำให้สิ่งนี้ดียิ่งขึ้น
David Hammen

1
@Wossname: ฉันเพียงแค่การตรวจสอบของฉันและมันก็ไม่ได้รับรู้การเปลี่ยนแปลงใดvimFALLTHRUและฉันคิดว่าด้วยเหตุผลที่ดี: TODOและFIXMEความคิดเห็นคือความคิดเห็นที่ต้องมี grepable เพราะคุณต้องการที่จะถามgit grepข้อบกพร่องที่คุณรู้จักซึ่งคุณมีในรหัสของคุณและที่ตั้งของพวกเขา การตกหล่นไม่ใช่ข้อบกพร่องและไม่มีเหตุผลอะไรที่จะทำให้มันเลวร้ายอย่างที่เคยเป็นมา
cmaster

4
@ DavidHammen ไม่การตะโกนไม่ใช่ความคิดที่ดี: ถ้าคุณมี // fallthrough แทนการหยุดพักที่คาดไว้; นั่นน่าจะเพียงพอสำหรับนักพัฒนาที่จะเข้าใจได้ทันที นอกจากนี้ // fallthrough ไม่ได้พูดถึงข้อบกพร่องมันเป็นเพียงสัญญาณว่าสถานการณ์ได้รับการพิจารณาและการหยุดพัก ซึ่งดูเหมือนจะหายไปมีจุดมุ่งหมายเพื่อไม่ให้มี นี่คือจุดประสงค์ในการให้ข้อมูลล้วนๆและไม่มีอะไรให้ตะโกน
cmaster

1
@cmaster - ตะโกนที่ไม่ได้เป็นความคิดที่ดีคือคุณมีความคิดเห็น ความคิดเห็นของคนอื่นนั้นแตกต่างกัน และเนื่องจากการกำหนดค่า vim ของคุณไม่รู้จักFALLTHRUไม่ได้หมายความว่าคนอื่นไม่ได้กำหนดค่า vim ให้ทำ
David Hammen

6

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

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


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

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

สไตล์ส่วนตัว: ไม่ว่าฉันจะใช้สไตล์รั้งใด (Allman, 1TB, ... ) ฉันมักจะใช้เครื่องมือจัดฟัน
David Hammen

เงื่อนไขที่ซับซ้อนหรือสิ่งที่คุณคิดว่าอาจจะยากที่จะเข้าใจสามารถแก้ไขได้เกือบทุกครั้งโดยการรวมตัวกันเป็นวิธีการ / ฟังก์ชั่นของตนเองอีกครั้ง บางอย่างเช่นนี้if(hasWriteAccess(user,file))อาจซับซ้อนอยู่ข้างใต้ แต่คุณรู้ได้ทันทีว่าผลลัพธ์ควรเป็นอะไร แม้ว่าจะเป็นเพียงเงื่อนไขสองสามอย่างเช่นif(user.hasPermission() && !file.isLocked())การเรียกใช้เมธอดที่มีชื่อที่เหมาะสมจะได้รับการแก้ไขดังนั้นการปฏิเสธจึงกลายเป็นปัญหาน้อยลง
Chris Schneider

ตกลง จากนั้นอีกครั้งฉันเป็นแฟนตัวยงของ refactoring เมื่อใดก็ตามที่เป็นไปได้ :)
Langecrew

5

elseบล็อกที่ชัดเจน

ฉันไม่เห็นด้วยกับสิ่งนี้เป็นคำสั่งแบบครอบคลุมที่ครอบคลุมข้อความทั้งหมดifแต่มีบางครั้งที่การเพิ่มelseบล็อกไม่ให้ติดนิสัยเป็นสิ่งที่ดี

ความifคิดของฉันครอบคลุมถึงสองหน้าที่ที่แตกต่างกัน

ถ้าเราควรทำอะไรทำที่นี่

เห็นได้ชัดว่าสิ่งนี้ไม่จำเป็นต้องมีelseส่วนร่วม

    if (customer.hasCataracts()) {
        appointmentSuggestions.add(new CataractAppointment(customer));
    }
    if (customer.isDiabetic()) {
        customer.assignNurse(DiabeticNurses.pickBestFor(customer));
    }

และในบางกรณีการยืนยันในการเพิ่มelseอาจทำให้เข้าใจผิด

    if (k > n) {
        return BigInteger.ZERO;
    }
    if (k <= 0 || k == n) {
        return BigInteger.ONE;
    }

คือไม่ได้เช่นเดียวกับ

    if (k > n) {
        return BigInteger.ZERO;
    } else {
        if (k <= 0 || k == n) {
            return BigInteger.ONE;
        }
    }

แม้ว่ามันจะเป็นเหมือนเดิม การเขียนคำแรกifที่ว่างเปล่าelseอาจนำคุณไปสู่ผลลัพธ์ที่สองซึ่งน่าเกลียดโดยไม่จำเป็น

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

        // Count wins/losses.
        if (doors[firstChoice] == Prize.Car) {
            // We would have won without switching!
            winWhenNotSwitched += 1;
        } else {
            // We win if we switched to the car!
            if (doors[secondChoice] == Prize.Car) {
                // We picked right!
                winWhenSwitched += 1;
            } else {
                // Bad choice.
                lost += 1;
            }
        }

โปรดจำไว้ว่ากฎเหล่านี้ใช้เฉพาะเมื่อคุณกำลังเขียนโค้ดใหม่ IMHO elseข้อที่ว่างเปล่าควรถูกลบออกก่อนการเช็คอิน


ทดสอบเพื่อtrueไม่ใช่false

นี่เป็นคำแนะนำที่ดีในระดับทั่วไป แต่ในหลาย ๆ กรณีทำให้รหัสมีความซับซ้อนเกินความจำเป็นและสามารถอ่านได้น้อย

แม้ว่ารหัสเช่น

    if(!customer.canBuyAlcohol()) {
        // ...
    }

เป็นที่สั่นสะเทือนให้กับผู้อ่าน แต่ทำให้

    if(customer.canBuyAlcohol()) {
        // Do nothing.
    } else {
        // ...
    }

อย่างน้อยก็แย่ถ้าไม่เลว

ผมเขียนใน BCPL หลายปีที่ผ่านมาและในภาษาที่มีIFข้อและUNLESSข้อเพื่อให้คุณสามารถรหัสอื่น ๆ อีกมากมาย readably เป็น:

    unless(customer.canBuyAlcohol()) {
        // ...
    }

ซึ่งดีกว่าอย่างมีนัยสำคัญ แต่ก็ยังไม่สมบูรณ์แบบ


กระบวนการส่วนตัวของฉัน

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

  if (returnVal == JFileChooser.APPROVE_OPTION) {
    handleFileChosen();
  } else {
    // TODO: Handle case where they pressed Cancel.
  }

ฉันพบว่าโดยทั่วไปฉันใช้งานelseไม่ค่อยได้ในโค้ดเพราะมักจะสามารถระบุกลิ่นรหัสได้


การจัดการบล็อก "ว่างเปล่า" ของคุณจะอ่านเหมือนการขัดถูรหัสมาตรฐานเมื่อติดตั้ง thngs ...
Deduplicator

unlessบล็อกเป็นคำแนะนำที่ดีและแทบจะไม่ได้ถูกคุมขังใน BCPL
tchrist

@TobySpeight โอ๊ะโอ มันอย่างใดหนีความสนใจของฉันว่าสิ่งที่ผมเคยเขียนในฐานะที่เป็นจริง... return(ในความเป็นจริงมีk=-1, n=-2ผลตอบแทนครั้งแรกที่จะได้รับการ แต่นี้เป็นที่สงสัยส่วนใหญ่.)
เดวิด Richerby

โมเดิร์นมี Perl และif unlessยิ่งไปกว่านั้นมันยังอนุญาตให้ใช้คำสั่งเหล่านี้เพื่อให้คุณสามารถพูดprint "Hello world!" if $born;หรือprint "Hello world!" unless $dead;และทั้งสองอย่างจะทำสิ่งที่คุณคิดว่าพวกเขาทำ
CVn

1

สำหรับจุดแรกฉันได้ใช้ภาษาที่บังคับให้ใช้คำสั่ง IF เพื่อใช้วิธีนี้ (ใน Opal ภาษาที่อยู่หลัง scraper หน้าจอเมนเฟรมสำหรับวางส่วนหน้า GUI บนระบบเมนเฟรม) และมีบรรทัดเดียวสำหรับ IF และอื่น ๆ มันไม่ได้เป็นประสบการณ์ที่น่ารื่นรมย์!

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

เวลาที่ฉันใช้บางอย่างเช่นคำสั่งพิเศษเหล่านี้คือเมื่อใช้การประมวลผลชนิด CASE / WHEN ฉันมักจะเพิ่มมาตราเริ่มต้นแม้ว่ามันจะว่างเปล่า นี่เป็นนิสัยในระยะยาวจากภาษาที่จะผิดพลาดหากไม่ได้ใช้ประโยคดังกล่าวและบังคับให้คิดว่าสิ่งต่าง ๆ ควรจะผ่านออกมาหรือไม่

เมนเฟรมที่ผ่านมานาน (เช่น PL / 1 และ COBOL) เป็นที่ยอมรับกันว่าการตรวจสอบเชิงลบมีประสิทธิภาพน้อยกว่า สิ่งนี้สามารถอธิบายจุดที่ 2 ได้แม้ว่าทุกวันนี้จะมีการประหยัดประสิทธิภาพที่สำคัญกว่าอย่างมาก

ตรรกะเชิงลบมีแนวโน้มที่จะอ่านได้น้อยลงแม้ว่าจะไม่มากในคำสั่ง IF ง่ายๆ


2
ฉันเข้าใจแล้วมันเป็นเรื่องธรรมดาในบางครั้ง
Patsuan

@ Patuan - ใช่ แม้ว่าจะเป็นตอนที่แอสเซมบลีเมนเฟรมเป็นทางเลือกที่สำคัญสำหรับโค้ดที่มีประสิทธิภาพ
กระตุ้น

1
"นานมาแล้ว ... เป็นที่ยอมรับกันว่าการตรวจสอบด้านลบมีประสิทธิภาพน้อยลง" ดีที่พวกเขามีเว้นแต่คอมไพเลอร์เพิ่มประสิทธิภาพในการif !A then B; else C if A then C; else Bการคำนวณเชิงลบของเงื่อนไขคือคำสั่ง CPU เพิ่มเติม (แม้ว่าคุณจะพูดแบบนี้ก็ไม่น่าจะมีประสิทธิภาพลดลงอย่างมีนัยสำคัญ )
David Richerby

@DavidRicherby และถ้าเราพูดโดยทั่วไปภาษาบางภาษาสามารถทำให้การปรับให้เหมาะสมนั้นเป็นไปได้ยาก ใช้ C ++ พร้อมโอเวอร์โหลด!และ==โอเปอเรเตอร์เป็นต้น ไม่ใช่ว่าทุกคนควรทำอย่างนั้นจริงๆจงใส่ใจคุณ
CVn

1

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

ปัญหาเกี่ยวกับการหลีกเลี่ยงเนกาทีฟสมควรได้รับความสนใจมากกว่า: โดยปกติแล้วเมื่อใดก็ตามที่คุณต้องการใช้ค่าบูลีนคุณต้องมีบล็อคของโค้ดเพื่อให้ทำงานเมื่อตั้งค่าและบล็อกอื่น ๆ จะทำงานเมื่อไม่ได้ตั้งค่า เช่นถ้าคุณบังคับใช้กฎห้ามเชิงลบคุณจะต้องมีif() {} else {...}ข้อความสั่ง (ด้วยifบล็อกว่างเปล่า!) หรือสร้างบูลีนที่สองสำหรับบูลีนแต่ละรายการที่มีค่าที่ถูกลบ ตัวเลือกทั้งสองไม่ดีเนื่องจากผู้อ่านของคุณสับสน

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


0

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


1
ฉันได้ยินคุณไม่เคยทำงานให้กับนายจ้างที่เกรดประสิทธิภาพของคุณขึ้นอยู่กับ SLOCs ผลิตต่อระยะเวลาพ ...
CVn

0

ยังมีรูปแบบอื่นที่ยังไม่ได้กล่าวถึงเกี่ยวกับการจัดการเคสที่สองที่มี if-block ที่ว่างเปล่า วิธีหนึ่งในการจัดการกับมันก็คือการกลับมาในบล็อกถ้า แบบนี้:

void foo()
{
    if (condition) return;

    doStuff();
    ...
}

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


0

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

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

var even = if (n % 2 == 0) {
  return "even";
} else {
  return "odd";
}

ตอนนี้ในภาษาที่มีรูปแบบแรงบันดาลใจจาก C สไตล์หรือ C (เช่น Java, C # และ JavaScript เพียงเพื่อตั้งชื่อไม่กี่) นี้ดูเหมือนแปลก อย่างไรก็ตามมันดูคุ้นเคยมากขึ้นเมื่อเขียนเช่น:

var even = (n % 2 == 0) ? "even" : "odd";

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


0

... คำสั่ง if ควรจะตามด้วยคำสั่ง else ไม่ว่าจะมีบางอย่างที่จะใส่เข้าไปหรือไม่

ผมไม่เห็นด้วยif (a) { } else { b(); }ควรจะเขียนใหม่เป็นif (!a) { b(); }และควรจะเขียนใหม่เป็นif (a) { b(); } else { }if (a) { b(); }

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

ประการที่สองจะเป็นการดีกว่าที่จะทดสอบค่าจริงแทนที่จะเป็นเท็จ นั่นหมายความว่าเป็นการดีกว่าที่จะทดสอบตัวแปร 'doorClosed' แทนที่จะเป็นตัวแปร '! doorOpened'

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

ฉันมีแนวโน้มที่จะสงสัยสัญชาตญาณของฉัน

มันเป็นการดีที่จะตั้งคำถามต่อไป

เป็นการฝึกที่ดี / ไม่ดี / "ไม่สำคัญ"?

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

มันเป็นเรื่องธรรมดา

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


0

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

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

เมื่อมีการระบุไว้

ประการที่สองจะเป็นการดีกว่าที่จะทดสอบค่าจริงแทนที่จะเป็นเท็จ นั่นหมายความว่าเป็นการดีกว่าที่จะทดสอบตัวแปร 'doorClosed' แทนที่จะเป็นตัวแปร '! doorOpened'

เหตุผลของเขาคือทำให้ชัดเจนว่ารหัสกำลังทำอะไร

จากมุมมองของฉันสมมติฐานถูกสร้างขึ้นที่นี่ว่าสถานะประตูเป็นสถานะไบนารีเมื่ออันที่จริงแล้วอย่างน้อยก็เป็นสถานะที่ประกอบไปด้วย:

  1. ประตูเปิดอยู่.
  2. ประตูไม่ได้เปิดอย่างเต็มที่หรือปิดอย่างเต็มที่
  3. ประตูปิด.

ดังนั้นขึ้นอยู่กับตำแหน่งของเซ็นเซอร์ดิจิตอลไบนารีตัวเดียวคุณสามารถคาดเดาได้หนึ่งในสองแนวคิด:

  1. หากเซ็นเซอร์อยู่ด้านเปิดของประตู: ประตูเปิดอยู่หรือไม่เปิด
  2. หากเซ็นเซอร์อยู่บนปิดด้านข้างของประตู: ประตูถูกปิดหรือไม่ปิด

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

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


สำหรับวัตถุประสงค์ในการสนทนาสำหรับงานที่ฉันทำจำนวนข้อมูลที่ฉันมีอยู่เกี่ยวกับสถานะของระบบขึ้นอยู่กับฟังก์ชันการทำงานที่ระบบรวมต้องการ

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

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

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

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


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

@Sanchises คำแถลงนั้นไม่ขัดแย้งกับที่คุณนำออกไปจากบริบท คำแถลงแรกอยู่ในบริบทที่การวัดไบนารี่ที่เป็นปฏิปักษ์สองอันไม่สามารถแลกเปลี่ยนได้ด้วยการปฏิเสธไบนารี คำสั่งที่สองอยู่ในบริบทที่ความรู้เพียงบางส่วนของสถานะที่ประกอบไปด้วยสามส่วนอาจเพียงพอสำหรับแอปพลิเคชันในการทำงานอย่างถูกต้อง สำหรับประตูนั้นคำถาม OPs นั้นมีการอ้างอิงถึงประตูที่เปิดและปิด ฉันแค่ชี้ให้เห็นถึงสมมติฐานที่ชัดเจนที่สามารถมีอิทธิพลต่อวิธีการปฏิบัติต่อข้อมูล
Peter M

-1

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

ที่กล่าวว่ามีความเกลียดชังมากสำหรับคนอื่นที่ว่างเปล่า "มันเปลืองเส้น" "การพิมพ์พิเศษ" ซึ่งไม่ดีเลย คุณสามารถสร้างอาร์กิวเมนต์สำหรับย้ายวงเล็บไปยังบรรทัดเดียวกันได้หากคุณต้องการพื้นที่แนวตั้งจริงๆ แต่ถ้านั่นเป็นปัญหาคุณไม่ควรใส่ {ลงในบรรทัดแยกต่างหาก

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

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

static var cached = null

func getCached() {
    if !cached {
        cached = (some calculation, etc)
    }

    return cached
}

ถ้าตรรกะ (จิต / อังกฤษ) ที่เกิดขึ้นจริงเกี่ยวข้องกับการลบดังนั้นคำสั่ง if ควร

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