วิธีการป้องกันการเยื้องลึก? [ปิด]


17

ฉันสามารถใช้ขั้นตอนและมาตรการใดในการป้องกันการเยื้องในโค้ดของฉัน


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

3
ใช้ความกว้างแท็บที่เล็กลง
mipadi

6
Arrowhead anti-pattern Google เคล็ดลับมากมาย
NimChimpsky

2
หยุดใช้ python: D
back2dos

ได้เวลาดูตรรกะการควบคุมและวนรอบของคุณ ดูเหมือนว่ารหัสของคุณจะซับซ้อนกว่าที่ควรจะเป็นและการกำหนดแนวคิดใหม่ของปัญหาจะนำไปสู่รหัสที่สั้นกว่ามาก ศึกษารหัสที่ดีและเรียนรู้เทคนิคต่าง ๆ
Macneil

คำตอบ:


14

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


26

สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือแยกวิธี:

int Step1(int state)
{
    if (state == 100)
    {
        return Step2(state);
    }
    else
    {
        return Step3(state);
    }
}

int Step2(int state)
{
    if (state != 100)
    {
        throw new InvalidStateException(2, state);
    }

    // ....
}

2
สิ่งนี้ยังใช้งานได้สำหรับif-conditions ที่ซับซ้อน เมื่อถึงจุดสุดยอดคุณจะพบกับ pseudocode ที่สามารถเรียกใช้งานได้
Alan Plum

สิ่งที่ดีที่สุดที่เราสามารถทำได้คือการวางelseบล็อคที่ไม่จำเป็น
sepehr

16

บางทีคุณอาจพิจารณาคำสั่งป้องกันหรือไม่

แทน

public void DoSomething(int value){
    if (someCondition){
           if(someOtherCondition){
                if(yetAnotherCondition){
                       //Finally execute some code
                }
           }
    }
} 

ทำ

public void DoSomething(int value){
    if(!(someCondition && someOtherCondition && yetAnotherCondition)){
        return;
        //Maybe throw exception if all preconditions must be true
    }
    //All preconditions are safe execute code
}

หากคุณเคยได้รับโอกาสฉันขอแนะนำให้คุณอ่าน Code Complete โดย Steve McConnell เขาได้รับคำแนะนำที่ดีมากมายในหัวข้อเหล่านี้

http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_6

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ "คำสั่งป้องกัน" ดูที่: https://sourcemaking.com/refactoring/replace-nested-conditional-with-guard-clauses


8

Invert ของคุณifs

แทน:

if (foo != null)
{
    something;
    something;
    if (x)
    {        
       something;
    }
    something;
}
else
{
    boohoo;
}

ฉันจะเขียน:

if (foo == null)
{
    boohoo;
    return;
}
something;
something;
if (x)
{        
   something;
}
something;

เช่นเดียวกับบล็อกif- elseหากelseซ้อนกันน้อยกว่าหรือน้อยกว่าให้เปลี่ยนกลับเป็นค่าเดิม

ตรวจสอบค่าพารามิเตอร์ในที่เดียว

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


1
สไตล์นี้มีชื่อเฉพาะหรือไม่?
โทมั

@ThomasLauria ไม่อยากรู้ มันเพิ่งจะออกเร็ว Ifที่จุดเริ่มต้นของรหัสที่หยุดการไหลของการดำเนินการเนื่องจากเงื่อนไขบางอย่างที่ไม่ได้พบกันยังเป็นที่รู้จักกันเป็นอนุประโยคปกป้องเช่น @JasonTuran ชี้ให้เห็น และดูเหมือนว่าจะใกล้เคียงกับชื่อที่แตกต่าง
Konrad Morawski

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

4

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

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


2

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

นอกจากนี้เยื้องสองช่องว่างแทนสี่


5
เมื่อคุณไปถึงขั้นตอนของการเปลี่ยนความกว้างแท็บของคุณคุณกำลังมีปัญหามาก ...
Daenyth

แท็บสองช่องว่างเป็นเรื่องยาก ....
David Thornley

6
การเปลี่ยนการเยื้องเป็นเพียงวิธีการซ่อนปัญหาไม่ใช่วิธีแก้ปัญหา
Murph

1

ฉันไม่เห็นว่าการลบรอยลึกเป็นปัญหาเชิงหมวดหมู่ที่จะลบออก

โดยทั่วไปแล้วแทนที่จะเป็น ifs ซ้อนกันฉันชอบที่จะเขียนคำสั่งตรรกะ:

if (foo && bar && baz) 

ค่อนข้างมากกว่า

if foo 
 if bar
   if baz

ปัญหาคือยังมีอยู่และในขณะที่ลูปที่ไม่อยู่ภายใต้กฎนี้
Tamara Wijsman

@TomWij: ฉันไม่ได้พยายามที่จะชักนำให้เกิดความจำเป็นเกี่ยวกับสไตล์
พอลนาธาน

1
??? `` `` ``
Tamara Wijsman

1

ฉันไม่เชื่อตัวเอง แต่ตาม Code Complete นี่เป็นสถานที่ที่เหมาะสมที่จะใช้break(ถ้าทีมของคุณอยู่บนเครื่อง) ฉันคิดว่านี่เป็นที่ยอมรับมากขึ้นกับโปรแกรมเมอร์ C ++ แต่ที่breakใช้ในswitchงบมากกว่าที่มีกับโปรแกรมเมอร์ Delphi ที่breakใช้เฉพาะเมื่อคุณไม่รู้สึกเหมือนเขียนwhileวน


0

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

แทน :

 {if (networkCardIsOn() == true)
     {if (PingToServer() == true)
        {if (AccesLogin(login,pass) == true)
             {if (nextCondition == true)
                ...
         }
     }
 }

ฉันกำลังเขียน:

 {vbContinue = true;

 if (vbContinue) {
       vbContinue = networkCardIsOn();
       if (vbContinue == false) {
             code to Handle This Error();
       } 
 }

 if (vbContinue) {
       vbContinue = PingToServer();
       if (vbContinue == false) {
             code to HandleThisError2();
       } 
 }

 if (vbContinue) {
       vbContinue = AccesLogin(login,pass);
      if (vbContinue == false) {
             HandleThisErrorToo();
       } 
 }
 ...

นี่เป็นครั้งแรกที่ฉันรู้สึกแปลก ๆ แต่เนื่องจากฉันใช้สิ่งนี้ค่าบำรุงรักษาจึงถูกแบ่งครึ่งและสมองของฉันก็เย็นลงในตอนท้ายของวัน

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

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

กำไรอีกอย่างก็คือ "ทางหนีและเงื่อนไข" จากทั้งหมดที่ซ้อนอยู่ใน "if-else" เหล่านั้นจะง่ายขึ้น


คุณสามารถอธิบายรายละเอียดเกี่ยวกับ "ค่าใช้จ่ายในการบำรุงรักษาแบ่งครึ่ง" แล้วคุณจะรู้ได้อย่างไรว่าการหยุดดำเนินการนั้นเป็นอย่างไร
Chris

ฉันแก้ไขเสร็จแล้ว ฉันหวังว่าฉันจะตอบคำถามของคุณ ...
Pierre Watelet

2
หากคุณต้องการที่จะไปได้อย่างง่ายดายคุณมีบรรทัด errorohand_handling
พอลนาธาน

นั่นไม่ดีเลย ขออภัย แต่มันก็ไม่ได้ จากนั้นอีกครั้งฉันประหลาด
Murph

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