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

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

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

2.1    ความซับซ้อนคืออะไร

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

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

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

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

img

ความซับซ้อนโดยรวมของระบบ (C) ถูกกำหนดโดยความซับซ้อนของแต่ละส่วน p (cp) ถ่วงน้ำหนักด้วยสัดส่วนเวลาที่นักพัฒนาใช้ทำงานในส่วนนั้น (tp) การซ่อนความซับซ้อนไว้ในที่ที่ไม่มีใครเห็นนั้นแทบจะดีเท่ากับการกำจัดความซับซ้อนทิ้งไปเลย

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

2.2    อาการของความซับซ้อน

ความซับซ้อนแสดงออกในสามรูปแบบหลัก ซึ่งจะอธิบายในย่อหน้าถัดไป แต่ละรูปแบบเหล่านี้ทําให้การทํางานพัฒนาซอฟต์แวร์ยากยิ่งขึ้น

Change amplification: อาการแรกของความซับซ้อนคือการเปลี่ยนแปลงที่ดูเหมือนง่ายแต่กลับต้องแก้ไขโค้ดในหลายๆ จุด ตัวอย่างเช่น เว็บไซต์ที่มีหลายหน้า แต่ละหน้าแสดงแบนเนอร์ที่มีสีพื้นหลัง ในเว็บไซต์ยุคแรกๆ หลายแห่ง สีถูกระบุไว้อย่างชัดเจนในแต่ละหน้า ดังที่แสดงใน Figure 2.1(a) การเปลี่ยนสีพื้นหลังของเว็บไซต์แบบนี้นักพัฒนาอาจต้องแก้ไขทุกหน้าที่มีอยู่ด้วยมือ ซึ่งแทบเป็นไปไม่ได้เลยสําหรับเว็บไซต์ขนาดใหญ่ที่มีเป็นพันหน้า โชคดีที่เว็บไซต์สมัยใหม่ใช้แนวทางแบบ Figure 2.1(b) ซึ่งกําหนดสีแบนเนอร์ไว้ที่จุดกลางเพียงจุดเดียว และทุกหน้าก็อ้างอิงค่าที่ใช้ร่วมกันนี้ ด้วยแนวทางนี้ สามารถเปลี่ยนสีแบนเนอร์ของทั้งเว็บไซต์ได้ด้วยการแก้ไขเพียงครั้งเดียว เป้าหมายหนึ่งของการออกแบบที่ดีคือการลดปริมาณโค้ดที่ได้รับผลกระทบจากการตัดสินใจออกแบบแต่ละครั้ง เพื่อให้การเปลี่ยนแปลงดีไซน์ไม่ต้องแก้ไขโค้ดจํานวนมาก

Cognitive load: อาการที่สองของความซับซ้อนคือ cognitive load ซึ่งหมายถึงปริมาณความรู้ที่นักพัฒนาต้องมีเพื่อทํางานให้สําเร็จ cognitive load ที่สูงขึ้นหมายความว่านักพัฒนาต้องใช้เวลาเรียนรู้ข้อมูลที่ต้องการมากขึ้น และมีความเสี่ยงสูงที่จะเกิดบั๊กเพราะพลาดข้อมูลสําคัญบางอย่าง ตัวอย่างเช่น สมมติว่าฟังก์ชันหนึ่งในภาษา C จัดสรรหน่วยความจํา ส่งคืน pointer ไปยังหน่วยความจํานั้น และคาดหวังให้ผู้เรียกเป็นคนคืนหน่วยความจํา สิ่งนี้เพิ่ม cognitive load ให้กับนักพัฒนาที่ใช้ฟังก์ชันนั้น ถ้านักพัฒนาลืมคืนหน่วยความจํา ก็จะเกิด memory leak ถ้าระบบสามารถถูกปรับโครงสร้างเพื่อให้ผู้เรียกไม่ต้องกังวลเรื่องการคืนหน่วยความจํา (โดยให้โมดูลเดียวกับที่จัดสรรหน่วยความจําเป็นผู้รับผิดชอบในการคืนหน่วยความจําด้วย) ก็จะช่วยลด cognitive load ได้ Cognitive load เกิดขึ้นได้ในหลายรูปแบบ เช่น APIs ที่มีหลาย methods, global variables, ความไม่สอดคล้องกัน และ dependencies ระหว่างโมดูล

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

img

