บรรทัดเพิ่มเติมในบล็อกและพารามิเตอร์เพิ่มเติมในรหัสที่สะอาด


33

บริบท

ในClean Codeหน้า 35 บอกไว้

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

ฉันเห็นด้วยอย่างสมบูรณ์ซึ่งทำให้รู้สึกมาก

ต่อมาในหน้า 40 มันพูดเกี่ยวกับข้อโต้แย้งฟังก์ชั่น

จำนวนอาร์กิวเมนต์ที่เหมาะสมที่สุดสำหรับฟังก์ชันคือศูนย์ (niladic) ถัดมาคือหนึ่ง (monadic) ตามมาด้วยสอง (dyadic) ควรหลีกเลี่ยงการโต้แย้งสามครั้ง (triadic) หากเป็นไปได้ มากกว่าสาม (polyadic) ต้องมีเหตุผลพิเศษมาก - จากนั้นไม่ควรใช้ต่อไป การโต้แย้งยาก พวกเขาใช้พลังความคิดมากมาย

ฉันเห็นด้วยอย่างสมบูรณ์ซึ่งทำให้รู้สึกมาก

ปัญหา

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

ฉันใช้สองบรรทัดในบล็อกหนึ่งรายการสำหรับสร้างสิ่งหนึ่งสำหรับเพิ่มไปยังผลลัพธ์:

    public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms)
    {
        List<Flurp> flurps = new List<Flurp>();
        foreach (BadaBoom badaBoom in badaBooms)
        {
            Flurp flurp = CreateFlurp(badaBoom);
            flurps.Add(flurp);
        }
        return flurps;
    }

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

    public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms)
    {
        List<Flurp> flurps = new List<Flurp>();
        foreach (BadaBoom badaBoom in badaBooms)
        {
            CreateFlurpInList(badaBoom, flurps);
        }
        return flurps;
    }

คำถาม

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


58
มีอะไรผิดปกติกับflurps.Add(CreateFlurp(badaBoom));?
cmaster

47
ไม่มันเป็นเพียงคำสั่งเดียว มันเป็นเพียงแค่การแสดงออกที่ซ้อนกันเล็กน้อย(ระดับที่ซ้อนกันเดียว) และถ้าความเรียบง่ายf(g(x))ขัดกับคู่มือนำสไตล์ของคุณฉันก็ไม่สามารถแก้ไขไกด์นำเที่ยวของคุณได้ ฉันหมายความว่าคุณไม่ได้แยกออกsqrt(x*x + y*y)เป็นสี่บรรทัดใช่ไหม? และนั่นคือ subexpressions สามซ้อน (!) ซ้อนกันสองระดับ (!) ซ้อนกันภายใน (หอบ!) เป้าหมายของคุณควรอ่านได้ไม่ใช่คำสั่งของผู้ดำเนินการ ถ้าคุณต้องการในภายหลังดีฉันมีภาษาที่สมบูรณ์แบบสำหรับคุณ: Assembler
cmaster

6
@cmaster แม้แต่ชุดประกอบ x86 ก็ไม่ได้มีคำสั่งตัวดำเนินการเดี่ยวอย่างเคร่งครัด โหมดการกำหนดแอดเดรสหน่วยความจำมีการดำเนินการที่ซับซ้อนมากมายและสามารถใช้สำหรับการคำนวณได้ - ในความเป็นจริงคุณสามารถสร้างคอมพิวเตอร์ทัวริงที่สมบูรณ์ได้โดยใช้เพียงmovคำสั่งx86 และหนึ่งเดียวjmp toStartในตอนท้าย มีคนสร้างคอมไพเลอร์ที่ทำเช่นนั้นจริงๆ: D
Luaan

5
@ Luaan อย่าพูดถึงrlwimiคำสั่งที่น่าอับอายใน PPC (นั่นหมายถึง Rotate Left Word Insert Mask ทันที) คำสั่งนี้ใช้เวลาไม่น้อยกว่าห้าตัวถูกดำเนินการ (สองรีจิสเตอร์และค่าทันทีสามค่า) และดำเนินการดังต่อไปนี้: เนื้อหารีจิสเตอร์หนึ่งหมุนโดยกะทันที สร้างด้วยการรัน 1 บิตเดียวซึ่งถูกควบคุมโดยตัวถูกดำเนินการทันทีอีกสองตัวและบิตที่ตรงกับ 1 บิตในรูปแบบนั้นในตัวถูกดำเนินการลงทะเบียนอื่นถูกแทนที่ด้วยบิตที่สอดคล้องกันของรีจิสเตอร์หมุน คำสั่งเด็ดมาก :-)
cmaster

