Fundamental Patterns (แพตเทิร์นพื้นฐาน)

ตลอดประวัติศาสตร์ของ software architecture มี pattern พื้นฐานหลายแบบที่ปรากฏขึ้นซ้ำแล้วซ้ำเล่า โดยทั่วไปเป็นเพราะมันให้มุมมองที่มีประโยชน์ ในการจัดระเบียบโค้ด การ deploy หรือแง่มุมอื่น ๆ ของสถาปัตยกรรม ตัวอย่างเช่น แนวคิดเรื่อง layer ที่แยก concern ต่าง ๆ ตามฟังก์ชันการทำงานนั้นมีมานานพอ ๆ กับซอฟต์แวร์เอง แต่ layer (ทั้งในรูปแบบ style และ pattern) ก็ยังคงปรากฏในรูปแบบที่แตกต่างกันไปเรื่อย ๆ รวมถึงรูปแบบสมัยใหม่ที่เราจะพูดถึงใน Chapter 10 .

แต่น่าเสียดายที่ยังมี antipattern ที่พบได้ทั่วไปอีกแบบหนึ่งซึ่งเกิดจากการไม่มีสถาปัตยกรรมเลย นั่นคือ Big Ball of Mud

Big Ball of Mud (ก้อนโคลนยักษ์)

สถาปนิกเรียกสภาวะที่ไม่มีโครงสร้างสถาปัตยกรรมที่สังเกตเห็นได้ชัดเจนเลยว่า Big Ball of Mud ซึ่งตั้งชื่อตาม antipattern ที่ Brian Foote และ Joseph Yoder นิยามไว้ในเปเปอร์ปี 1997 ซึ่งนำเสนอในงานประชุม Patterns Languages of Programs ปี 1997

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

โครงสร้างโดยรวมของระบบอาจไม่เคยถูกกำหนดไว้อย่างชัดเจนเลยตั้งแต่แรก

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

ทุกวันนี้ Big Ball of Mud อาจใช้อธิบายแอปพลิเคชันสคริปต์ง่าย ๆ ที่ไม่มีโครงสร้างภายในที่แท้จริงเลย โดยมี event handler เชื่อมตรงเข้ากับการเรียกฐานข้อมูล แอปพลิเคชันเล็ก ๆ จำนวนมากเริ่มต้นแบบนี้ แล้วก็กลายเป็นสิ่งที่จัดการยากขึ้นเรื่อย ๆ เมื่อมันเติบโตขึ้น

โดยทั่วไปแล้ว ควรหลีกเลี่ยงสถาปัตยกรรมแบบนี้ไม่ว่าจะด้วยวิธีใดก็ตาม การไม่มีโครงสร้างทำให้การเปลี่ยนแปลงยากขึ้นเรื่อย ๆ สถาปัตยกรรมแบบนี้ยังประสบปัญหาด้าน deployment, testability, scalability และ performance อีกด้วย ยิ่งระบบเหล่านี้ใหญ่ขึ้นเท่าไร ความเจ็บปวดจากการไม่มีสถาปัตยกรรมก็ยิ่งเลวร้ายมากขึ้นเท่านั้น

น่าเสียดายที่ antipattern นี้เกิดขึ้นค่อนข้างบ่อยในโลกความเป็นจริง มีสถาปนิกไม่กี่คนที่ตั้งใจสร้างความยุ่งเหยิงขึ้นมา แต่หลายโปรเจกต์กลับกลายเป็นแบบนั้นโดยไม่ได้ตั้งใจ ซึ่งมักเกิดจากการขาดการกำกับดูแล (governance) เรื่องคุณภาพและโครงสร้างของโค้ด ตัวอย่างเช่น Neal เคยทำงานในโปรเจกต์ของลูกค้ารายหนึ่งที่มีโครงสร้างตามที่ปรากฏใน Figure 9-1 .