Figure 2.1: แต่ละหน้าในเว็บไซต์แสดงแบนเนอร์ที่มีสีสัน ใน (a) สีพื้นหลังของแบนเนอร์ถูกระบุอย่างชัดเจนในแต่ละหน้า ใน (b) ตัวแปรที่ใช้ร่วมกันเก็บสีพื้นหลัง และแต่ละหน้าอ้างอิงตัวแปรนั้น ใน (c) บางหน้าแสดงสีเพิ่มเติมเพื่อเน้นย้ำ ซึ่งเป็นสีที่เข้มกว่าสีพื้นหลังของแบนเนอร์ ถ้าสีพื้นหลังเปลี่ยน สีที่ใช้เน้นก็ต้องเปลี่ยนตามไปด้วย

Unknown unknowns: อาการที่สามของความซับซ้อนคือการที่ไม่ชัดเจนว่าต้องแก้ไขโค้ดส่วนไหนบ้างจึงจะทํางานสําเร็จ หรือต้องมีข้อมูลอะไรบ้างเพื่อให้ดําเนินการได้สําเร็จ Figure 2.1(c) แสดงให้เห็นปัญหานี้ เว็บไซต์ใช้ตัวแปรกลางในการกําหนดสีพื้นหลังของแบนเนอร์ จึงดูเหมือนว่าเปลี่ยนได้ง่าย อย่างไรก็ตาม มีบางหน้าเว็บที่ใช้สีเข้มกว่าของสีพื้นหลังเพื่อเน้นย้ำ และสีที่เข้มกว่านั้นถูกระบุไว้อย่างชัดเจนในแต่ละหน้า ถ้าสีพื้นหลังเปลี่ยน สีที่ใช้เน้นก็ต้องเปลี่ยนให้เข้ากันด้วย น่าเสียดายที่นักพัฒนามักไม่ตระหนักถึงสิ่งนี้ พวกเขาอาจเปลี่ยนตัวแปรกลาง bannerBg โดยไม่ปรับปรุงสีที่ใช้เน้น แม้ว่านักพัฒนาจะรู้ถึงปัญหา ก็ไม่ชัดเจนว่าหน้าไหนใช้สีที่เน้นนั้นบ้าง ดังนั้นนักพัฒนาอาจต้องค้นหาทุกหน้าในเว็บไซต์

จากสามอาการของความซับซ้อน unknown unknowns เป็นสิ่งที่แย่ที่สุด unknown unknown หมายถึงมีบางสิ่งที่คุณจําเป็นต้องรู้ แต่ไม่มีทางที่คุณจะค้นพบว่ามันคืออะไร หรือแม้กระทั่งว่าเกิดปัญหาหรือไม่ คุณจะไม่รู้จนกว่าบั๊กจะปรากฏขึ้นหลังจากคุณเปลี่ยนแปลงโค้ดแล้ว Change amplification นั้นน่ารําคาญ แต่ตราบใดที่ชัดเจนว่าต้องแก้ไขโค้ดส่วนไหน ระบบก็จะทํางานได้เมื่อการเปลี่ยนแปลงเสร็จสมบูรณ์ ในทํานองเดียวกัน cognitive load ที่สูงจะเพิ่มต้นทุนของการเปลี่ยนแปลง แต่ถ้าชัดเจนว่าต้องอ่านข้อมูลใด การเปลี่ยนแปลงก็ยังมีแนวโน้มที่จะถูกต้อง แต่กับ unknown unknowns นั้นไม่ชัดเจนว่าจะทําอย่างไร หรือแม้กระทั่งว่าวิธีแก้ที่เสนอจะใช้ได้ผลหรือไม่ วิธีเดียวที่จะแน่ใจได้คืออ่านทุกบรรทัดของโค้ดในระบบ ซึ่งเป็นไปไม่ได้สําหรับระบบไม่ว่าจะขนาดไหน แม้กระทั่งวิธีนี้อาจไม่เพียงพอ เพราะการเปลี่ยนแปลงอาจขึ้นอยู่กับการตัดสินใจออกแบบที่ละเอียดอ่อนซึ่งไม่เคยมีการบันทึกไว้

