The Nature of Complexity (ลักษณะของความซับซ้อน)
หนังสือเล่มนี้เกี่ยวกับวิธีการออกแบบระบบซอฟต์แวร์เพื่อให้มีความซับซ้อนน้อยที่สุด ขั้นตอนแรกคือการเข้าใจศัตรู ความซับซ้อนคืออะไรกันแน่ คุณจะรู้ได้อย่างไรว่าระบบมีความซับซ้อนมากเกินไป สิ่งใดที่ทำให้ระบบมีความซับซ้อน บทนี้จะตอบคำถามเหล่านี้ในระดับสูง บทต่อ ๆ ไปจะแสดงให้คุณเห็นวิธีการรับรู้ความซับซ้อนในระดับต่ำ ในแง่ของลักษณะโครงสร้างเฉพาะเจาะจง
ความสามารถในการรับรู้ความซับซ้อนเป็นทักษะการออกแบบที่สำคัญ มันช่วยให้คุณสามารถระบุปัญหาก่อนที่จะลงทุนเวลานานในการแก้ไข และช่วยให้คุณตัดสินใจเลือกทางเลือกต่าง ๆ ได้อย่างดี การบอกได้ว่าการออกแบบนั้นเรียบง่ายหรือไม่นั้นง่ายกว่าการสร้างการออกแบบที่เรียบง่าย แต่เมื่อคุณสามารถรับรู้ได้ว่าระบบมีความซับซ้อนเกินไป คุณสามารถนำความสามารถนี้มาใช้เพื่อชี้นำปรัชญาการออกแบบของคุณไปสู่ความเรียบง่าย หากการออกแบบดูเหมือนมีความซับซ้อน ลองลองวิธีที่ต่างออกไปและดูว่าวิธีนั้นนั้นเรียบง่ายกว่าหรือไม่ เมื่อเวลาผ่านไป คุณจะสังเกตได้ว่าเทคนิคบางอย่างมีแนวโน้มที่จะให้ผลลัพธ์ที่เรียบง่ายมากขึ้น ในขณะที่เทคนิคอื่น ๆ มีความสัมพันธ์กับความซับซ้อน ซึ่งจะช่วยให้คุณสามารถสร้างการออกแบบที่เรียบง่ายได้อย่างรวดเร็วขึ้น
บทนี้ยังระบุสมมติฐานพื้นฐานบางอย่างที่เป็นรากฐานสำหรับส่วนที่เหลือของหนังสือ บทต่อ ๆ ไปนำเนื้อหาของบทนี้มาใช้ปกติและใช้เพื่อสนับสนุนการปรับปรุงและข้อสรุปต่าง ๆ
2.1 Complexity defined (ความซับซ้อนที่ถูกนิยาม)
สำหรับวัตถุประสงค์ของหนังสือนี้ ผมนิยาม "ความซับซ้อน" ในทางปฏิบัติ ความซับซ้อนคือสิ่งใด ๆ ที่เกี่ยวข้องกับโครงสร้างของระบบซอฟต์แวร์ที่ทำให้มันยากต่อการเข้าใจและการแก้ไขระบบ ความซับซ้อนสามารถมีรูปแบบต่าง ๆ ได้ ตัวอย่างเช่น อาจเป็นการยากต่อการเข้าใจว่า Code ชิ้นหนึ่งทำงานอย่างไร อาจใช้เวลานาน ในการนำการปรับปรุงเล็ก ๆ น้อย ๆ ไปใช้ หรืออาจไม่ชัดเจนว่าส่วนใดของระบบต้องแก้ไขเพื่อให้เกิดการปรับปรุง อาจเป็นการยากต่อการแก้ไขข้อผิดพลาดหนึ่งโดยไม่เกิดข้อผิดพลาดอื่น หากระบบซอฟต์แวร์ยากต่อการเข้าใจและแก้ไข แสดงว่าระบบมีความซับซ้อน หากง่ายต่อการเข้าใจและแก้ไข แสดงว่าระบบนั้นเรียบง่าย
คุณยังสามารถคิดเกี่ยวกับความซับซ้อนในแง่ของต้นทุนและประโยชน์ได้ ในระบบที่ซับซ้อน ต้องใช้เวลานานในการนำการปรับปรุงแม้แต่เล็กน้อยมาใช้ ในระบบที่เรียบง่าย การปรับปรุงที่ใหญ่ขึ้นสามารถถูกนำไปใช้ได้ด้วยความพยายามที่น้อยลง
ความซับซ้อนคือสิ่งที่ Developer สัมผัสได้ในเวลาหนึ่งที่เฉพาะเจาะจงเมื่อพยายามบรรลุเป้าหมายที่เฉพาะเจาะจง มันไม่จำเป็นต้องเกี่ยวข้องกับขนาดหรือฟังก์ชันโดยรวมของระบบ ผู้คนมักใช้คำว่า "ซับซ้อน" เพื่ออธิบายระบบขนาดใหญ่ที่มีลักษณะเฉพาะที่ซับซ้อน แต่ถ้าระบบดังกล่าวง่ายต่อการทำงาน แล้วสำหรับจุดประสงค์ของหนังสือนี้ก็ไม่ซับซ้อน แน่นอนว่า ระบบซอฟต์แวร์ขนาดใหญ่และมีลักษณะเฉพาะที่ซับซ้อนเกือบทั้งหมดนั้นยากต่อการทำงานจริง ๆ ดังนั้นพวกเขาจึงตรงตามคำนิยาม "ความซับซ้อน" ของผมด้วย แต่สิ่งนี้ไม่จำเป็นต้องเป็นเช่นนั้น นอกจากนี้ยังเป็นไปได้ที่ระบบขนาดเล็กและไม่มีลักษณะเฉพาะที่ซับซ้อนสามารถมีความซับซ้อนได้มากมาย
ความซับซ้อนถูกกำหนดโดยกิจกรรมที่พบบ่อยที่สุด หากระบบมีส่วนที่ซับซ้อนมากบ้าง แต่ส่วนเหล่านั้นเกือบไม่เคยต้องการการสัมผัส พวกเขาก็จะไม่มีผลกระทบมากต่อความซับซ้อนโดยรวมของระบบ เพื่อแสดงลักษณะของสิ่งนี้ในลักษณะที่ค่อนข้างหยาบ ๆ ทางคณิตศาสตร์:
ความซับซ้อนโดยรวมของระบบ (C) ถูกกำหนดโดยความซับซ้อนของแต่ละส่วน p (cp) ถ่วงน้ำหนักด้วยสัดส่วนของเวลาที่ Developer ใช้ในการทำงานกับส่วนนั้น (tp) การแยกความซับซ้อนไปยังสถานที่ที่มันจะไม่เคยเห็นนั้นเกือบจะดีเท่ากับการกำจัดความซับซ้อนไปเลย
ความซับซ้อนเห็นได้ชัดเจนมากขึ้นกับผู้อ่านมากกว่าผู้เขียน หากคุณเขียน Code ชิ้นหนึ่งและดูเหมือนว่าเรียบง่ายกับคุณ แต่คนอื่น ๆ คิดว่ามันซับซ้อน แล้วมันก็ซับซ้อนจริง ๆ เมื่อคุณพบตัวเองในสถานการณ์เช่นนี้ จะคุ้มค่าที่จะสอบถามผู้พัฒนารายอื่น ๆ เพื่อค้นหาว่าทำไม Code จึงดูเหมือนซับซ้อนสำหรับพวกเขา มีบทเรียนที่น่าสนใจอยู่เบื้องหลังความเห็นที่แตกต่างกันนี้ หน้าที่ของคุณในฐานะ Developer ไม่ใช่แค่สร้าง Code ที่คุณสามารถทำงานได้ง่าย ๆ เท่านั้น แต่ยังต้องสร้าง Code ที่คนอื่น ๆ สามารถทำงานได้ง่าย ๆ อีกด้วย
2.2 Symptoms of complexity (อาการของความซับซ้อน)
ความซับซ้อนแสดงออกมาด้วยวิธีสามวิธีโดยทั่วไป ซึ่งอธิบายในย่อหน้าข้างล่าง แต่ละการแสดงออกของความซับซ้อนเหล่านี้ทำให้มันเป็นเรื่องยากต่อการดำเนินงานพัฒนาซอฟต์แวร์
Change amplification (การขยายของการเปลี่ยนแปลง): อาการแรกของความซับซ้อนคือการเปลี่ยนแปลงที่ดูเหมือนเรียบง่ายนั้นต้องมีการปรับเปลี่ยน Code ในหลาย ๆ สถานที่ ตัวอย่างเช่น พิจารณาเว็บไซต์ที่มีหลายหน้า แต่ละหน้าแสดงแบนเนอร์ที่มีสีพื้นหลัง ในเว็บไซต์ในยุคแรก สีนั้นถูกระบุไว้อย่างชัดเจนในแต่ละหน้า ดังแสดงใน รูปที่ 2.1(a) เพื่อเปลี่ยนพื้นหลังของเว็บไซต์ดังกล่าว Developer อาจต้องปรับเปลี่ยนทุกหน้าที่มีอยู่ด้วยตนเอง สิ่งนี้จะเป็นเรื่องเกือบเป็นไปไม่ได้สำหรับเว็บไซต์ขนาดใหญ่ที่มีหลายพันหน้า โชคดีที่ เว็บไซต์สมัยใหม่ใช้วิธีเช่น รูปที่ 2.1(b) ซึ่งสีของแบนเนอร์ถูกระบุไว้ครั้งเดียวในสถานที่ที่เป็นส่วนกลาง และหน้าแต่ละหน้าอ้างอิงถึงค่าที่ใช้ร่วมกันนั้น ด้วยวิธีนี้ สีของแบนเนอร์ของเว็บไซต์ทั้งหมดสามารถเปลี่ยนแปลงได้ด้วยการแก้ไขครั้งเดียว เป้าหมายหนึ่งของการออกแบบที่ดีคือการลดปริมาณ Code ที่ได้รับผลกระทบจากการตัดสินใจออกแบบแต่ละตัด ดังนั้นการเปลี่ยนแปลงการออกแบบจึงไม่ต้องมีการปรับเปลี่ยน Code จำนวนมาก
Cognitive load (ภาระการรับรู้): อาการที่สองของความซับซ้อนคือ Cognitive load ซึ่งหมายถึงว่า Developer ต้องรู้เท่าไหร่เพื่อให้สามารถทำงานให้เสร็จสิ้น Cognitive load ที่สูงขึ้นหมายความว่า Developer ต้องใช้เวลามากขึ้นในการเรียนรู้ข้อมูลที่จำเป็น และมีความเสี่ยงที่มากขึ้นในการเกิด Bug เพราะพวกเขาอาจพลาดสิ่งที่สำคัญ ตัวอย่างเช่น สมมติว่า Function ใน C จัดสรรหน่วยความจำ ส่งกลับ Pointer ไปยังหน่วยความจำนั้น และสมมติว่า Caller จะยกเลิกการจัดสรรหน่วยความจำ สิ่งนี้จะเพิ่ม Cognitive load สำหรับ Developer ที่ใช้ Function หากผู้พัฒนาล้มเหลวในการยกเลิกการจัดสรรหน่วยความจำ จะเกิดการรั่วไหลของหน่วยความจำ หากระบบสามารถจัดโครงสร้างใหม่เพื่อให้ Caller ไม่ต้องกังวลเกี่ยวกับการยกเลิกการจัดสรรหน่วยความจำ (Module เดียวกันที่จัดสรรหน่วยความจำยังรับผิดชอบในการยกเลิกการจัดสรร) มันจะลด Cognitive load ได้ Cognitive load เกิดขึ้นด้วยวิธีต่าง ๆ มากมาย เช่น API ที่มี Method จำนวนมาก ตัวแปรสากล ความไม่สอดคล้องกัน และ Dependencies ระหว่าง Module
นักออกแบบระบบบางครั้งสมมติว่าความซับซ้อนสามารถวัดได้โดยจำนวนบรรทัด Code พวกเขาสมมติว่าหากการใช้งานหนึ่งสั้นกว่าอีกการใช้งานหนึ่ง แล้วมันจะต้องเรียบง่ายกว่า หากต้องใช้เพียงไม่กี่บรรทัด Code เพื่อทำการเปลี่ยนแปลง แล้วการเปลี่ยนแปลงนั้นก็ต้องเป็นเรื่องง่าย อย่างไรก็ตาม มุมมองนี้มองข้ามต้นทุนที่เกี่ยวข้องกับ Cognitive load ผมเคยเห็น Framework ที่อนุญาตให้ Application เขียนด้วยเพียงไม่กี่บรรทัด Code แต่มันทำให้เป็นเรื่องยากอย่างยิ่งในการหาว่าบรรทัดเหล่านั้นควรจะเป็นอย่างไร บางครั้งวิธีการที่ต้องใช้บรรทัด Code มากขึ้นนั้นง่ายกว่าจริง ๆ เพราะมันลด Cognitive load
Figure 2.1 (รูปที่ 2.1): แต่ละหน้าในเว็บไซต์แสดงแบนเนอร์สีต่าง ๆ ใน (a) สีพื้นหลังของแบนเนอร์ถูกระบุไว้อย่างชัดเจนในแต่ละหน้า ใน (b) ตัวแปรที่ใช้ร่วมกันเก็บสีพื้นหลัง และแต่ละหน้าอ้างอิงถึงตัวแปรนั้น ใน (c) บางหน้าแสดงสีเพิ่มเติมเพื่อเน้น ซึ่งเป็นเฉดสีที่เข้มกว่าของสีพื้นหลังของแบนเนอร์ หากสีพื้นหลังเปลี่ยนไป สีที่เน้นจะต้องเปลี่ยนไปด้วย
Unknown unknowns (สิ่งที่ไม่รู้ว่าไม่รู้): อาการที่สามของความซับซ้อนคือไม่ชัดเจนว่า Code ชิ้นส่วนใดจะต้องแก้ไขเพื่อให้สามารถทำงานให้เสร็จสิ้น หรือข้อมูลใดที่ Developer ต้องมีเพื่อให้สามารถดำเนินการงานได้สำเร็จ รูปที่ 2.1(c) แสดงปัญหานี้ เว็บไซต์ใช้ตัวแปรส่วนกลางเพื่อกำหนดสีพื้นหลังของแบนเนอร์ ดังนั้นดูเหมือนว่าจะง่ายต่อการเปลี่ยนแปลง อย่างไรก็ตาม หน้าเว็บไซต์บางแห่งใช้เฉดสีที่เข้มกว่าของสีพื้นหลังเพื่อเน้น และสีที่เข้มกว่านี้ถูกระบุไว้อย่างชัดเจนในแต่ละหน้า หากสีพื้นหลังเปลี่ยนไป สีที่เน้นจะต้องเปลี่ยนไปด้วยเพื่อให้สอดคล้องกัน น่าเสียดายที่ Developer ไม่มีแนวโน้มที่จะเข้าใจสิ่งนี้ ดังนั้นพวกเขาอาจเปลี่ยน bannerBg ตัวแปรส่วนกลางโดยไม่ทำการอัปเดตสีที่เน้น แม้ว่า Developer ทราบถึงปัญหา ก็ไม่ชัดเจนว่าหน้าใดใช้สีที่เน้น ดังนั้น Developer อาจต้องค้นหาทุกหน้าในเว็บไซต์
จากอาการสามอย่างของความซับซ้อน สิ่งที่ไม่รู้ว่าไม่รู้นั้นเป็นอันตรายที่สุด สิ่งที่ไม่รู้ว่าไม่รู้หมายความว่า มีสิ่งที่คุณต้องทราบ แต่ไม่มีวิธีใดให้คุณค้นพบว่าสิ่งนั้นคืออะไร หรือแม้แต่ว่ามีปัญหาหรือไม่ คุณจะไม่พบมันจนกว่าจะเกิด Bug หลังจากที่คุณทำการเปลี่ยนแปลง การขยายของการเปลี่ยนแปลงนั้นน่ารำคาญ แต่ตราบใดที่ชัดเจนว่า Code ใดที่ต้องแก้ไข ระบบก็จะทำงานได้หลังจากที่ทำการเปลี่ยนแปลงเสร็จสิ้น ในทำนองเดียวกัน Cognitive load ที่สูง จะเพิ่มต้นทุนของการเปลี่ยนแปลง แต่หากชัดเจนว่าข้อมูลใดที่ควรอ่าน การเปลี่ยนแปลงจึงมีแนวโน้มที่จะถูกต้อง ด้วย Unknown unknowns นั่นไม่ชัดเจนว่าต้องทำอะไรหรือว่าวิธีแก้ปัญหาที่เสนอให้นั้นสามารถทำงานได้แม้ กรรมวิธีเดียวที่ช่วยให้แน่ใจได้คือการอ่านทุกบรรทัด Code ในระบบ ซึ่งเป็นไปไม่ได้สำหรับระบบที่มีขนาด แม้นี่ก็ไม่เพียงพออาจจะเพียงพอ เนื่องจากการเปลี่ยนแปลงอาจขึ้นอยู่กับการตัดสินใจออกแบบแบบละเอียดอ่อนที่ไม่เคยได้รับการบันทึก
เป้าหมายที่สำคัญที่สุดอย่างหนึ่งของการออกแบบที่ดีคือสำหรับระบบที่จะ เห็นได้ชัดเจน นี่คือสิ่งตรงกันข้ามของ Cognitive load ที่สูงและ Unknown unknowns ในระบบที่เห็นได้ชัดเจน Developer สามารถเข้าใจได้อย่างรวดเร็วว่า Code ที่มีอยู่ทำงานอย่างไร และต้องการอะไรในการทำการเปลี่ยนแปลง ระบบที่เห็นได้ชัดเจนคือระบบที่ Developer สามารถสร้าง Guess ได้อย่างรวดเร็วเกี่ยวกับสิ่งที่ต้องทำ โดยไม่ต้องคิดมากนัก แต่อย่างไรก็ตามมั่นใจว่า Guess นั้นถูกต้อง บทที่ 18 อภิปรายเทคนิคสำหรับทำให้ Code เห็นได้ชัดเจนขึ้น
2.3 Causes of complexity (สาเหตุของความซับซ้อน)
ตอนนี้ที่คุณทราบถึงอาการของความซับซ้อนในระดับสูงและเหตุใดความซับซ้อนจึงทำให้การพัฒนาซอฟต์แวร์เป็นเรื่องยากขึ้น ขั้นตอนต่อไปคือการเข้าใจว่าสิ่งใดที่ก่อให้เกิดความซับซ้อน เพื่อให้เราสามารถออกแบบระบบเพื่อหลีกเลี่ยงปัญหาต่าง ๆ ได้ ความซับซ้อนเกิดจากสิ่งสองอย่าง: Dependencies และ Obscurity ส่วนนี้อภิปรายปัจจัยเหล่านี้ในระดับสูง บทต่อ ๆ ไปจะอภิปรายว่าพวกเขาเกี่ยวข้องกับการตัดสินใจออกแบบระดับต่ำ ๆ อย่างไร
สำหรับจุดประสงค์ของหนังสือนี้ Dependency มีอยู่เมื่อ Code ชิ้นหนึ่งไม่สามารถเข้าใจและแก้ไขได้ในระบบที่โดดเดี่ยว Code นั้นเกี่ยวข้องในบางวิธีกับ Code อื่น ๆ และ Code อื่น ๆ นั้นต้องได้รับการพิจารณา หรือแก้ไขหากเปลี่ยน Code ที่ให้มา ในตัวอย่างเว็บไซต์ของ รูปที่ 2.1(a) สีพื้นหลังสร้าง Dependencies ระหว่างหน้าทั้งหมด หน้าทั้งหมดต้องมีพื้นหลังเดียวกัน ดังนั้นหากเปลี่ยนพื้นหลังสำหรับหน้าหนึ่ง ก็จะต้องเปลี่ยนสำหรับหน้าทั้งหมด ตัวอย่างอื่นของ Dependencies เกิดขึ้นใน Network Protocol โดยปกติมี Code ที่แยกต่างหากสำหรับ Sender และ Receiver สำหรับ Protocol แต่พวกเขาต้องแต่ละรูปแบบเป็นไปตามกฎเกณฑ์ของ Protocol เปลี่ยน Code สำหรับ Sender เกือบทั้งหมดต้องมีการเปลี่ยนแปลงที่สอดคล้องกันใน Receiver และในทางกลับกัน Signature ของ Method สร้าง Dependency ระหว่าง Implementation ของ Method นั้นและ Code ที่เรียก มันถ้า Parameter ใหม่ถูกเพิ่มเข้าไปใน Method การเรียก Method ทั้งหมดต้องถูกแก้ไขเพื่อระบุ Parameter นั้น
Dependencies เป็นส่วนพื้นฐานของซอฟต์แวร์และไม่สามารถกำจัดได้ทั้งหมด จริง ๆ แล้ว เราจงใจนำเข้า Dependencies เป็นส่วนหนึ่งของกระบวนการออกแบบซอฟต์แวร์ ทุกครั้งที่คุณเขียน Class ใหม่ คุณสร้าง Dependencies รอบ API ของ Class นั้น อย่างไรก็ตาม เป้าหมายหนึ่งของการออกแบบซอฟต์แวร์คือการลดจำนวนของ Dependencies และทำให้ Dependencies ที่เหลืออยู่ง่ายและเห็นได้ชัดเจนมากที่สุด
พิจารณาตัวอย่างเว็บไซต์ ในเว็บไซต์เก่าที่มีพื้นหลังระบุไว้อย่างแยกต่างหากในแต่ละหน้า หน้าเว็บไซต์ทั้งหมดมี Dependencies ซึ่งกันและกัน เว็บไซต์ใหม่ได้แก้ไขปัญหานี้โดยระบุสีพื้นหลังในสถานที่ที่เป็นส่วนกลางและให้ API ที่หน้าแต่ละหน้าใช้ในการดึงข้อมูลสีนั้นเมื่อทำการแสดงผล เว็บไซต์ใหม่ได้กำจัด Dependency ระหว่างหน้า แต่มันสร้าง Dependency ใหม่รอบ API สำหรับการดึงข้อมูลสีพื้นหลัง โชคดีที่ Dependency ใหม่นั้นเห็นได้ชัดเจนกว่า: ชัดเจนว่าหน้าเว็บแต่ละหน้าขึ้นอยู่กับ bannerBg สี และ Developer สามารถค้นหาทุกสถานที่ที่ใช้ตัวแปรได้อย่างง่ายดายโดยค้นหาชื่อของมัน นอกจากนี้ Compiler ยังช่วยจัดการ API Dependencies ถ้าชื่อของตัวแปรที่ใช้ร่วมกันเปลี่ยนไป ข้อผิดพลาดในการรวบรวมจะเกิดขึ้นใน Code ใด ๆ ที่ยังคงใช้ชื่อเก่า เว็บไซต์ใหม่ได้แทนที่ Dependency ที่ไม่ชัดเจนและยากต่อการจัดการด้วย Dependency ที่ง่ายและชัดเจนกว่า
สาเหตุที่สองของความซับซ้อนคือ Obscurity ความไม่ชัดเจนเกิดขึ้นเมื่อข้อมูลที่สำคัญไม่เห็นได้ชัดเจน ตัวอย่างง่าย ๆ คือชื่อตัวแปรที่เป็นสากลจนไม่ได้นำข้อมูลที่มีประโยชน์มากนัก (ตัวอย่างเช่น time) หรือ Documentation สำหรับตัวแปรอาจไม่ระบุหน่วยของมัน ดังนั้นวิธีเดียวที่จะค้นพบคือการค้นหา Code สำหรับสถานที่ที่ใช้ตัวแปร ความไม่ชัดเจนมักเกี่ยวข้องกับ Dependencies ซึ่งไม่ชัดเจนว่ามี Dependency อยู่หรือไม่ ตัวอย่างเช่น หากเพิ่มสถานะข้อผิดพลาดใหม่ลงในระบบ อาจจำเป็นต้องเพิ่มรายการลงในตารางที่เก็บข้อความ String สำหรับแต่ละสถานะ แต่การมีอยู่ของตารางข้อความอาจไม่เห็นได้ชัดเจนกับโปรแกรมเมอร์ที่มองไปที่การประกาศสถานะ ความไม่สอดคล้องกันก็เป็นปัจจัยสำคัญในการความไม่ชัดเจน: หากใช้ชื่อตัวแปรเดียวกันสำหรับสองวัตถุประสงค์ที่แตกต่างกัน มันจะไม่ชัดเจนสำหรับ Developer ว่า Objekt ตัวแปรนั้นประกอบด้วยวัตถุประสงค์ใด
ในหลาย ๆ กรณี ความไม่ชัดเจนเกิดขึ้นเพราะขาดการ Documentation ที่เพียงพอ บทที่ 13 เกี่ยวข้องกับหัวข้อนี้ อย่างไรก็ตาม ความไม่ชัดเจนก็เป็นปัญหาการออกแบบเช่นกัน หากระบบมีการออกแบบที่สะอาดและเห็นได้ชัดเจน มันจะต้องการ Documentation น้อยลง ความจำเป็นในการ Documentation ที่กว้างขวางมักเป็นสัญญาณเตือนว่าการออกแบบอาจไม่ค่อยถูกต้อง วิธีที่ดีที่สุดในการลดความไม่ชัดเจนคือการทำให้การออกแบบระบบเรียบง่ายขึ้น
ด้วยกัน Dependencies และ Obscurity คิดเป็นสามอาการของความซับซ้อน ที่อธิบายใน มาตรา 2.2 Dependencies นำไปสู่การขยายของการเปลี่ยนแปลงและ Cognitive load ที่สูง Obscurity สร้าง Unknown unknowns และยังส่งผลต่อ Cognitive load ด้วย หากเราสามารถค้นหาเทคนิคการออกแบบที่ลด Dependencies และ Obscurity ได้ แล้วเราก็สามารถลดความซับซ้อนของซอฟต์แวร์ได้
2.4 Complexity is incremental (ความซับซ้อนเป็นขั้นตอน)
ความซับซ้อนไม่ได้เกิดจากข้อผิดพลาดที่หนึ่งอันร้ายแรง มันสะสมจากหลาย ๆ ส่วนเล็ก ๆ Dependency หรือความไม่ชัดเจนตัวเดียว ด้วยตัวมันเองนั้นไม่น่าจะส่งผลกระทบที่สำคัญต่อการบำรุงรักษาระบบซอฟต์แวร์ ความซับซ้อนมาจากหลายร้อยหรือหลายพันขึ้นอยู่กับ Dependencies และความไม่ชัดเจนเล็ก ๆ ที่สะสมเมื่อเวลาผ่านไป ในที่สุด มี Dependencies และความไม่ชัดเจนเพียงพอที่ทุก ๆ การเปลี่ยนแปลงที่เป็นไปได้กับระบบจะได้รับผลกระทบจากหลายรายการ
ลักษณะการเพิ่มของความซับซ้อนทำให้มันยากต่อการควบคุม มันง่ายที่จะโน้มตัวให้ตัวเองว่าความซับซ้อนเล็ก ๆ น้อย ๆ ที่นำเข้ามาโดยการเปลี่ยนแปลงปัจจุบันของคุณไม่ใหญ่โต อย่างไรก็ตาม หากผู้พัฒนาทุกคนใช้วิธีนี้สำหรับทุก ๆ การเปลี่ยนแปลง ความซับซ้อนก็จะสะสมเร็วขึ้น เมื่อมีการสะสมความซับซ้อนแล้ว มันก็เป็นเรื่องยากที่จะกำจัด เนื่องจากการแก้ไข Dependency หรือความไม่ชัดเจนเพียงครั้งเดียวจะไม่ สามารถสร้างความแตกต่างที่มากได้ด้วยตัวมันเอง เพื่อชะลอการเติบโตของความซับซ้อน คุณต้องนำ "Zero tolerance" Philosophy มาใช้ ตามที่อภิปรายใน บทที่ 3
2.5 Conclusion (บทสรุป)
ความซับซ้อนมาจากการสะสมของ Dependencies และความไม่ชัดเจน เมื่อความซับซ้อนเพิ่มขึ้น มันจะนำไปสู่การขยายของการเปลี่ยนแปลง Cognitive load ที่สูง และ Unknown unknowns ผลที่ตามมาคือต้องใช้การปรับเปลี่ยน Code มากขึ้นเพื่อนำเสนอแต่ละลักษณะใหม่ นอกจากนี้ Developer ใช้เวลามากขึ้นในการรับข้อมูลที่เพียงพอในการทำการเปลี่ยนแปลงอย่างปลอดภัยและในกรณีที่เลวร้ายที่สุด พวกเขายังไม่สามารถหาข้อมูลทั้งหมดที่พวกเขาต้องการได้ เส้นบรรทัดที่ต่ำสุดคือ ความซับซ้อนทำให้มันยากและเสี่ยงต่อการแก้ไข Codebase ที่มีอยู่