mvc
เมื่อวานนั่งดู Code การพัฒนา iOS ด้วยภาษา Swift
โจทย์เดียวกันจาก developer 4 คน
แต่โครงสร้างของ code ที่ออกมานั้นเหมือนกัน
นั่นคือเป็น MVC(Model View Controller) ในรูปแบบของ Apple
ซึ่งส่วนใหญ่จะนำไปสู่ MVC ที่ย่อมาจาก Massive ViewController มากกว่านะ !!
และนั่นคือความหายนะที่กำลังมาเยือนนักพัฒนาโดยทั้งรู้และไม่รู้ตัว

คำถามที่น่าสนใจคือ แล้ว MVC มันไม่ดีหรือไง ?

ตอบได้เลยว่าดีนะ
ถ้าเข้าใจ และ ใช้งานได้อย่างถูกต้อง

คำถามต่อมา แล้วโครงสร้างแบบอื่นที่ดี ๆ ทำไมไม่ใช้กัน ?

ทั้ง MVP, MVVM และ VIPER เป็นต้น
แต่ก่อนจะเลือกอะไรนั้น
นักพัฒนาลองตอบคำถามเหล่านี้ก่อนสิ

  • เรื่องการการเรียกใช้งาน API ผ่านระบบ network ควรอยู่ตรงไหนดี Model หรือ Controller ?
  • จะทำการส่ง Model ไปยัง View เพื่อแสดงผลอย่างไร ?
  • ปัจจุบันเขียน code อย่างไร ?
  • ทดสอบกันแบบไหน ?

ถ้ายังงง ๆ ตอบไม่ถูก
แสดงว่าอย่าเพิ่งทำอะไรเลยนะ
มาทำความเข้าใจและเรียนรู้
จากนั้นมาฝึกฝนกันก่อน

คำถามต่อมา เราจะสนใจเรื่องโครงสร้างของระบบไปทำไม ?

ถ้านักพัฒนาไม่เลือกหรือกำหนดตั้งแต่แรก
มันมักจะก่อให้เกิด class ขนาดใหญ่หรือ God class จำนวนมากมาย
ยากต่อการค้นหาและแก้ไขอย่างมาก
หรือแค่มานั่งไล่ code เพื่อทำความเข้าใจก็ยังยากเลย !!
เรื่องของโครงสร้างมันก็สัมพันธ์กับความสามารถของทีมเช่นกัน

มาดูตัวอย่างจาก code ของ iOS app ที่พัฒนาด้วยภาษา Swift

จะมีลักษณะดังนี้

  • ทำการ extends มาจาก UIViewController
  • ข้อมูลต่าง ๆ ที่จะทำการแสดงผลหรือดึงข้อมูลจากภายนอกก็อยู่ใน UIViewController นี่แหละ
  • ส่วนของ UIViews ไม่ได้ทำอะไรเลย
  • Model ก็เป็นเพียง class และ struct สำหรับกำหนดโครงสร้างของข้อมูลเท่านั้น
  • UI testing อย่าคิด ส่วน Unit testing อย่าฝันว่าจะมี

ซึ่งเป็นผลมาจาก MVC ของ Apple นั่นเอง
เมื่อเข้าไปดูเอกสารเรื่อง MVC จากทาง Apple แล้วพบรูปนี้ ซึ่งมันแจ่มมาก ๆ

model_view_controller_2x

แต่เมื่อนำมา implement จริง ๆ กลับได้แบบนี้ !!

นั่นคือ ViewController ผูกติดกลายเป็นตัวเดียวกันไปเลย

mvc-apple

ซึ่งเป็นโครงสร้างที่เอื้อต่อการสร้าง Massive ViewController อย่างมาก
เนื่องจากทำการรวม View Life Cycle เข้ากับ Controller
ทำให้พวก business logic ต่าง ๆ รวมอยู่ในนั้นด้วย
ทำได้เพียงแยกส่วนของ data หรือ Model ออกมาเท่านั้น
ทำให้ใน ViewController นั้นจะใช้งานพวก
Delegate และ Datasource ของทุก ๆ อย่างเสมอ เช่น TableView และ SwipeView เป็นต้น

ผลที่ตามมาคือ
View คุยกับ Model โดยตรง หรือ ทำการส่ง Model ไปให้ View ซะงั้น !!
นั่นคือ ข้อขัดแย้งอย่างรุนแรงต่อ MVC
และเราพบเห็นได้บ่อยมาก ๆ ใน ViewController ของ iOS app
และนักพัฒนาทุกคนก็มองว่า มันเป็นเรื่องปกติ ไม่ได้ผิดอะไร !!
เมื่อเวลาผ่านไปนานขึ้น ขนาดของ ViewController ต่าง ๆ ก็ใหญ่โตขึ้นเรื่อย ๆ
นี่แหละคือที่ไปที่มาของ Massive ViewController

ยังไม่พอนะ เมื่อต้องเขียน Unit testing ด้วยแล้ว !!
ปัญหามันหนักมาก ๆ
เนื่องจาก ViewController มันเยอะไปหมด
code ผูกติดกันอย่างแน่นหนา
ทั้ง View ทั้ง Controller ทั้ง Business logic
หวังว่าระบบที่พัฒนาหรือดูแลกันอยู่ ไม่น่าจะเป็นเช่นนี้นะครับ

ดังนั้นสิ่งที่ควรทำก่อนเลยก็คือ

ทำความเข้าใจกับ code
และลองเขียนออกมาหน่อยว่า
ใน ViewController มีหน้าที่การทำงานอะไรบ้าง
จากนั้นค่อย ๆ แยกส่วนการทำงานต่าง ๆ ออกมา
โดยในแต่ละส่วนก็ช่วยเขียน Unit test ขึ้นมาคลุมหน่อยนะครับ
ค่อย ๆ ถอด
ค่อย ๆ แยก
ค่อย ๆ ทดสอบ
ค่อย ๆ integrate
แล้ว code จะค่อย ๆ ดีขึ้นเอง

ส่วน code ใหม่ ๆ ลองคิด วิเคราะห์ แยกแยะก่อนว่า

ในแต่ละ feature ต้องทำอะไร ต้องการอะไรบ้าง
โดยแนะนำให้ทำดังนี้

  • แยกส่วนการทำงานของ Model, View ออกจากกันก่อน
  • ส่วนของ Controller กับ View อาจจะยังติดกันนิดหน่อย
  • แต่ละส่วนการทำงานต้องสามารถทดสอบได้ แต่ถ้าคุณแยกส่วนการทำงานไม่ดีจะทดสอบได้ยาก หรือ ทำได้เพียง Model เท่านั้น ซึ่งต้องระวังให้มาก ๆ
  • Code แต่ละส่วนง่ายต่อการใช้งาน ง่ายต่อการดูแล แม้แต่นักพัฒนาที่มีประสบการณ์น้อยก็ตาม มิเช่นนั้นคุณจะเอาเทคนิคแปลก ๆ มาใช้จนคนในทีมงงไปเลย อย่าทำนะ !! มันจะเป็นการใช้งานที่มากเกินความจำเป็น
  • ของดีแต่อาจจะยังไม่เหมาะสมกับทีมในเวลานี้ก็เป็นได้

ดังนั้นการจะเลือกวางโครงสร้างของระบบอย่างไรนั้น
มันมีปัจจัยหลาย ๆ อย่าง
แต่เหนือสิ่งอื่นใด สิ่งที่คุณเลือกมันทำให้คุณและทีมช้าลงหรือเร็วขึ้น