ลูกค้ารายนี้ (ซึ่งขอไม่เปิดเผยชื่อด้วยเหตุผลที่เข้าใจได้) สร้างเว็บแอปพลิเคชันที่เขียนด้วย Java ขึ้นมาอย่างเร่งรีบที่สุดเท่าที่จะทำได้ตลอดหลายปี ภาพ visualization เชิงเทคนิคใน Figure 9-1 แสดงให้เห็นถึง coupling ของระบบ โดยแต่ละจุดรอบวงกลมแทน class หนึ่งตัว และแต่ละเส้นแทนความเชื่อมโยงระหว่าง class เหล่านั้น เส้นที่หนากว่าหมายถึงความเชื่อมโยงที่แน่นกว่า ในโค้ดเบสนี้ การเปลี่ยนแปลง class ใด ๆ ก็ตามทำให้ยากที่จะคาดเดาผลกระทบที่จะเกิดกับ class อื่น ๆ ทำให้การเปลี่ยนแปลงกลายเป็นเรื่องที่น่าหวาดกลัว

Figure 9-1. สถาปัตยกรรม Big Ball of Mud ที่แสดงเป็นภาพ visualization จากโค้ดเบสจริง (สร้างด้วยเครื่องมือที่เลิกใช้งานแล้วชื่อ XRay ซึ่งเป็น Eclipse plug-in)

ปัญหาของ Big Ball of Mud architecture ไม่ได้มีแค่การขาดโครงสร้างเท่านั้น เพราะทุกอย่างเชื่อมโยงกันไปหมด การเปลี่ยนแปลงจึงมักก่อให้เกิดผลกระทบข้างเคียงที่คาดเดายากและลุกลามไปเรื่อย ๆ ปัญหานี้อาจรุนแรงถึงขั้นที่นักพัฒนาต้องใช้เวลาทั้งหมดไล่ตามแก้บั๊กและผลกระทบข้างเคียงของมัน แทนที่จะได้ทำฟีเจอร์ใหม่ ๆ

Unitary Architecture (สถาปัตยกรรมแบบเอกภาพ)

ในยุคเริ่มแรก มีเพียงคอมพิวเตอร์เท่านั้น และซอฟต์แวร์ก็ทำงานอยู่บนมัน ทั้งสองสิ่งเริ่มต้นจากการเป็นสิ่งเดียวกัน ก่อนจะแยกออกจากกันเมื่อมันพัฒนาขึ้นและความต้องการความสามารถที่ซับซ้อนมากขึ้นก็เพิ่มขึ้นตามไปด้วย ตัวอย่างเช่น mainframe computer เริ่มต้นจากการเป็นระบบเดี่ยว ก่อนจะค่อย ๆ แยกข้อมูลออกไปเป็นระบบของตัวเองต่างหาก ในทำนองเดียวกัน เมื่อคอมพิวเตอร์ส่วนบุคคล (PC) ถูกพัฒนาขึ้นเชิงพาณิชย์เป็นครั้งแรก จุดสนใจส่วนใหญ่ก็อยู่ที่เครื่องเดี่ยว ๆ เมื่อการเชื่อมต่อเครือข่าย PC เริ่มแพร่หลายมากขึ้น ระบบแบบ distributed (เช่น client/server) จึงปรากฏขึ้น

Client/Server

มี unitary architecture หลงเหลืออยู่น้อยมากนอกเหนือจากใน embedded system และสภาพแวดล้อมที่มีข้อจำกัดสูงอื่น ๆ โดยทั่วไปแล้วระบบซอฟต์แวร์มักจะเพิ่มฟังก์ชันการทำงานขึ้นเรื่อย ๆ ตามเวลา และการแยก concern ออกจากกันก็กลายเป็นสิ่งจำเป็น เพื่อรักษาคุณลักษณะเชิงปฏิบัติการของสถาปัตยกรรม เช่น performance และ scale

architecture style จำนวนมากเกี่ยวข้องกับวิธีการแยกส่วนต่าง ๆ ของระบบออกจากกันอย่างมีประสิทธิภาพ style พื้นฐานอย่างหนึ่งในงานสถาปัตยกรรมคือการแยกฟังก์ชันการทำงานเชิงเทคนิคระหว่าง frontend กับ backend เรียกว่า architecture แบบ two-tier หรือ client/server ซึ่งมีหลายรูปแบบแตกต่างกันไปตามยุคสมัยและความสามารถด้าน computing ของระบบในขณะนั้น

Desktop and database server (Desktop กับ database server)