7
@ R.Schmitz "ฉันกำลังเขียนโปรแกรมวัตถุประสงค์ทั่วไป" - จริง ๆ แล้วคุณไม่ใช่คุณกำลังเขียนโปรแกรมเพื่อวัตถุประสงค์เฉพาะ (ฉันไม่รู้ว่ามีจุดประสงค์อะไรแต่ฉันสมมติว่าคุณทำ ;-) มีนับพันของวัตถุประสงค์สำหรับการเขียนโปรแกรมและการเขียนโปรแกรมที่ดีที่สุดสำหรับพวกเขาในรูปแบบที่แตกต่างกัน - เพื่อให้สิ่งที่เหมาะสมสำหรับคุณอาจจะไม่เหมาะสำหรับคนอื่น ๆ และในทางกลับกัน: คำแนะนำบ่อยครั้งที่นี่เป็นที่แน่นอน (" มักจะทำ x; Y คือไม่ดี "ฯลฯ ) โดยไม่สนใจว่าในบางโดเมนจะทำไม่ได้อย่างเต็มที่ นั่นเป็นสาเหตุที่คำแนะนำในหนังสือเช่น Clean Code ควรใช้เกลือ (จริง)
นิดหน่อยเสมอ

คำตอบ:


104

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

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

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

หากเป็นไปได้ที่จะทำได้ดีกว่าโดยการสังเกตว่า "แปลงองค์ประกอบทั้งหมดจากรายการเป็นรายการอื่น" เป็นรูปแบบทั่วไปที่มักจะถูกแยกออกไปโดยใช้การทำงานที่map()ใช้งานได้ ใน C # Selectผมคิดว่ามันเรียกว่า บางสิ่งเช่นนี้

public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms)
{
    return badaBooms.Select(BadaBoom => CreateFlurp(badaBoom)).ToList();
}

7
รหัสยังคงไม่ถูกต้องและจะทำให้ล้อหมุนวนกลับมาอย่างไม่มีจุดหมาย ทำไมต้องโทรCreateFlurps(someList)เมื่อ BCL ให้มาแล้วsomeList.ConvertAll(CreateFlurp)?
Ben Voigt

44
@BenVoigt นี่เป็นคำถามระดับการออกแบบ ฉันไม่สนใจไวยากรณ์ที่แน่นอนโดยเฉพาะอย่างยิ่งเมื่อไวท์บอร์ดไม่มีคอมไพเลอร์ (และฉันเขียน C # ครั้งสุดท้ายใน '09) ประเด็นของฉันไม่ใช่“ ฉันได้แสดงรหัสที่ดีที่สุดเท่าที่จะเป็นไปได้” แต่“ นอกเหนือไปจากนี้นี่เป็นรูปแบบทั่วไปที่แก้ไขได้แล้ว” Linq เป็นวิธีหนึ่งที่จะทำมัน ConvertAll ที่คุณพูดถึงอีก ขอบคุณสำหรับการแนะนำทางเลือกนั้น
amon

1
คำตอบของคุณนั้นสมเหตุสมผล แต่ข้อเท็จจริงที่ว่า LINQ จะสรุปตรรกะออกไปและลดข้อความให้เหลือหนึ่งบรรทัดหลังจากทั้งหมดดูเหมือนจะขัดแย้งกับคำแนะนำของคุณ ในฐานะที่เป็นบันทึกด้านข้างBadaBoom => CreateFlurp(badaBoom)เป็นซ้ำซ้อน; คุณสามารถผ่านCreateFlurpเป็นฟังก์ชันโดยตรง ( Select(CreateFlurp)) (เท่าที่ฉันรู้มันเป็นกรณีนี้เสมอ)
jpmc26

2
โปรดทราบว่านี่จะเป็นการขจัดความต้องการวิธีการทั้งหมด ชื่อที่เป็นจริงมากขึ้นทำให้เข้าใจผิดและยากที่จะเข้าใจมากกว่าเพียงแค่การมองเห็นCreateFlurps badaBooms.Select(CreateFlurp)หลังมีการประกาศอย่างสมบูรณ์ - ไม่มีปัญหาในการย่อยสลายและดังนั้นจึงไม่จำเป็นต้องมีวิธีการทั้งหมด
Carl Leth

1
@ R.Schmitz มันไม่ได้เป็นเรื่องยากที่จะเข้าใจ แต่ก็น้อยง่ายbadaBooms.Select(CreateFlurp)ที่จะเข้าใจกว่า คุณสร้างวิธีการเพื่อให้ชื่อ (ระดับสูง) ย่อมาจากการใช้งาน (ระดับต่ำ) ในกรณีนี้พวกเขาอยู่ในระดับเดียวกันดังนั้นเพื่อค้นหาว่าเกิดอะไรขึ้นฉันต้องไปดูวิธีการ (แทนที่จะเห็นแบบอินไลน์) CreateFlurps(badaBooms)สามารถเก็บความประหลาดใจ แต่badaBooms.Select(CreateFlurp)ไม่สามารถ นอกจากนี้ยังทำให้เข้าใจผิดเพราะมันไม่สมควรขอแทนList IEnumerable
Carl Leth

61

จำนวนอาร์กิวเมนต์ที่เหมาะสมที่สุดสำหรับฟังก์ชันคือศูนย์ (niladic)

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

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

public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms)
{
    List<Flurp> flurps = new List<Flurp>();
    foreach (BadaBoom badaBoom in badaBooms)
    {
        flurps.Add(CreateFlurp(badaBoom));
    }
    return flurps;
}

