เมื่อฉันเขียนรหัสฉันพยายามทำให้รหัสของฉันสะอาดและอ่านง่ายที่สุดเท่าที่จะทำได้
ทุกครั้งที่มีเวลาที่คุณต้องข้ามเส้นและไปจากรหัสที่สะอาดดีเป็นรหัสที่น่าเกลียดเล็กน้อยเพื่อให้เร็วขึ้น
เมื่อไรที่จะข้ามเส้นนั้น?
เมื่อฉันเขียนรหัสฉันพยายามทำให้รหัสของฉันสะอาดและอ่านง่ายที่สุดเท่าที่จะทำได้
ทุกครั้งที่มีเวลาที่คุณต้องข้ามเส้นและไปจากรหัสที่สะอาดดีเป็นรหัสที่น่าเกลียดเล็กน้อยเพื่อให้เร็วขึ้น
เมื่อไรที่จะข้ามเส้นนั้น?
คำตอบ:
คุณข้ามเส้นเมื่อ
นี่คือตัวอย่างของโลกแห่งความจริง: ระบบทดลองที่ฉันกำลังทำงานกำลังผลิตข้อมูลช้าเกินไปใช้เวลานานกว่า 9 ชั่วโมงต่อการทำงานและใช้ CPU เพียง 40% แทนที่จะทำให้รหัสยุ่งมากเกินไปฉันย้ายไฟล์ชั่วคราวทั้งหมดไปยังระบบไฟล์ในหน่วยความจำ เพิ่ม 8 บรรทัดใหม่ของโค้ดที่ไม่น่าเกลียดและตอนนี้การใช้งาน CPU สูงกว่า 98% แก้ไขปัญหา; ไม่ต้องมีความน่าเกลียด
foo
และเปลี่ยนชื่อเดิมfoo_ref
- โดยปกติแล้วจะอยู่เหนือfoo
ไฟล์แหล่งที่มาทันที ในชุดทดสอบของฉันฉันเรียกfoo
และfoo_ref
ตรวจสอบความถูกต้องและการวัดประสิทธิภาพสัมพัทธ์
มันเป็นขั้วที่ผิดพลาด คุณสามารถสร้างรหัสได้อย่างรวดเร็วและง่ายต่อการดูแลรักษา
วิธีที่คุณเขียนมันสะอาดโดยเฉพาะโครงสร้างข้อมูลที่ง่ายที่สุดเท่าที่จะทำได้
จากนั้นคุณจะพบว่าเวลาอยู่ที่ใด (โดยการรันหลังจากที่คุณเขียนไม่ได้มาก่อน) และแก้ไขทีละครั้ง (นี่คือตัวอย่าง)
เพิ่ม:เรามักจะได้ยินเกี่ยวกับการแลกเปลี่ยนที่ถูกต้องเช่นการแลกเปลี่ยนระหว่างเวลาและหน่วยความจำหรือการแลกเปลี่ยนระหว่างความเร็วและการบำรุงรักษา? ในขณะที่เส้นโค้งดังกล่าวอาจมีอยู่จริงก็ไม่ควรคิดว่าโปรแกรมใดก็ตามที่อยู่บนเส้นโค้งหรือแม้กระทั่งบริเวณใกล้เคียง
โปรแกรมใด ๆ ที่อยู่บนเส้นโค้งสามารถทำได้ง่าย (โดยมอบให้กับโปรแกรมเมอร์ชนิดหนึ่ง) ทำให้ช้าลงมากและสามารถบำรุงรักษาได้น้อยกว่ามากและจากนั้นจะไม่อยู่ใกล้กับโค้ง โปรแกรมดังกล่าวมีพื้นที่เหลือเฟือที่จะทำให้ทั้งเร็วขึ้นและบำรุงรักษาได้ดี
จากประสบการณ์ของฉันนั่นคือจุดเริ่มต้นของโปรแกรมมากมาย
ใน OSS ของฉันฉันทำงานห้องสมุดหลายอย่างที่มุ่งเน้นไปที่ประสิทธิภาพซึ่งเชื่อมโยงอย่างลึกซึ้งกับโครงสร้างข้อมูลของผู้โทร (เช่นภายนอกห้องสมุด) ด้วย (โดยการออกแบบ) ไม่มีการมอบอำนาจให้แก่ประเภทที่เข้ามา วิธีที่ดีที่สุดในการทำให้นักแสดงคนนี้คือการเขียนโปรแกรมเมตาซึ่ง (เนื่องจากฉันอยู่ใน. NET-land) หมายถึง IL-emit นั่นเป็นโค้ดที่น่าเกลียด แต่ก็เร็วมาก
ด้วยวิธีนี้ฉันยอมรับรหัสห้องสมุดอย่างมีความสุขอาจจะ "น่าเกลียด" กว่ารหัสแอปพลิเคชันเพียงเพราะมันมีการควบคุมอินพุต (หรืออาจจะไม่น้อยกว่า)ดังนั้นจึงจำเป็นต้องทำงานบางอย่างผ่านกลไกที่แตกต่างกัน หรือในขณะที่ฉันแสดงวันอื่น ๆ :
"การเขียนรหัสบนหน้าผาแห่งความวิกลจริตดังนั้นคุณไม่จำเป็นต้อง "
ตอนนี้รหัสแอปพลิเคชันจะแตกต่างกันเล็กน้อยเนื่องจากเป็นที่ที่นักพัฒนา "ปกติ" (มีสติ) มักจะลงทุนกับเวลาทำงานร่วมกัน / อาชีพเป็นจำนวนมาก เป้าหมายและความคาดหวังของแต่ละคนนั้นแตกต่างกันเล็กน้อย (IMO)
IMO คำตอบข้างต้นที่แนะนำว่าสามารถทำได้อย่างรวดเร็วและง่ายต่อการบำรุงรักษาคือการอ้างถึงรหัสแอปพลิเคชันที่ผู้พัฒนาสามารถควบคุมโครงสร้างข้อมูลได้มากขึ้นและไม่ได้ใช้เครื่องมือเช่นการเขียนโปรแกรมเมตา ที่กล่าวว่ามีวิธีการเขียนโปรแกรมเมตาที่แตกต่างกันโดยมีระดับความวิกลจริตและค่าใช้จ่ายในระดับที่แตกต่างกัน แม้แต่ในเวทีนั้นคุณต้องเลือกระดับนามธรรมที่เหมาะสม แต่เมื่อคุณอย่างแข็งขันบวกต้องการให้จัดการกับข้อมูลที่ไม่คาดคิดในวิธีที่เร็วที่สุดแน่นอน; มันอาจจะดูน่าเกลียด จัดการกับมัน;
เมื่อคุณสร้างโปรไฟล์รหัสและตรวจสอบว่าเป็นจริงทำให้เกิดการชะลอตัวที่สำคัญ
รหัสคลีนไม่จำเป็นต้องเป็นเอกสิทธิ์ของโค้ดที่รันเร็ว ปกติแล้วโค้ดที่อ่านยากจะถูกเขียนเพราะเขียนได้เร็วกว่าไม่ใช่เพราะรันเร็วกว่า
การเขียนรหัส "สกปรก" ในความพยายามที่จะทำให้เร็วขึ้นนั้นไม่ฉลาดนักเนื่องจากคุณไม่รู้ว่าการเปลี่ยนแปลงของคุณจะปรับปรุงอะไร Knuth กล่าวไว้อย่างดีที่สุด:
“ เราควรลืมเกี่ยวกับประสิทธิภาพเล็กน้อยพูดถึง 97% ของเวลา: การปรับให้เหมาะสมก่อนกำหนดเป็นรากของความชั่วร้ายทั้งหมดแต่เราไม่ควรผ่านโอกาสของเราในการวิจารณ์ 3% โปรแกรมเมอร์ที่ดีจะไม่ถูกกล่อมด้วยความพึงพอใจเช่นนี้ เขาจะฉลาดพอที่จะดูรหัสที่สำคัญอย่างระมัดระวัง แต่หลังจากได้รับการระบุรหัสแล้ว "
กล่าวอีกนัยหนึ่งเขียนรหัสสะอาดก่อน จากนั้นโปรไฟล์โปรแกรมผลลัพธ์และดูว่าส่วนนั้นเป็นปัญหาคอขวดของประสิทธิภาพหรือไม่ ถ้าเป็นเช่นนั้นให้เพิ่มประสิทธิภาพส่วนตามความจำเป็นและให้แน่ใจว่าได้รวมความคิดเห็นเอกสารมากมาย (อาจรวมถึงรหัสต้นฉบับ) เพื่ออธิบายการเพิ่มประสิทธิภาพ จากนั้นโปรไฟล์ผลลัพธ์เพื่อยืนยันว่าคุณได้ทำการปรับปรุงจริง
ตั้งแต่คำถามที่ว่า " รหัสยากที่จะอ่านอย่างรวดเร็ว" คำตอบง่ายๆคือไม่เคย ไม่เคยมีข้อแก้ตัวในการเขียนโค้ดที่อ่านยาก ทำไม? ด้วยเหตุผลสองประการ
เมื่อมันเป็นรหัสทิ้ง ฉันหมายความว่าตัวอักษร: เมื่อคุณเขียนสคริปต์เพื่อดำเนินการคำนวณ one-off หรืองานและรู้ด้วยความมั่นใจเช่นคุณจะไม่ต้องทำการกระทำนั้นอีกครั้งที่คุณสามารถ 'RM แหล่งแฟ้ม' โดยไม่ลังเลแล้วคุณอาจจะเลือก เส้นทางที่น่าเกลียด
ไม่อย่างนั้นมันเป็นขั้วที่ผิดพลาด - ถ้าคุณคิดว่าคุณต้องทำให้มันน่าเกลียดที่จะทำมันให้เร็วขึ้นคุณก็ทำผิด (หรือหลักการของคุณเกี่ยวกับสิ่งที่เป็นรหัสที่ดีต้องมีการแก้ไขการใช้ goto เป็นจริงค่อนข้างสง่างามเมื่อมันเป็นทางออกที่เหมาะสมในการแก้ไขปัญหา แต่มันไม่ค่อยเป็น)
เมื่อใดก็ตามที่ต้นทุนโดยประมาณของประสิทธิภาพต่ำในตลาดมากกว่าค่าใช้จ่ายโดยประมาณของการบำรุงรักษาโค้ดสำหรับโมดูลรหัสที่เป็นปัญหา
ผู้คนยังคงทำ SSE / NEON / etc แบบเข้ารหัสด้วยมือ การชุมนุมเพื่อลองและเอาชนะซอฟต์แวร์ของคู่แข่งบางรายบนชิปซีพียูยอดนิยมในปีนี้
อย่าลืมว่าคุณสามารถทำให้โค้ดที่อ่านยากเข้าใจง่ายโดยใช้เอกสารและการแสดงความคิดเห็นที่เหมาะสม
โดยทั่วไปโปรไฟล์หลังจากที่คุณเขียนโค้ดที่อ่านง่ายซึ่งทำหน้าที่ที่ต้องการ คอขวดอาจทำให้คุณต้องทำอะไรบางอย่างที่ทำให้มันดูซับซ้อนขึ้น แต่คุณต้องแก้ไขด้วยการอธิบายตัวเอง
สำหรับฉันมันเป็นสัดส่วนของความมั่นคง (เช่นในคอนกรีตซีเมนต์ดินเหนียวในเตาอบตั้งอยู่ในหินเขียนด้วยหมึกถาวร) ยิ่งรหัสของคุณไม่เสถียรมากเท่าไหร่ก็ยิ่งมีความเป็นไปได้ที่คุณจะต้องเปลี่ยนรหัสในอนาคตยิ่งมีความยืดหยุ่นที่จะต้องมีความยืดหยุ่นมากขึ้นเช่นดินเหนียวที่เปียกชื้น ฉันยังเน้นถึงความยืดหยุ่นและไม่สามารถอ่านได้ สำหรับผมแล้วความง่ายในการเปลี่ยนรหัสมีความสำคัญมากกว่าความง่ายในการอ่าน รหัสสามารถอ่านได้ง่ายและฝันร้ายที่เปลี่ยนไปและการใช้อะไรที่สามารถอ่านและเข้าใจรายละเอียดการใช้งานได้ง่ายหากพวกเขาเป็นฝันร้ายที่จะเปลี่ยนแปลง เว้นแต่เป็นเพียงแบบฝึกหัดทางวิชาการโดยทั่วไปจุดที่สามารถเข้าใจรหัสได้ง่ายในฐานข้อมูลการผลิตคือเจตนาที่จะสามารถเปลี่ยนแปลงได้ง่ายขึ้นตามที่ต้องการ ถ้ามันยากที่จะเปลี่ยน จากนั้นประโยชน์มากมายของการอ่านออกไปนอกหน้าต่าง ความสามารถในการอ่านโดยทั่วไปมีประโยชน์ในบริบทของความยืดหยุ่นเท่านั้นและความน่าเชื่อถือนั้นมีประโยชน์ในบริบทของความไม่แน่นอนเท่านั้น
แม้แต่การรักษาโค้ดที่จินตนาการได้ไม่ว่าจะอ่านง่ายหรือยากแค่ไหนก็ไม่ได้เป็นปัญหาหากไม่มีเหตุผลที่จะต้องเปลี่ยนมันให้ใช้มันเท่านั้น และเป็นไปได้ที่จะบรรลุถึงคุณภาพดังกล่าวโดยเฉพาะอย่างยิ่งสำหรับรหัสระบบระดับต่ำซึ่งประสิทธิภาพมักจะนับได้สูงสุด ฉันมีรหัส C ฉันยังคงใช้เป็นประจำซึ่งไม่ได้เปลี่ยนตั้งแต่ปลายยุค 80 ไม่จำเป็นต้องเปลี่ยนแปลงตั้งแต่นั้นมา รหัสนี้เขียนขึ้นในวันที่ยุ่งเหยิงและฉันแทบจะไม่เข้าใจเลย ถึงกระนั้นก็ยังใช้งานได้ในปัจจุบันและฉันไม่จำเป็นต้องเข้าใจการใช้งานเพื่อให้ได้ประโยชน์มากมาย
การทดสอบการเขียนอย่างละเอียดเป็นวิธีหนึ่งในการปรับปรุงเสถียรภาพ อีกอย่างคือการแยกส่วน หากรหัสของคุณไม่ได้ขึ้นอยู่กับสิ่งใดเหตุผลเดียวที่ต้องเปลี่ยนคือถ้าตัวเองต้องเปลี่ยน บางครั้งการทำสำเนารหัสจำนวนเล็กน้อยสามารถใช้เป็นกลไกการแยกชิ้นส่วนเพื่อปรับปรุงเสถียรภาพอย่างมากในทางที่ทำให้การแลกเปลี่ยนที่คุ้มค่าหากในการแลกเปลี่ยนคุณจะได้รับรหัสซึ่งตอนนี้เป็นอิสระอย่างสมบูรณ์จากสิ่งอื่นใด ตอนนี้รหัสนั้นคงกระพันกับการเปลี่ยนแปลงสู่โลกภายนอก ในขณะเดียวกันรหัสที่ขึ้นอยู่กับ 10 ไลบรารีภายนอกที่แตกต่างกันมี 10 เท่าเหตุผลที่จะเปลี่ยนในอนาคต
สิ่งที่เป็นประโยชน์ในทางปฏิบัติคือการแยกไลบรารีของคุณออกจากส่วนที่ไม่เสถียรของ codebase ของคุณหรืออาจสร้างแยกจากกันเพราะคุณอาจทำกับไลบรารีของบุคคลที่สาม ทีม). เพียงแค่องค์กรประเภทนั้นสามารถป้องกันไม่ให้บุคคลเข้าไปยุ่งเกี่ยวกับมัน
อีกอย่างคือความเรียบง่าย ยิ่งรหัสของคุณพยายามทำน้อยเท่าไหร่ก็ยิ่งมีโอกาสมากเท่านั้นที่จะทำในสิ่งที่ทำได้ดี การออกแบบเสาหินเกือบจะไม่แน่นอนอย่างถาวรเนื่องจากยิ่งมีการเพิ่มฟังก์ชั่นการใช้งานมากขึ้นเท่าไหร่พวกเขาก็ดูเหมือนจะไม่สมบูรณ์
ความเสถียรควรเป็นเป้าหมายหลักของคุณเมื่อใดก็ตามที่คุณต้องการเขียนโค้ดที่จะยากที่จะเปลี่ยนแปลงอย่างหลีกเลี่ยงไม่ได้เช่นรหัส SIMD แบบขนานซึ่งได้รับการปรับแต่งจนเสียชีวิต คุณตอบโต้ความยากลำบากในการบำรุงรักษาโค้ดโดยการเพิ่มโอกาสที่คุณจะไม่ต้องเปลี่ยนรหัสและดังนั้นจึงไม่จำเป็นต้องรักษารหัสไว้ในอนาคต ทำให้ค่าบำรุงรักษาลดลงเหลือศูนย์ไม่ว่ารหัสนั้นจะยากเพียงใด