เมื่อวานนั่งดู 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 แล้วพบรูปนี้ ซึ่งมันแจ่มมาก ๆ
แต่เมื่อนำมา implement จริง ๆ กลับได้แบบนี้ !!
นั่นคือ ViewController ผูกติดกลายเป็นตัวเดียวกันไปเลย
ซึ่งเป็นโครงสร้างที่เอื้อต่อการสร้าง 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 แต่ละส่วนง่ายต่อการใช้งาน ง่ายต่อการดูแล แม้แต่นักพัฒนาที่มีประสบการณ์น้อยก็ตาม มิเช่นนั้นคุณจะเอาเทคนิคแปลก ๆ มาใช้จนคนในทีมงงไปเลย อย่าทำนะ !! มันจะเป็นการใช้งานที่มากเกินความจำเป็น
- ของดีแต่อาจจะยังไม่เหมาะสมกับทีมในเวลานี้ก็เป็นได้
ดังนั้นการจะเลือกวางโครงสร้างของระบบอย่างไรนั้น
มันมีปัจจัยหลาย ๆ อย่าง
แต่เหนือสิ่งอื่นใด สิ่งที่คุณเลือกมันทำให้คุณและทีมช้าลงหรือเร็วขึ้น