แต่นั่นเป็นรหัสที่ยืดยาวมาก (C #) เพียงทำตาม:

IEnumerable<Flurp> CreateFlurps(IEnumerable<BadaBoom> badaBooms) =>
    from badaBoom in babaBooms select CreateFlurp(badaBoom);

14
ฟังก์ชั่นที่มีข้อโต้แย้งเป็นศูนย์หมายถึงการที่วัตถุห่อหุ้มข้อมูลที่ต้องการไม่ใช่สิ่งที่มีอยู่ในสถานะโกลบอลนอกวัตถุ
Ryathal

19
@Ryathal สองจุด: (1) หากคุณกำลังพูดถึงวิธีการสำหรับภาษา OO ส่วนใหญ่ (ทั้งหมด?) วัตถุนั้นจะถูกอนุมาน (หรือระบุไว้อย่างชัดเจนในกรณีของ Python) เป็นพารามิเตอร์แรก ใน Java, C # ฯลฯ วิธีการทั้งหมดเป็นฟังก์ชั่นที่มีอย่างน้อยหนึ่งพารามิเตอร์ คอมไพเลอร์เพียงซ่อนรายละเอียดนั้นจากคุณ (2) ฉันไม่เคยพูดถึง "ทั่วโลก" สถานะของวัตถุเป็นวิธีภายนอกเช่น
David Arno

17
ฉันค่อนข้างแน่ใจว่าเมื่อลุงบ๊อบเขียนว่า "ศูนย์" เขาหมายถึง "ศูนย์ (ไม่นับสิ่งนี้)"
Doc Brown

26
@DocBrown อาจเป็นเพราะเขาเป็นแฟนตัวยงของการผสมสถานะและฟังก์ชั่นในวัตถุดังนั้นโดย "ฟังก์ชั่น" เขาน่าจะหมายถึงวิธีการเฉพาะ และฉันก็ยังไม่เห็นด้วยกับเขา เป็นการดีกว่าที่จะให้วิธีการที่ต้องการเท่านั้นแทนที่จะปล่อยให้มันเข้าไปในวัตถุเพื่อให้ได้สิ่งที่ต้องการ (กล่าวคือเป็นคลาสสิก "บอกอย่าถาม" ในทางปฏิบัติ)
David Arno

8
@AlessandroTeruzzi, อุดมคติคือหนึ่งพารามิเตอร์ ศูนย์มีน้อยเกินไป นี่คือเหตุผลว่าทำไมภาษาที่ใช้งานได้นำมาใช้อย่างใดอย่างหนึ่งเป็นจำนวนพารามิเตอร์สำหรับวัตถุประสงค์ในการแก้ปัญหา (ในความเป็นจริงในบางภาษาที่ใช้งานได้ฟังก์ชั่นทั้งหมดมีพารามิเตอร์หนึ่งตัว: การปิดบังด้วยพารามิเตอร์ศูนย์จะไร้สาระ ที่ระบุว่า "เหมาะเป็นกี่เท่าที่เป็นไปได้เพราะฉะนั้นศูนย์ที่ดีที่สุดคือ" เป็นตัวอย่างของreductio น่าหัวเราะ
David Arno

19

คำแนะนำ 'รหัสสะอาด' ผิดอย่างสมบูรณ์

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

วิธีที่สองที่คุณพูดถึงไม่สมเหตุสมผลนักเนื่องจากคุณไม่ได้ถูกบังคับให้เพิ่มอาร์กิวเมนต์ที่สองเพื่อหลีกเลี่ยงสองบรรทัด

public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms)
    {
        List<Flurp> flurps = new List<Flurp>();
        foreach (BadaBoom badaBoom in badaBooms)
        {
            flurps.Add(badaBoom .CreateFlurp());
            //or
            badaBoom.AddToListAsFlurp(flurps);
            //or
            flurps.Add(new Flurp(badaBoom));
            //or
            //make flurps a member of the class
            //use linq.Select()
            //etc
        }
        return flurps;
    }

หรือ

foreach(var flurp in ConvertToFlurps(badaBooms))...

ตามที่ระบุไว้โดยคนอื่น ๆ คำแนะนำว่าฟังก์ชั่นที่ดีที่สุดคือสิ่งที่ไม่มีข้อโต้แย้งที่จะบิดเบือน OOP ที่ดีที่สุดและคำแนะนำที่ไม่ดีที่แย่ที่สุด


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

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

19
@ R.Schmitz ฉันได้อ่าน "Clean Code" ด้วยตัวเองและฉันก็ทำตามสิ่งที่หนังสือเล่มนี้บอกไว้ อย่างไรก็ตามเกี่ยวกับขนาดฟังก์ชั่นที่สมบูรณ์แบบซึ่งเป็นคำสั่งเดียวมันค่อนข้างผิดธรรมดา ผลกระทบเพียงอย่างเดียวคือมันเปลี่ยนรหัสสปาเก็ตตี้เป็นรหัสข้าว ผู้อ่านหายไปในฟังก์ชั่นมากมายที่สร้างความหมายที่สมเหตุสมผลเมื่อเห็นร่วมกัน มนุษย์มีความจุหน่วยความจำที่ใช้งานได้ จำกัด และคุณสามารถโอเวอร์โหลดได้ด้วยคำสั่งหรือด้วยฟังก์ชั่น คุณต้องสมดุลระหว่างสองถ้าคุณต้องการที่จะอ่าน หลีกเลี่ยงสุดขั้ว!
cmaster

@cmaster คำตอบเป็นเพียง 2 ย่อหน้าแรกเมื่อฉันเขียนความคิดเห็นนั้น มันเป็นคำตอบที่ดีกว่าตอนนี้
R. Schmitz

7
ตรงไปตรงมาฉันต้องการคำตอบที่สั้นกว่าของฉัน มีการพูดคุยทางการทูตมากเกินไปในคำตอบส่วนใหญ่ คำแนะนำที่ยกมานั้นผิดธรรมดาไม่จำเป็นต้องคาดเดากับ 'ความหมายจริงๆ' หรือบิดไปมาเพื่อลองและตีความหมายที่ดี
Ewan

15

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

และฉันขอเสนอตัวเลือกที่สามที่ดีที่สุด:

public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms)
{
    return badaBooms.Select(CreateFlurp).ToList();
}

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


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