เป้าหมายที่สําคัญที่สุดประการหนึ่งของการออกแบบที่ดีคือการทําให้ระบบ ชัดเจนในตัวเอง (obvious) ซึ่งตรงกันข้ามกับ cognitive load ที่สูงและ unknown unknowns ในระบบที่ชัดเจน นักพัฒนาสามารถเข้าใจได้อย่างรวดเร็วว่าโค้ดที่มีอยู่ทํางานอย่างไร และต้องทําอะไรบ้างเพื่อทําการเปลี่ยนแปลง ระบบที่ชัดเจนคือระบบที่นักพัฒนาสามารถเดาได้อย่างรวดเร็วว่าจะต้องทําอะไร โดยไม่ต้องคิดหนัก และยังมั่นใจได้ว่าการเดานั้นถูกต้อง Chapter 18 อภิปรายเทคนิคในการทําให้โค้ดชัดเจนยิ่งขึ้น

2.3    สาเหตุของความซับซ้อน

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

สําหรับหนังสือเล่มนี้ dependency เกิดขึ้นเมื่อโค้ดส่วนหนึ่งไม่สามารถทําความเข้าใจและแก้ไขได้โดยลําพัง โค้ดส่วนนั้นมีความเกี่ยวข้องกับโค้ดอื่นในบางทาง และต้องพิจารณาและ/หรือแก้ไขโค้ดอื่นนั้นด้วยหากโค้ดส่วนนี้มีการเปลี่ยนแปลง ในตัวอย่างเว็บไซต์ของ Figure 2.1(a) สีพื้นหลังสร้าง dependencies ระหว่างทุกหน้า ทุกหน้าต้องมีสีพื้นหลังเดียวกัน ดังนั้นถ้าเปลี่ยนสีพื้นหลังของหน้าหนึ่ง ก็ต้องเปลี่ยนทุกหน้าด้วย ตัวอย่างอีกประการของ dependencies เกิดขึ้นใน network protocols โดยทั่วไปจะมีโค้ดแยกกันสําหรับผู้ส่งและผู้รับของโปรโตคอล แต่ทั้งคู่ต้องเป็นไปตามโปรโตคอล การเปลี่ยนโค้ดของผู้ส่งมักต้องมีการเปลี่ยนแปลงที่สอดคล้องกันที่ฝั่งผู้รับ และในทางกลับกัน Signature ของ method สร้าง dependency ระหว่าง implementation ของ method นั้นกับโค้ดที่เรียกใช้ method: ถ้าเพิ่ม parameter ใหม่เข้าไปใน method การเรียกใช้ method นั้นทั้งหมดต้องถูกแก้ไขเพื่อระบุ parameter นั้น

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

ลองพิจารณาตัวอย่างเว็บไซต์ ในเว็บไซต์เก่าที่ระบุสีพื้นหลังแยกกันในแต่ละหน้า หน้าเว็บทั้งหมดต้องพึ่งพากันและกัน เว็บไซต์ใหม่แก้ปัญหานี้โดยระบุสีพื้นหลังไว้ที่จุดกลาง และให้ API ที่แต่ละหน้าใช้ดึงสีนั้นเมื่อถูกเรนเดอร์ เว็บไซต์ใหม่กําจัด dependency ระหว่างหน้าแต่สร้าง dependency ใหม่รอบๆ API สําหรับดึงสีพื้นหลัง โชคดีที่ dependency ใหม่นี้ชัดเจนกว่า: เห็นได้ชัดว่าแต่ละหน้าขึ้นอยู่กับสี bannerBg และนักพัฒนาสามารถค้นหาทุกที่ที่ใช้ตัวแปรนี้ได้ง่ายๆ โดยการค้นหาชื่อของมัน นอกจากนี้ compiler ยังช่วยจัดการ API dependencies ได้อีกด้วย: ถ้าชื่อของตัวแปรที่ใช้ร่วมกันเปลี่ยนไป compilation errors จะเกิดขึ้นในโค้ดใดๆ ที่ยังใช้ชื่อเก่าอยู่ เว็บไซต์ใหม่ได้แทนที่ dependency ที่ไม่ชัดเจนและจัดการยากด้วย dependency ที่เรียบง่ายและชัดเจนกว่า

