จากงาน Android Dev Summit 2015 นั้น
มีหัวข้อที่น่าสนใจเยอะเลย หนึ่งในนั้นคือ Android Application Architecture
ได้อธิบายสิ่งต่าง ๆ ที่น่าสนใจสำหรับการพัฒนา Android application
แต่หัวข้อที่ชอบมาก ๆ คือ โครงสร้างการทำงานของระบบ
มาดูกันว่าเป็นอย่างไร
เริ่มต้นได้อย่างน่าคิด
อะไรที่คุณตัดสินใจไปแล้วมันจะอยู่กับคุณไปตลอด ดังนั้นคิดให้ดี ๆ โดยโครงสร้างของ app ที่คิดขึ้นมานั้น มันจะง่าย หรือ ยาก ให้คิดถึงปัญหาที่ต้องการแก้ไขเป็นหลัก ไม่ใช่คิดถึง วิธีการแก้ไขปัญหา หรือ framework หรือ library เป็นหลัก !! คำถามต่อมา น่าคิดมาก ๆ คือ แล้วโครงสร้างของระบบจะเป็นแบบไหนดีล่ะ ?- MVC
- MVP
- MVP-I
- MVVM
- MVVM-I
- VIPER
- Clean Architecture
- Reactive
- Flux
- ...
สิ่งที่แนะนำในการออกแบบ คือ Architect for UX (User Experience)
มันเป็นอย่างไรล่ะ ? ตัวอย่าง App ต้องทำการส่งข้อมูลไปยัง server คำถามคือ จะขึ้นรูป loading ทำไม ? แถมบางครั้งถ้า network มีปัญหา รูป loading มันไม่หายไปด้วย ทำให้ app ปิดตัวเองอีก ซึ่งเป็นประสบการณ์การใช้งานที่ไม่ดีเลยใช่ไหม ? แสดงการทำงานดังรูป ปัญหาจากรูปแบบการทำงานนี้ คือ View จะรอไปจนกว่าจะได้ข้อมูลจาก ViewController และ Network นั่นคือ ViewController มันผูกติดกับ Network อย่างมาก !! สามารถแก้ไขด้วยการแยก ViewController ออกจาก Network ซะ ด้วยการเพิ่มอีกหนึ่งส่วน หรือ อีกหนึ่ง layer นั่นคือ Model เนื่องจาก ViewController นั้นต้องการเพียงข้อมูลเพื่อส่งไปแสดงผลที่ View เท่านั้น ไม่ได้ต้องการ Network เลย แสดงการทำงานดังรูป แต่จากรูปแบบนี้ก็ยังคงมีปัญหากับ Network อยู่ใช่ไหม ? เนื่องจากเราเพียงย้ายให้ Network ไปทำงานกับ Model เท่านั้นเอง ดังนั้น จะแก้ไขปัญหานี้อย่างไรดีล่ะ ? สิ่งที่ต้องทำก็คือ Model นั้นให้เป็น Persistent model ที่อยู่บนเครื่อง หรือ Local ซะ และเพิ่มส่วนของ Application Logic ขึ้นมา เพื่อทำงานร่วมกับ Network แทน โดยแบ่งการทำงานเป็นส่วน ๆ ดังนี้ ส่วนที่ 1 เมื่อ Application logic ได้ข้อมูลจาก Network หรือ sync data เรียบร้อยแล้ว จะทำการส่ง หรือ จัดเก็บไปที่ Persistent Model แสดงการทำงานดังรูป ส่วนที่ 2 ส่วนของ ViewController เมื่อต้องการข้อมูลไปแสดงผลที่ View ก็ให้ทำการดึงข้อมูลจาก Persistent Model แทน ซึ่งไม่ต้องรออะไรเลย แสดงการทำงานดังรูป ส่วนที่ 3 เมื่อมีการร้องขอ หรือ ส่งข้อมูลมาจากผู้ใช้งานผ่าน View จะทำการส่งการร้องขอมายัง ViewController จากนั้นจะส่งการร้องขอไปยัง Application Logic เพื่อทำงาน ซึ่งจะทำงาน 2 อย่าง คือ- ทำการ update ข้อมูลที่ Persistent Model
- ทำการส่งข้อมูลไปยัง Network
มาถึงตรงนี้อาจจะงงอีกว่า จะแจ้งกลับไปยัง ViewController ยังไงว่าทำงานเสร็จแล้ว ?
น่าคิดมาก ๆ ดังนั้นในขั้นตอนการส่งคำร้องขอตั้งแต่แรก ต้องมีการจัดการ event หรือ เหตุการณ์ต่าง ๆ ไว้ก่อนนะ นั่นคือมีการ register event และ subscribe ไว้ เมื่อมีการทำการเสร็จสิ้นก็ให้ทำการส่ง notify ไปยัง subscribe นั้น ๆ จากนั้นก็ทำการ unsubscribe ซะ เป็นอันพบขั้นตอนการทำงาน แนวคิดพวกนี้มันคือ EventBus นั่นเอง แต่ทำมาเยอะขนาดนี้ มันก็ยังไม่ปัญหาตามมาอีก นั่นคือ เรื่องของ Background process ถ้า queue การทำงานมันค้าง และ เต็ม ทำให้ process อื่น ๆ ที่อยู่ใน queue รอไปเรื่อย ๆ จะส่งผลให้ app ค้าง หรือ ปิดตัวไปอีก แสดงการทำงานดังรูป การแก้ไขปัญหานี้คือ ก็ให้แยก queue ของการทำงานให้ทำงานคนละ Thread ไป นั่นคือ- Network task queue
- Local task queue
สามารถสรุปการทำงานในส่วนของ Activity สำหรับการ Notify ได้ดังนี้ ( Activity State Machine )
- onCreate() ทำการ setup พวก User Interface ต่าง ๆ
- onStart() ทำการ register event เช่น การดึงข้อมูล
- เมื่อเกิด event ขึ้นมา หรือ onEvent() หรือ ดึงข้อมูลเสร็จแล้ว จะทำการ refesh ข้อมูลใหม่
- onStop() ทำการ unregister event
Key Takeaway มีดังนี้
- Design for offline เนื่องจากเรื่องของ network มันไม่เคยเป็นมิตรกับใครเลย
- ให้ส่วนของ User Interface ใช้ข้อมูลจาก model
- ส่วนของ network และการ update model ให้ Application Logic จัดการ
- ให้แต่ละส่วนทำงานเป็นอิสระจากกัน อาจจะใช้งาน Event, Callback หรืออะไรก็ได้ที่จำเป็น
- Decoupling แต่ละส่วนแยกกันทำงาน
- สามารถนำ Dependency Injection มาใช้งานได้
- มันมีทั้งข้อดีและข้อเสีย ต้องทำความเข้าใจก่อน ไม่ใช่ทำตาม ๆ กันไป
- อย่าใช้ Reflection API โดยเด็ดขาด เพราะว่ามันทำให้ performance ต่ำลงไปมาก ดังนั้นเลือก library ให้ระวังกันด้วย
- Design API
- ออกแบบ API เพื่อฝั่ง client หรือ ผู้ใช้งานนะ
- ให้ฝั่ง client ทำงานน้อยที่สุด
- ให้ฝั่ง server ทำงานมากที่สุด
- Act locally, Sync Globally !!