10

อาร์กิวเมนต์หนึ่งเวอร์ชันนั้นดีกว่า แต่ไม่ใช่ในขั้นต้นเนื่องจากจำนวนอาร์กิวเมนต์

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

ถ้าคุณให้ผมด้วยCreateFlurp(BadaBoom)ผมสามารถใช้ที่มีประเภทใด ๆ ของภาชนะคอลเลกชัน: ง่ายFlurp[], List<Flurp>, LinkedList<Flurp>, Dictionary<Key, Flurp>และอื่น ๆ แต่ด้วยCreateFlurpInList(BadaBoom, List<Flurp>)ฉันจะกลับมาหาคุณในวันพรุ่งนี้เพื่อขอดูCreateFlurpInBindingList(BadaBoom, BindingList<Flurp>)โมเดลของฉันเพื่อรับการแจ้งเตือนว่ารายการมีการเปลี่ยนแปลง yuck!

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

ค่อนข้างบ่อยฉันพบว่าตัวเองสร้างรายการจากรายการอื่น

เป็นเพียงเรื่องของการใช้เครื่องมือที่มีอยู่ รุ่นที่สั้นที่สุดมีประสิทธิภาพมากที่สุดและดีที่สุดคือ:

var Flurps = badaBooms.ConvertAll(CreateFlurp);

ไม่เพียง แต่โค้ดที่น้อยกว่านี้สำหรับคุณในการเขียนและทดสอบ แต่ยังเร็วกว่าเพราะList<T>.ConvertAll()ฉลาดพอที่จะรู้ว่าผลลัพธ์จะมีจำนวนรายการเท่ากันกับอินพุตและจัดสรรล่วงหน้ารายการขนาดที่ถูกต้อง ในขณะที่รหัสของคุณ (ทั้งสองเวอร์ชัน) ต้องการการเพิ่มรายการ


List.ConvertAllอย่าใช้ วิธีสำนวนการแมปนับของวัตถุกับวัตถุที่แตกต่างกันใน C # Selectจะเรียกว่า เหตุผลเดียวที่ConvertAllสามารถใช้ได้แม้ที่นี่เป็นเพราะ OP จะไม่สมควรขอListในวิธีการ - IEnumerableมันควรจะเป็น
Carl Leth

6

ระลึกถึงเป้าหมายโดยรวม: การทำให้โค้ดอ่านและบำรุงรักษาง่าย

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

ตัวอย่างเช่นในกรณีของคุณแทนที่การใช้งานทั้งหมดด้วย var

flups = badaBooms.Select(bb => new Flurp(bb));

อาจเป็นไปได้ หรือคุณอาจทำสิ่งที่ชอบ

flups.Add(new Flurp(badaBoom))

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

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

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