การสร้างฟังก์ชั่นที่ซ้อนกันเพื่อเหตุผลด้านสุนทรียะล้วนๆ?


16

ฉันสงสัยอยู่เสมอว่าโปรแกรมเมอร์คนอื่น ๆ คิดอย่างไรเกี่ยวกับความคิดในการสร้างฟังก์ชั่นความงามที่บริสุทธิ์

Function ProcessBigDataว่าฉันมีฟังก์ชั่นที่ประมวลผลชิ้นของข้อมูลที่: Step1บอกว่าผมต้องทำตามขั้นตอนกระบวนการหลายใช้ได้เฉพาะสำหรับข้อมูลที่: Step2, Step3,

aproach ปกติฉันเห็นมากที่สุดในซอร์สโค้ดคือการเขียนความเห็นเช่น:

Function ProcessBigData:
    # Does Step1
    Step1..
    Step1..

    #Does Step2
    Step2..
    Step2..

สิ่งที่ฉันมักจะทำ แต่มักจะรู้สึกผิดเพราะขาดรูปแบบการเข้ารหัสโดยเพื่อนร่วมงานคือ:

Function ProcessBigData:
    Function Step1:
        Step1..
        Step1..

    Function Step2:
        Step2..
        Step2..

    Step1() -> Step2()

ฉันเป็นห่วงถ้ามีข้อเสียสำหรับสไตล์ดังกล่าวในJavascriptและPython

มีทางเลือกอื่นที่ฉันไม่เห็นหรือไม่?


3
ฉันไม่สามารถพูดอะไรเกี่ยวกับ Python ได้ แต่สำหรับ Javascript มีค่าใช้จ่ายด้านประสิทธิภาพสำหรับฟังก์ชั่นที่ซ้อนกัน: เอ็นจิ้น JavaScript ส่วนใหญ่ใช้โครงสร้างคล้ายรายการที่เชื่อมโยงเพื่อแสดงขอบเขตตัวแปร การเพิ่มเลเยอร์เพิ่มเติมของฟังก์ชั่นจึงบังคับให้เครื่องยนต์ค้นหาโครงสร้างข้อมูลที่ยาวขึ้น / ใหญ่ขึ้นเมื่อแก้ไขตัวแปร ในทางกลับกันรากเหง้าแห่งความชั่วร้ายทั้งหมดนั้นคือการปรับให้เหมาะสมก่อนเวลาอันควร :)
Marco

คำตอบ:


4

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

local
    fun recursion_helper (iteration_variable, accumulator) =
        ... (* implementation goes here *)
in
    fun recursive_function (arg) = recursion_helper(arg, 0);
end

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

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


11

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

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

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

การอ่าน

รหัสขั้นตอนมากกว่า 200 บรรทัด (เนื้อหาของฟังก์ชัน) อ่านยาก ฟังก์ชั่นบรรทัด 2-20 อ่านง่าย รหัสสำหรับมนุษย์

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

ขอบเขตตัวแปร จำกัด

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

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

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

การทดสอบหน่วย

แต่ละภารกิจย่อยใช้ฟังก์ชั่น (หรือแม้กระทั่งชั้นเรียน) เป็นชิ้นส่วนของรหัสแบบสแตนด์อะโลนทดสอบได้ ประโยชน์ของการทดสอบหน่วยและTDD ได้รับการบันทึกไว้ที่อื่น

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

ทำงานเป็นทีม / ออกแบบจากบนลงล่าง

งานย่อยสามารถเขียนโดยคนต่าง ๆ ได้อิสระหากจำเป็น

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

การใช้รหัสซ้ำ

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

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

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


2
นี่เป็นจุดที่ถูกต้องจริงๆสำหรับการใช้งานฟังก์ชั่นทั่วไป แต่ฉันไม่ได้รับคำตอบจากคุณถ้าคุณคิดว่าฟังก์ชั่น NESTED เป็นความคิดที่ดี หรือคุณได้รับฟังก์ชั่นออกมาในขอบเขตต้นน้ำ?
Slytael

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