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

    การออกแบบซอฟต์แวร์ที่ไม่เหมาะสมมีหลายรูปแบบ เช่น (1) การออกแบบซอฟต์แวร์ที่ไม่ยืดหยุ่นและแก้ไขหรือปรับเปลี่ยนได้ยาก (rigid design) โดยมากเกิดจากการออกแบบที่มีข้อกำหนดหรือมีโซลูชั่นมากเกินจำเป็น การแก้ไขหรือปรับเปลี่ยนจะส่งผลกระทบไปทั้งระบบงานและก่อให้เกิดข้อผิดพลาดได้มาก การประเมินว่าต้องทำอะไรแค่ไหนรวมถึงการประเมินความเสี่ยงจะประเมินได้ยากมากเพราะเราไม่สามารถระบุผลกระทบที่จะเกิดขึ้นได้ (2) การออกแบบซอฟต์แวร์ที่จะเสียหายหรือไม่มั่นคงเมื่อมีการเปลี่ยนแปลง (design fragility) การแก้ไขหรือปรับเปลี่ยนแม้เพียงส่วนเล็กๆอาจจะส่งผลให้เกิดข้อผิดพลาดต่อเนื่องไปยังส่วนอื่นของระบบ ต้องอาศัยการแก้ไขและทดสอบอย่างหนักเพื่อให้แน่ใจว่าโปรแกรมมั่นคงและถูกต้อง ทำให้ปรับปรุงหรือเพิ่มความสามารถได้ยาก ความเปราะบางของการออกแบบอาจเกิดจากหลายปัจจัย เช่น รหัสที่ซับซ้อนเกินไป โปรแกรมผูกพันกันมากเกินไป การไม่ป้องกันโอกาสที่จะเกิดข้อผิดพลาด การที่ผลลัพธ์ของโปรแกรมมีความเป็นไปได้หลายแบบที่ไม่สอดคล้องกัน หรือขาดการแยกการทำงานออกเป็นส่วนย่อยๆ (3) การออกแบบซอฟต์แวร์ที่ปรับเปลี่ยนแก้ไขได้ยากเมื่อใช้งานไปแล้ว (design immobility) โดยมากเกิดจาก ออกแบบซับซ้อนเกินไป โปรแกรมผูกพันกันมากเกินไป เอกสารประกอบไม่มีคุณภาพ หรือขาดการแยกการทำงานออกเป็นส่วนย่อยๆ การปรับเปลี่ยนแก้ไขจะกระทบกับความมั่นคงหรือฟังก์ชั่นของโปรแกรมเสมอทำให้เกิดหนี้ทางเทคนิกในอนาคตเพราะการบำรุงรักษาและการปรับปรุงจะยุ่งยากและราคาแพง (4) การออกแบบซอฟต์แวร์ที่ทำให้ปรับเปลี่ยนแก้ไขได้ยาก (viscous design) โดยมากเกิดจากการออกแบบที่ซับซ้อนไป มีสถาปัตยกรรมที่มีการผูกพันกันอย่างแนบแน่นทำให้ทำความเข้าใจได้ยากและแก้ไขหรือขยายขีดความสามารถได้ยาก การขาดเอกสารประกอบที่ดี การขาดการป้องการข้อผิดพลาดที่ดี ทำให้เกิดหนี้ทางเทคนิกในอนาคตเพราะการบำรุงรักษาและการปรับปรุงจะยุ่งยาก หรืออาจจะถึงขั้นต้องพัฒนาขึ้นมาใหม่ 

(5) เราใช้ซอฟต์แวร์เพื่อแก้ปัญหาที่ซับซ้อน ซอฟต์แวร์ที่ได้จึงซับซ้อนไปด้วย (needless complexity) ในขณะที่เราก็ต้องการให้ซอฟต์แวร์ถูกใช้งานไปได้นานๆ ทำให้เราถูกผลักดันให้ใช้การออกแบบในแนวทางภาพสรุป (abstraction) เพื่อให้สามารถเพิ่มเติมและขยายได้อย่างง่ายดายในอนาคต แต่การใช้แนวทางภาพสรุปมากเกินไปก็ทำให้โปรแกรมซับซ้อนได้เช่นกันเพราะจะทำให้เข้าใจได้ยาก แต่ในบางกรณีเช่นการสร้างไลบรารี่เพื่อให้ใช้งานทั่วไปการใช้แนวทางภาพสรุปเป็นหลักก็เหมาะสมเพราะผู้ใช้งานสนใจผลลัพธ์จากการเรียกใช้ไลบรารี่เท่านั้น (6) ปัญหาถัดมาคือการสำเนาส่วนของโปรแกรมจากส่วนอื่นของโปรแกรมมาใช้ (repetition) ซึ่งหากในภายหลังพบว่าส่วนของโปรแกรมนั้นมีข้อผิดพลาด เราจะต้องตามไปแก้ไขในทุกๆที่ที่นำไปใช้ ซึ่งการสำเนาโปรแกรมไปใช้เป็นการละเลยการใช้แนวทางภาพสรุป (7) โปรแกรมมักจะเข้าใจยากขึ้นหรือคลุมเครือมากขึ้นเมื่อเวลาผ่านไป (opacity) โดยเฉพาะเมื่อมีการเพิ่มความสามารถใหม่ๆ ผู้พัฒนามักจะบ่ายเบี่ยงที่จะสร้างคลาสใหม่แต่ใช้การแทรกรหัสใหม่เข้าไปในโปรแกรมโดยไม่สนใจว่ามันควรจะอยู่ที่นั่นหรือไม่ ซึ่งส่งผลให้ยากที่จะทำความเข้าใจจุดมุ่งหมายของโปรแกรมซึ่งจะก่อปัญหาเมื่อต้องการแก้ไขปรับปรุงในอนาคต