เมื่อวานมีโอกาสไปร่วมงาน iOSDevTH Meetup #8 ซึ่งจัดที่บริษัท Ascend
โดยในครั้งนี้มี 2 หัวข้อคือ

  1. Organize your code to repository: Case study Cocoapods
  2. VIPER: Scalable Architecture

ทั้งสองหัวข้อเป็นเรื่องของการวางโครงสร้างของ Mobile app
ซึ่งสามารถนำมาใช้ได้ทั้ง Android และ iOS app เลยนะ
ดังนั้นมาดูรายละเอียดแบบสั้น ๆ กันหน่อย

ปล. ไม่ค่อยได้ฟังเท่าไรนะครับ พอดีงานเข้า

ธรรมชาติของ Mobile app

Mobile app ส่วนใหญ่จะเป็น product ที่ทำการพัฒนาและเพิ่ม feature ตลอด
ที่สำคัญต้อง deploy/release กันบ่อยเช่นกัน
ทำให้ขนาดของ app ใหญ่ขึ้นเรื่อย ๆ

ถ้าไม่วางโครงสร้างของ app ให้ดี ๆ แล้ว
อนาคตอันใกล้อาจจะต้องทำการแก้ไข หรือ รื้อและทำใหม่ก็เป็นไปได้
รวมทั้งถ้า app มีขนาดใหญ่แล้ว
ก็ส่งผลต่อเวลาในการพัฒนาเช่นกัน
นั่นคือ เวลาในการพัฒนามากขึ้นเรื่อย ๆ ตามจำนวน feature !!
ทั้ง build นาน
ทั้งเพิ่ม feature ยาก
ทั้งแก้ไขยาก
ทั้งทดสอบยาก

แน่นอนว่า คงไม่มีใครอยากอยู่ในสถานการณ์เช่นนี้
แต่บอกได้เลยว่า ต้องผ่านมากันทุกคนจึงจะเข้าใจ

ดังนั้นจึงมีแนวคิดมากมายเพื่อแก้ไขและป้องกันปัญหาเหล่านี้
ตัวอย่างเช่น

  • การแบ่ง code ออกเป็น module
  • โครงสร้างของ app ที่ดีเช่น MVC, MVP, MVVM, VIPER, Redux และ Clean Architecture เป็นต้น

มาดูเรื่องแรกคือ การแบ่ง code ออกเป็น module

โดยปกติแล้วเรามักจะมี code ส่วนที่เรียกว่า common/utility
ซึ่งใช้งานร่วมกันทั้งระบบ
ดังนั้น code ส่วนนี้ควรจะแยกออกไปเป็น module/library ต่อไป
สามารถนำ module/library ต่าง ๆ เหล่านี้
ไปไว้ในตัวจัดการ dependency ต่าง ๆ ได้ เช่น

ที่สำคัญสามารถจัดการได้ทั้งแบบ public และ private
ตามที่ต้องการกันเลยทีเดียว

แต่เพียงเท่านี้ก็ยังไม่พอ
ถ้าเราสามารถแยก module ตาม feature หรือ service
จะยิ่งทำให้เกิดประโยชน์มากขึ้นไปอีก เช่น

  • Authentication
  • Authorization
  • External APIs
  • Persistence

ยิ่งถ้านำแนวคิด microservice มาใช้ในการแยก service ใน Mobile app
ก็จะช่วยทำให้เราแยกพัฒนา app ได้ง่ายขึ้น
จากนั้นทำการรวมหรือ integrate ด้วย dependency management ของแต่ละ platform ต่อไป

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

ต่อมาคือเรื่องของ Architecture ของ app

เป็นเรื่องที่สำคัญมาก ๆ
โดยใน session นั้นเป้นการแบ่งปันเรื่องของ VIPER
ซึ่งย่อมาจาก

  • View ทำการแสดงผล กับรอรับ event จากผู้ใช้งาน โดยจะถูกสั่งให้ทำงานจาก Presenter เท่านั้น
  • Interactor เป็นส่วนของ business logic ของแต่ละ use case
  • Presenter เป็นส่วนของ view logic นั่นคือรับ event ต่าง ๆ จาก view และเรียกใช้งานส่วนอื่น ๆ ตาม business process เช่นดึงข้อมูลจาก database ผ่าน interactor เมื่อได้ข้อมูลก็ส่งข้อมูลไปแสดงผลที่ view โดยที่ควรมี ViewModel สำหรับเป็น model ที่ใช้งานจาก view
  • Entity คือ data model ซึ่งถูกใช้จาก interactor
  • Routing เป็นส่วนจัดการ flow การทำงานของ app หรืออาจจะเรียกว่า Navigation logic ก็ได้

แต่ละส่วนจะมีหน้าที่การทำงานที่ชัดเจน (Single Responsibility Principle)
ทำให้การพัฒนาเป็นทีมง่ายขึ้น
ทำให้การพัฒนามาตรฐานมากขึ้น
ทำให้สามารถทดสอบแต่ละส่วนได้ง่ายขึ้น

แสดงดังรูป

มีข้อดีก็มีข้อเสีย

  • Learning curve สูง
  • ถ้าไม่เข้าใจก็จะ copy-and-paste
  • จำนวนไฟล์เยอะ แต่ถ้าเข้าใจก็สามารถลดบางสิ่งไปได้

ผมมีความคิดเห็นว่า

Architecture ของ app นั้นไม่ควรแข็งกระด้าง
หรือบางคนอาจจะเรียกว่ามันคือ pattern ต้องทำแบบนี้เสมอ
ซึ่งผลที่ตามมามันไม่ดีเลย

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

โดยที่ Architecture ที่ดีควรเป็นดังนี้

  • จำนวนไฟล์ให้แยกตามหน้าที่การทำงานของแต่ละ feature ไม่ใช่ทุก feature มีโครงสร้างเดียวกันหมด
  • สามารถทดสอบได้ง่าย
  • ง่ายต่อการใช้งาน
  • ใช้เวลาในการดูแลรักษาน้อย หรือ cost ต่ำนั่นเอง

ไปเจอข้อมูลเปรียบเทียบน่าสนใจดี
ซึ่งมอง 3 เรื่องคือ distribution, testability และ ease of use ดังรูป