นักพัฒนาโปรแกรมถกเถียงว่า Type Systems สร้างปัญหามากกว่าแก้ปัญหาในการจัดการ Business Logic หรือไม่

ทีมชุมชน BigGo
นักพัฒนาโปรแกรมถกเถียงว่า Type Systems สร้างปัญหามากกว่าแก้ปัญหาในการจัดการ Business Logic หรือไม่

การถกเถียงที่ร้อนแรงได้เกิดขึ้นในชุมชนนักพัฒนาโปรแกรมเกี่ยวกับว่า 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