สาเหตุที่สองของความซับซ้อนคือ obscurity Obscurity เกิดขึ้นเมื่อข้อมูลสําคัญไม่ชัดเจน ตัวอย่างง่ายๆ คือชื่อตัวแปรที่กว้างเกินไปจนไม่มีข้อมูลที่มีประโยชน์มากนัก (เช่น time) หรือเอกสารกํากับตัวแปรอาจไม่ระบุหน่วยของมัน ทําให้วิธีเดียวที่จะรู้ได้คือสแกนโค้ดหาตําแหน่งที่ใช้ตัวแปรนั้น Obscurity มักเกี่ยวข้องกับ dependencies โดยที่มองไม่ชัดเจนว่ามี dependency อยู่ ตัวอย่างเช่น ถ้าเพิ่ม error status ใหม่เข้าไปในระบบ อาจต้องเพิ่มรายการในตารางที่เก็บข้อความสตริงสําหรับแต่ละ status แต่การมีอยู่ของตารางข้อความนั้นอาจไม่ชัดเจนสําหรับโปรแกรมเมอร์ที่ดูการประกาศ status ความไม่สอดคล้องกัน (inconsistency) ก็เป็นปัจจัยสําคัญที่ทําให้เกิด obscurity: ถ้าชื่อตัวแปรเดียวกันถูกใช้เพื่อวัตถุประสงค์สองอย่างที่แตกต่างกัน ก็จะไม่ชัดเจนสําหรับนักพัฒนาว่าตัวแปรแต่ละตัวทําหน้าที่ใด

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

เมื่อรวมกันแล้ว dependencies และ obscurity อธิบายอาการทั้งสามของความซับซ้อนที่อธิบายไว้ใน Section 2.2 Dependencies นําไปสู่ change amplification และ cognitive load ที่สูง Obscurity สร้าง unknown unknowns และยังมีส่วนทําให้เกิด cognitive load หากเราสามารถค้นหาเทคนิคการออกแบบที่ลด dependencies และ obscurity ได้ เราก็จะลดความซับซ้อนของซอฟต์แวร์ลงได้

2.4    ความซับซ้อนสะสมทีละน้อย

ความซับซ้อนไม่ได้เกิดจากความผิดพลาดร้ายแรงเพียงครั้งเดียว แต่มันสะสมจากชิ้นส่วนเล็กๆ นับร้อยนับพัน dependency หรือ obscurity เพียงตัวเดียวนั้นไม่น่าจะส่งผลกระทบต่อการบํารุงรักษาระบบซอฟต์แวร์อย่างมีนัยสําคัญ ความซับซ้อนเกิดขึ้นเพราะ dependencies และ obscurities เล็กๆ นับร้อยหรือนับพันสะสมตัวขึ้นเมื่อเวลาผ่านไป ในที่สุดก็มีปัญหาเล็กๆ เหล่านี้มากมายจนการเปลี่ยนแปลงใดๆ ต่อระบบล้วนได้รับผลกระทบจากหลายๆ ปัญหา

ธรรมชาติที่ค่อยเป็นค่อยไปของความซับซ้อนทําให้ควบคุมได้ยาก มันง่ายที่จะโน้มน้าวตัวเองว่าความซับซ้อนเล็กน้อยที่เกิดจากการเปลี่ยนแปลงในครั้งนี้ไม่ใช่เรื่องใหญ่ อย่างไรก็ตาม ถ้านักพัฒนาทุกคนใช้แนวทางนี้กับการเปลี่ยนแปลงทุกครั้ง ความซับซ้อนก็จะสะสมอย่างรวดเร็ว เมื่อความซับซ้อนสะสมแล้ว ก็ยากที่จะกําจัดออกไป เพราะการแก้ไข dependency หรือ obscurity เพียงตัวเดียวจะไม่สร้างความแตกต่างอย่างมีนัยสําคัญ เพื่อชะลอการเติบโตของความซับซ้อน คุณต้องนําปรัชญา "zero tolerance" มาใช้ ดังที่กล่าวถึงใน Chapter 3

2.5    บทสรุป

ความซับซ้อนเกิดจากการสะสมของ dependencies และ obscurities เมื่อความซับซ้อนเพิ่มขึ้น มันนําไปสู่ change amplification, cognitive load ที่สูง และ unknown unknowns ผลที่ตามมาคือต้องแก้ไขโค้ดมากขึ้นเพื่อ implement แต่ละฟีเจอร์ใหม่ นอกจากนี้ นักพัฒนายังใช้เวลามากขึ้นในการหาข้อมูลที่เพียงพอเพื่อทําการเปลี่ยนแปลงอย่างปลอดภัย และในกรณีที่แย่ที่สุด พวกเขาไม่สามารถหาข้อมูลทั้งหมดที่ต้องการได้ด้วยซ้ํา สรุปคือความซับซ้อนทําให้การแก้ไข code base ที่มีอยู่เป็นเรื่องยากและเสี่ยง