การเปลี่ยนแปลงใดที่ใหญ่เกินกว่าจะออกแบบได้โดยง่าย


11

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

โดยทั่วไปเมื่อเรียนรู้เกี่ยวกับการเขียนโปรแกรมเชิงวัตถุ, นามธรรม, แยกตัวประกอบ ฯลฯ จอกศักดิ์สิทธิ์ของการออกแบบ - และเหตุผลที่พวกเขาอ้างเสมอว่าคุณใช้เทคนิคการพัฒนาที่เป็นปัญหา - คือมันจะทำให้โปรแกรมของคุณ "ง่ายต่อการเปลี่ยนแปลง" , "maintainable", "ยืดหยุ่น" หรือคำพ้องความหมายใด ๆ ที่ใช้เพื่อแสดงแนวคิดเกี่ยวกับการผลิตที่ทำให้เกิดเสียงดังกล่าว ด้วยการทำเครื่องหมายส่วนตัวของ ivars ให้แยกรหัสออกเป็นวิธีเล็ก ๆ ที่มีอยู่ในตัวเองทำให้อินเตอร์เฟสทั่วไปทำให้คุณสามารถปรับเปลี่ยนโปรแกรมของคุณได้อย่างง่ายดาย

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

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

อย่างไรก็ตามเมื่อใดก็ตามที่การเปลี่ยนแปลงมีขนาดใหญ่และมีขนฟูนั่นคือการเปลี่ยนแปลง API - ไม่มีรูปแบบ "อันมีค่า" ของฉันเลยที่จะช่วยเหลือ การเปลี่ยนแปลงครั้งใหญ่ยังคงใหญ่รหัสที่ได้รับผลกระทบยังคงได้รับผลกระทบและงานการวางไข่หลายชั่วโมงอยู่ข้างหน้าฉัน

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

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

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


ฉันไม่เห็นว่าการเปลี่ยนแปลงในภาษาของคุณสัมผัสอะไร แต่ตัวแยกวิเคราะห์ คุณช่วยอธิบายเรื่องนี้ได้มั้ย
scarfridge

ใน smalltalk เหมือนภาษามันเป็นความจริงที่ว่าคุณจะต้องเท่านั้นที่จะแก้ไข parser เพราะมันจะเป็นเรื่องธรรมดาของการรักษาเป็นfoo metarg1: bar metarg2: baz foo.metarg1_metarg2_(bar, baz)อย่างไรก็ตามภาษาของฉันมีการเปลี่ยนแปลงที่ใหญ่กว่านั่นคือรายการตามพารามิเตอร์เป็นพารามิเตอร์ตามพจนานุกรมซึ่งมีผลต่อรันไทม์ แต่ไม่ใช่ตัวแยกวิเคราะห์ที่จริงแล้วเนื่องจากคุณสมบัติเฉพาะของภาษาของฉันฉันจะไม่เข้าไปตอนนี้ เนื่องจากไม่มีการแมปที่ชัดเจนระหว่างคำสั่งที่ไม่ได้จัดเรียงคำหลักและอาร์กิวเมนต์ตำแหน่งการใช้งานจึงเป็นปัญหาหลัก
มีอยู่จริง forall

คำตอบ:


13

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

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

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

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

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

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


+1 สำหรับการสนับสนุนเคสใหม่และเคสเก่าเพื่อให้คุณเลิกใช้งานได้
Erik Reppen

9

ฉันขอแนะนำให้คุณอ่านเรียงความBig Ball of Mud

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

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

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

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


1
+1: การออกแบบล่วงหน้าใหม่ ๆ ไม่ค่อยประสบความสำเร็จ การออกแบบที่ประสบความสำเร็จนั้นเป็นการสรุปผลของการออกแบบที่ผ่านการพิสูจน์แล้วหรือถูกขัดเกลาซ้ำ ๆ
kevin cline

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

4

โดยทั่วไปแล้วจะมี "ส่วนของรหัส" (ฟังก์ชั่นวิธีการวัตถุอะไรก็ตาม) และ "ส่วนต่อประสานระหว่างส่วนของรหัส" (APIs การประกาศฟังก์ชันสิ่งใดก็ตามรวมถึงพฤติกรรม)

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

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

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


ข้อดีอีกอย่างของ OOP คือการห่อหุ้มข้อมูลด้วยตรรกะที่ทำงานบนนั้นนำไปสู่การเชื่อมต่อสาธารณะที่มีขนาดเล็กลง (ถ้าทำได้ดี)
Michael Borgwardt

2

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

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

กล่าวโดยย่อการเปลี่ยนแปลงทั้งหมดทำได้ง่ายขึ้นด้วยการออกแบบที่ดี แต่การออกแบบที่ดีไม่สามารถเปลี่ยนการเปลี่ยนแปลงครั้งใหญ่ให้กลายเป็นเรื่องเล็กได้ (การออกแบบที่ไม่ดี / ไม่มีเลยในทางกลับกันสามารถเปลี่ยนการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ ให้กลายเป็นการเปลี่ยนแปลงครั้งใหญ่ได้)


1

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

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

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

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


3
ตำแหน่งเริ่มต้นอาจเป็นลบได้เช่นกัน อย่าดูถูกพลังของ Legacy :)
Maglob

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

1

ค่าใช้จ่ายของการเปลี่ยนแปลงกวาดมักจะเป็นสัดส่วนกับขนาดของฐานรหัส ดังนั้นการลดขนาดของรหัสฐานควรเป็นหนึ่งในเป้าหมายของการออกแบบที่เหมาะสม

ในตัวอย่างของคุณการออกแบบที่เหมาะสมทำให้งานของคุณง่ายขึ้น: ต้องทำการเปลี่ยนแปลงทั่วทั้งฐานรหัส 2000 บรรทัดแทนที่จะเป็นฐานรหัส 20000 หรือ 200,000 รายการ

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

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


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