การถกเถียงที่ร้อนแรงได้เกิดขึ้นในชุมชนนักพัฒนาโปรแกรมเกี่ยวกับว่า type systems ขั้นสูงช่วยหรือเป็นอุปสรรคในการสร้างแอปพลิเคชันทางธุรกิจ การถกเถียงนี้มีจุดศูนย์กลางอยู่ที่คำถามพื้นฐาน: นักพัฒนาควรเข้ารหัสกฎทางธุรกิจลงใน type system ของภาษาโปรแกรมโดยตรง หรือเก็บไว้เป็นโค้ดที่ยืดหยุ่นซึ่งสามารถเปลี่ยนแปลงได้ง่าย
การสนทนานี้เริ่มต้นจากการวิพากษ์วิจารณ์ทั้งแนวทาง object-oriented programming และ functional programming ที่พยายามทำให้สถานะที่ผิดกฎหมายไม่สามารถแสดงออกได้ - ซึ่งเป็นแนวคิดยอดนิยมที่ type system จะป้องกันข้อผิดพลาดบางอย่างไม่ให้เกิดขึ้น แม้ว่าสิ่งนี้จะฟังดูดีในทางทฤษฎี แต่นักพัฒนาหลายคนพบว่ามันสร้างโค้ดที่แข็งกระด้างซึ่งกลายเป็นการเปลี่ยนแปลงที่มีต้นทุนสูงเมื่อข้อกำหนดทางธุรกิจมีการพัฒนา
แนวคิดทางเทคนิคหลักที่กล่าวถึง
- Make Illegal States Unrepresentable: ปรัชญาการเขียนโปรแกรมที่ระบบประเภทข้อมูลป้องกันไม่ให้เกิดสภาวะข้อผิดพลาดบางประการ
- Algebraic Type Systems: แนวทางทางคณิตศาสตร์ในการกำหนดประเภทข้อมูลด้วยกฎเกณฑ์ที่แม่นยำเกี่ยวกับค่าที่อนุญาตให้ใช้ได้
- Row Types and Effect Systems: คุณสมบัติระบบประเภทข้อมูลขั้นสูงที่ให้ความยืดหยุ่นมากกว่าแนวทางแบบดั้งเดิม
- Event-Driven Architecture: การออกแบบระบบที่ส่วนประกอบต่าง ๆ สื่อสารกันผ่านเหตุการณ์แทนการเชื่อมต่อโดยตรง
- Swiss Cheese Model: แนวทางด้านความปลอดภัยที่ใช้การป้องกันหลายชั้นแทนการพึ่งพาระบบเดียวที่สมบูรณ์แบบ
ปัญหาหลัก: กฎทางธุรกิจเปลี่ยนแปลงอย่างต่อเนื่อง
ปัญหาหลักที่นักพัฒนาเผชิญคือ business logic ไม่ค่อยคงที่เหมือนเดิม ตัวอย่างง่ายๆ แสดงให้เห็นถึงความท้าทาย: ลองจินตนาการถึงร้านค้าออนไลน์ที่ลูกค้า VIP สามารถแก้ไขคำสั่งซื้อหลังจากชำระเงินแล้ว แต่เฉพาะในกรณีที่การเปลี่ยนแปลงมีค่าใช้จ่ายน้อยกว่า 20 ดอลลาร์สหรัฐ กฎประเภทนี้ยากที่จะเข้ารหัสใน type system เพราะมันเกี่ยวข้องกับเงื่อนไขและข้อยกเว้นหลายอย่างที่นักธุรกิจคิดได้อย่างเป็นธรรมชาติ แต่คอมพิวเตอร์ต่อสู้เพื่อแสดงออก
นักพัฒนาคนหนึ่งแบ่งปันความหงุดหงิดของพวกเขากับแนวทางนี้ โดยสังเกตว่าเมื่อโดเมนมีการพัฒนา - ซึ่งพวกมันทำเสมอ - การเชื่อมโยงที่แน่นหนาระหว่างกฎทางธุรกิจและ type systems ต้องการการปรับโครงสร้างใหม่ที่มีราคาแพงทั่วทั้ง codebase ชุมชนดูเหมือนจะแบ่งออกระหว่างผู้ที่เห็นสิ่งนี้เป็นคุณสมบัติ (compiler บังคับให้คุณอัปเดตทุกอย่างอย่างสม่ำเสมอ) และผู้ที่มองว่าเป็นภาระที่ทำให้การพัฒนาช้าลง
การแบ่งแยกระหว่าง Testing กับ Types
ส่วนสำคัญของการสนทนามุ่งเน้นไปที่ว่าการทดสอบอย่างครอบคลุมสามารถแทนที่ความปลอดภัยที่ type systems ให้ได้หรือไม่ นักพัฒนาบางคนโต้แย้งว่าเมื่อคุณเขียนการทดสอบสำหรับ business logic ที่ซับซ้อน คุณได้ครอบคลุมกรณีง่ายๆ ที่ type systems จับได้แล้ว เช่น null pointer errors หรือประเภทพารามิเตอร์ที่ผิด คนอื่นๆ ไม่เห็นด้วยอย่างยิ่ง โดยชี้ให้เห็นว่า type systems จับข้อผิดพลาดทั้งหมวดหมู่โดยอัตโนมัติโดยไม่ต้องให้นักพัฒนาเขียนการทดสอบเฉพาะสำหรับแต่ละกรณี
การทดสอบส่วนใหญ่เป็นการทดสอบเส้นทางที่มีความสุข การทดสอบการจัดการข้อผิดพลาดเพียงเล็กน้อยหากคุณโชคดี สำหรับค่าตัวอย่างเพียงไม่กี่ค่าที่จะพลาดขอบมากมาย และให้เป็นไปตามความจริง เป็นเรื่องปกติที่ส่วนของโค้ดจะไม่มีการทดสอบเลยเพราะกำหนดเวลาแน่นเกินไปหรือถือว่าไม่สำคัญ
การถกเถียงเผยให้เห็นการแบ่งแยกทางปรัชญาที่ลึกซึ้งเกี่ยวกับว่าความปลอดภัยควรมาจากไหนในการพัฒนาซอฟต์แวร์ ผู้สนับสนุน type system ชอบจับข้อผิดพลาดในเวลา compile ในขณะที่คนอื่นๆ สนับสนุนความยืดหยุ่นใน runtime ด้วยแนวทางการทดสอบที่ดี
จุดที่เหมาะสม: เครื่องมือที่แตกต่างกันสำหรับงานที่แตกต่างกัน
นักพัฒนาที่มีประสบการณ์หลายคนในการสนทนาแนะนำว่าคำตอบที่แท้จริงไม่ใช่การเลือกแนวทางหนึ่งมากกว่าอีกแนวทางหนึ่ง แต่เป็นการใช้เครื่องมือที่เหมาะสมในระดับที่เหมาะสม พวกเขาโต้แย้งว่า type systems ทำงานได้ดีสำหรับข้อกังวลระดับต่ำ เช่น การป้องกันข้อผิดพลาดของหน่วยความจำหรือการรับรองความสมบูรณ์ของข้อมูล แต่กลายเป็นผลเสียเมื่อนำไปใช้กับ business logic ระดับสูงที่เปลี่ยนแปลงบ่อยครั้ง
แนวทางจุดกึ่งกลางนี้แนะนำให้ใช้ strong typing สำหรับส่วนที่มั่นคงของระบบ - เช่น การคำนวณทางการเงินหรือ API contracts - ในขณะที่เก็บกฎทางธุรกิจไว้ในโค้ดที่ยืดหยุ่นซึ่งสามารถปรับตัวให้เข้ากับข้อกำหนดที่เปลี่ยนแปลงได้อย่างรวดเร็ว นักพัฒนาบางคนกล่าวถึงการใช้ database constraints และ relational models เป็นอีกชั้นหนึ่งของความปลอดภัยที่ทำงานโดยไม่คำนึงถึงภาษาโปรแกรมที่เลือก
การเปรียบเทียบแนวทางของระบบ Type
แนวทาง | ข้อดี | ข้อเสีย |
---|---|---|
Strong Static Typing | ตรวจจับข้อผิดพลาดในขณะ compile ป้องกัน null pointer exceptions ทำให้การ refactor ปลอดภัยกว่า | ขาดความยืดหยุ่นเมื่อกฎทางธุรกิจเปลี่ยนแปลง ต้องดูแลรักษา type hierarchy อย่างครอบคลุม |
Dynamic Typing with Tests | มีความยืดหยุ่นสำหรับ business logic ที่เปลี่ยนแปลง สร้าง prototype ได้เร็วกว่า | เกิดข้อผิดพลาดขณะ runtime ต้องมี test coverage ที่ครอบคลุม การ refactor อย่างปลอดภัยทำได้ยากกว่า |
Hybrid Approach | typing แบบเข้มงวดสำหรับ component ที่เสถียร ความยืดหยุ่นสำหรับ business logic | ต้องตัดสินใจในการออกแบบอย่างรอบคอบว่าจะใช้แนวทางไหนตรงไหน |
ประสบการณ์ในโลกแห่งความเป็นจริงแตกต่างกันอย่างกว้างขวาง
การตอบสนองของชุมชนแสดงให้เห็นว่าประสบการณ์ของนักพัฒนากับปัญหานี้แตกต่างกันอย่างมากขึ้นอยู่กับโปรเจ็กต์ที่พวกเขาทำงานและภาษาที่พวกเขาใช้ นักพัฒนาที่ทำงานบน codebases ขนาดใหญ่ของ Haskell รายงานว่าความยืดหยุ่นไม่ใช่ปัญหาจริงๆ ในขณะที่คนอื่นๆ อธิบายการต่อสู้กับ type systems เมื่อพยายามใช้กฎทางธุรกิจที่ซับซ้อน
การสนทนายังเผยให้เห็นว่านักพัฒนาหลายคนได้เปลี่ยนไปสู่ event-driven architectures และ data-oriented programming เป็นวิธีหลีกเลี่ยงปัญหาความแข็งกระด้างทั้งหมด แทนที่จะเข้ารหัสกฎทางธุรกิจทั้งหมดในที่เดียว พวกเขาแบ่งออกเป็นส่วนประกอบที่เล็กกว่าและเชื่อมโยงหลวมๆ ซึ่งสามารถพัฒนาได้อย่างอิสระ
การถกเถียงยังคงดำเนินต่อไปในขณะที่อุตสาหกรรมซอฟต์แวร์ต่อสู้กับการสร้างสมดุลระหว่างประโยชน์ด้านความปลอดภัยของ strong type systems กับความยืดหยุ่นที่จำเป็นสำหรับข้อกำหนดทางธุรกิจที่เปลี่ยนแปลงอย่างรวดเร็ว แม้ว่าจะไม่มีฉันทามติที่ชัดเจนเกิดขึ้น แต่การสนทนาเน้นย้ำถึงความสำคัญของการเลือกระดับ abstraction ที่เหมาะสมสำหรับส่วนต่างๆ ของระบบซอฟต์แวร์
อ้างอิง: The Big Oops in Type Systems: This Problem Extends to FP as Well