architecture ของ PC ยุคแรก ๆ แบบหนึ่งสนับสนุนให้นักพัฒนาเขียนแอปพลิเคชันเดสก์ท็อปที่มีความสามารถสูงบน user interface อย่าง Windows โดยแยกข้อมูลออกไปไว้ที่ database server ต่างหาก architecture แบบนี้เกิดขึ้นพร้อม ๆ กับการปรากฏตัวของ database server แบบ standalone ที่สามารถเชื่อมต่อผ่าน network protocol มาตรฐานได้ สิ่งนี้ทำให้ presentation logic สามารถอยู่บนเครื่อง desktop ได้ ในขณะที่งานที่ต้องใช้การประมวลผลหนัก (ทั้งในแง่ปริมาณและความซับซ้อน) จะเกิดขึ้นบน database server ที่แข็งแกร่งกว่า

Browser and web server (Browser กับ web server)

เมื่อการพัฒนาเว็บสมัยใหม่มาถึง การแยก architecture ออกเป็น web browser ที่เชื่อมต่อกับ web server (ซึ่งเชื่อมต่อกับ database server อีกทอดหนึ่ง) ก็กลายเป็นเรื่องปกติ การแบ่งความรับผิดชอบแบบนี้คล้ายกับรูปแบบ desktop แต่ client จะบางกว่ามากในรูปของ browser ทำให้กระจายการใช้งานได้กว้างขวางขึ้นทั้งภายในและภายนอก firewall แม้ว่าฐานข้อมูลจะแยกออกจาก web server แต่สถาปนิกหลายคนก็ยังนับว่านี่เป็น two-tier architecture เพราะ web server และ database server ทำงานอยู่บนเครื่องประเภทเดียวกันในศูนย์ปฏิบัติการ ในขณะที่ UI ทำงานอยู่บน browser ของผู้ใช้

Single-page JavaScript applications (แอปพลิเคชัน JavaScript แบบหน้าเดียว)

เมื่อการตอบสนองของเว็บดีขึ้น การ implement JavaScript ใน browser ก็พัฒนาตามไปด้วย จึงเกิดกลุ่มแอปพลิเคชันสไตล์ client/server ที่คล้ายกับรูปแบบ desktop ดั้งเดิม แต่ rich client ถูกเขียนด้วย JavaScript ใน browser แทนที่จะเป็นแอปพลิเคชันเดสก์ท็อป

ดังที่หัวข้อนี้แสดงให้เห็น จะมี layer สำหรับแยกส่วนต่าง ๆ ของ architecture อยู่เสมอ ขึ้นอยู่กับความต้องการของแอปพลิเคชันและความสามารถของแพลตฟอร์ม

Three-tier (สถาปัตยกรรมแบบสามชั้น)

Three-tier architecture ซึ่งให้การแยกชั้นที่มากขึ้นไปอีก ได้รับความนิยมในช่วงปลายทศวรรษ 1990 เมื่อเครื่องมืออย่าง application server เริ่มโดดเด่นขึ้นใน Java และ .NET บริษัทต่าง ๆ ก็เริ่มสร้าง layer เพิ่มเข้าไปใน topology ของตนมากขึ้นไปอีก ระบบหนึ่งอาจมี database tier ที่ใช้ database server ระดับอุตสาหกรรม, application tier ที่จัดการโดย application server และ frontend ที่เขียนด้วย HTML ที่สร้างขึ้นอัตโนมัติ และเพิ่มมากขึ้นเรื่อย ๆ ด้วย JavaScript (เมื่อความสามารถของมันขยายตัวขึ้น)

Three-tier architecture มาพร้อมกับ network-level protocol อย่าง Common Object Request Broker Architecture (CORBA) และ Distributed Component Object Model (DCOM) เพื่อช่วยให้การสร้าง distributed architecture ทำได้ง่ายขึ้น

เช่นเดียวกับที่นักพัฒนาในปัจจุบันไม่ต้องกังวลว่า network protocol อย่าง TCP/IP ทำงานอย่างไร (เพราะมันก็แค่ทำงานได้เอง) สถาปนิกส่วนใหญ่ก็ไม่ต้องกังวลกับรายละเอียดระดับ plumbing แบบนี้ใน distributed architecture เช่นกัน ความสามารถที่เครื่องมือในยุคนั้นเคยมอบให้ ทุกวันนี้ยังคงมีอยู่ ไม่ว่าจะในรูปของเครื่องมือ (เช่น message queue) หรือในรูปของ architecture pattern (เช่น event-driven architecture ที่จะกล่าวถึงใน Chapter 15 )