Screen Shot 2558-11-05 at 4.20.18 PM
ช่วงนี้ว่างจากงาน เลยนั่งเขียนระบบงานเอาไว้ใช้เอง
ซึ่งเป็นระบบ CRM เล็ก ๆ ง่าย ๆ
โดยมี requirement ดังต่อไปนี้

  • การจัดการข้อมูลบริษัทที่ทำงานด้วย
  • การจัดการชื่อผู้ติดต่อของแต่ละบริษัท
  • การจัดการเรื่องสัญญาการทำงานของแต่ละบริษัท ประกอบไปด้วย การ training, coaching, consuling และ project

มาเริ่มพัฒนาในส่วนของ Entity ดีกว่า

เริ่มต้นด้วยการจัดการข้อมูลบริษัท

โดยหน้าตาของ Entity เป็นดังนี้

เป็น Entity ที่เรียบง่ายมาก ๆ
สามารถจัดการข้อมูลบริษัทได้แบบสบาย ๆ

จากนั้นทำการเพิ่มรายชื่อผู้ติดต่อของแต่ละบริษัท

โดยแต่ละบริษัทต้องสามารถจัดการรายชื่อผู้ติดต่อได้
ซึ่งสามารถเขียน code ได้ดังนี้

จะสังเกตได้ว่า
ความสัมพันธ์ระหว่าง Entity Company และ Contact
เป็นแบบ 2 ทิศทาง (Bidirectional)

คำถาม
ในตอนนี้มีอยู่ 2 entity คิดว่ามันก่อให้เกิดปัญหาอะไรบ้าง ตรงส่วนไหน ?
คำตอบ
ในตอนนี้ที่ผมคิดได้คือ
ปัญหาในหน้าแสดงข้อมูลบริษัท
และหน้าจัดการข้อมูลบริษัท
ซึ่งในหน้าเหล่านี้ ต้องการแสดงเฉพาะข้อมูลรายละเอียดของบริษัทเท่านั้น
ไม่ต้องการข้อมูลรายชื่อผู้ติดต่อเลย !!
แต่ในตอนนี้ Entity ของ Company มีรายชื่อของผู้ติดต่อทั้งหมดมาตลอดเวลา

คำถามคือ
เราต้องทำการดึงข้อมูลของผู้ติดต่อขึ้นมาทุกครั้งเมื่อเรียกดูข้อมูลบริษัทหรือไม่ ?
ถ้าไม่ดึงข้อมูลของผู้ติดต่อขึ้นมาเสมอ จะเกิดปัญหาอะไรตามมา ?

ดังนั้น เราควรมีตัวจัดการว่า
เมื่อไรจะดึงข้อมูล หรือ ไม่ดึงข้อมูลผู้ติดต่อมาด้วย ?
นี่เรากำลังเพิ่มความซับซ้อนให้กับ code อีกแล้วนะ !!

ที่สำคัญมันอาจจะก่อให้เกิดความผิดพลาดขึ้นมาได้อีก เช่น
ถ้าข้อมูลรายชื่อของผู้ติดต่อในแต่ละบริษัทมีค่าว่างล่ะ
มันจะหมายถึงอะไร ?
ระหว่าง ไม่มีข้อมูล หรือ ไม่ได้ทำการดึงข้อมูลขึ้นมา ?
มันก่อให้เกิดความสับสนขึ้นมาใน code อีกแล้ว !!

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

ต่อไปเพิ่มส่วนการจัดการเรื่องสัญญาการทำงานของแต่ละบริษัทว่ามีอะไรบ้าง ?

โดยจะเพิ่ม Entity Engagement ขึ้นมา
ซึ่งมีความสัมพันธ์กับ Entity Company แบบสองทิศทางเช่นกันดังนี้

คำถาม
มาถึงตรงนี้ เราพบเห็นปัญหาอะไรเพิ่มมาอีกบ้าง ?
คำตอบ
ปัญหาเดิม คือ เมื่อเราต้องการข้อมูลของบริษัทเท่านั้น
แต่ระบบต้องดึงข้อมูลทั้งรายชื่อผู้ติดต่อ และ สัญญาว่าจ้างต่าง ๆ ขึ้นมาด้วยเสมอ
หรือบางหน้าต้องการเพียงข้อมูล บริษัท และ รายชื่อสัญญาว่าจ้างเท่านั้น
หรือบางหน้าต้องการเพียงข้อมูล บริษัท และ รายชื่อผู้ติดต่อเท่านั้น

ตอนนี้เพียง 3 Entity เราก็สร้างความซับซ้อนกันขึ้นมาอีกหนึ่งเรื่องล่ะ !!
Developer นี่ชอบสร้างความซับซ้อนขึ้นมาเสมอนะเออ

ลองคิดดูสิว่า
ถ้าเราทำการดึงข้อมูลที่เกี่ยวข้องกับบริษัทบ้าง หรือ ไม่ดึงบ้าง หรือ ดึงทั้งหมดบ้าง
แสดงว่าเราได้สร้างความซับซ้อนของ code ขึ้นมาอีกหนึ่ง

ฝั่งผู้ใช้งานก็ลำบากเช่นกัน
ตัวอย่างเช่น ฝั่งผู้ใช้งานเป็นส่วนของ Web อาจจะใช้พวก JavaScript framework
ทำการติดต่อผ่าน REST APIs
มีรูปแบบข้อมูลเป็น JSON
ทางผู้ใช้งานก็ต้องตรวจสอบว่า ข้อมูลของบริษัทในหน้าต่าง ๆ ว่า
มีรายชื่อผู้ติดต่อหรือไม่ ?
มีรายชื่อสัญษาหรือไม่ ?
หรือมี หรือ ไม่มีทั้งคู่เลย ?

ลองคิดดูสิว่า
ถ้าเรายิ่งทำการลด หรือ เพิ่ม ข้อมูลที่เกี่ยวข้องกับบริษัทเข้ามาอีกล่ะ
เราจะต้องทำการเปลี่ยนแปลงกี่ที่ กี่จุด ?
คิดแล้วสยองน่าดูชม
ยิ่งถ้าเขียนชุดการทดสอบอีกนะ
ขอบอกเลยว่า การแก้ไขจะเยอะมาก ๆๆๆๆ

มาถึงตรงนี้

น่าจะพอทำให้เห็นแล้วว่า code ที่เราเขียนขึ้นมานั้น
มันสร้างความยากลำบากในการดูแลรักษามากน้อยเพียงใด ?
มันสร้างความยากลำบากในการพัฒนาเพียงใด ?
จะเปลี่ยนแปลงแต่ละครั้ง ชีวิตน่าจะเจ็บปวดไม่น้อย
ที่สำคัญปัญหามันจะใหญ่ขึ้นเรื่อย ๆ เหมือนกับ Ripple Effect เลยนะ

ลองคิดดูสิว่า
เราได้เพิ่มความซับซ้อนขึ้นมามากน้อยเพียงใด ?
แล้วเรายังจะทำกันต่อไปแบบนี้เชียวหรือ ?
ดังนั้น เรามาดูกันหน่อยว่า จะแก้ไขปัญหานี้กันอย่างไร ?

การแก้ไขแบบที่ 1

ถ้าแต่ละ Entity มันแยกกันอย่างอิสระ ก็น่าจะดีกว่านะ
โดย Entity Company ไม่ข้องเกี่ยวกับใครเลย
ส่วนอื่น ๆ ก็มีข้อมูลตามที่มันควรจะมี ดังนี้

ซึ่งวิธีการนี้ เหมาะสำหรับการบันทึกข้อมูลเท่านั้น
ส่วนการดึงข้อมูลขึ้นมาจำเป็นต้องสร้าง
สิ่งที่เรียกว่า Read object ขึ้นมา
เพื่อใช้สำหรับการอ่านข้อมูลเท่านั้น
และให้เหมาะสมกับผู้ใช้งานหนึ่ง ๆ ไปเลย ดังนี้

คำอธิบาย
เราใช้การ composition ของ Entity ต่าง ๆ เข้าด้วยกัน
ตามความต้องการของผู้ใช้งาน
ซึ่งช่วยแก้ไขปัญหา Ripple effect จากการเปลี่ยนแปลงได้
เพราะว่าแต่ละส่วนจะมี Read object ที่แตกต่างกันไป
แถมไม่ต้องมามีปัญหากับ Lazy และ Eager loading ด้วยนะ !!
ชาว ORM นิยมน่าจะเจอปัญหานี้เช่นกัน ?

การแก้ไขแบบที่ 2

ถ้าไม่ชอบการ composition ของ Read object
ก็ให้ผู้ใช้งานทำการเรียกระบบหลังบ้าน
เพื่อขอข้อมูลตามที่ต้องการ

เช่น ถ้าต้องการข้อมูลบริษัท และ รายชื่อผู้ติดต่อ
ก็ให้ผู้ใช้งานดึงข้อมูล 2 ครั้งสิ คือ
ครั้งที่ 1 ดึงข้อมูลบริษัท
ครั้งที่ 2 ดึงข้อมูลรายชื่อผู้ติดต่อ
เพียงเท่านี้ก็แก้ไขได้แล้ว
แต่จะติดใจก็ตรงที่ ต้องเรียกบ่อย ๆ เท่านั้นเอง
ดังนั้นต้องทำการตรวจสอบเพื่อวัดค่า Latency ด้วยว่าเยอะ หรือ น้อยนะครับ
ไม่เช่นนั้นจะมีปัญหาเรื่อง performance กันต่อไปอีก

โดยสรุปแล้ว

หลาย ๆ คนอาจจะคิดว่า
เพิ่งเขียนขึ้นมา 3 Entity เองนะ
ทำไมคิดเยอะจัง ?

แต่ลองถามตัวเราเองสิว่า
สิ่งที่เราคิดนั้น มันบอกว่าเราเข้าใจ business domain หรือไม่ ?
สิ่งที่เราคิดนั้น มันบอกว่าเราเข้าใจ ระบบงานหรือไม่ ?
สิ่งที่เราคิดนั้น มันสร้างความซับซ้อนขึ้นมามากมายหรือไม่ ?
สิ่งที่เราคิดนั้น มันใช้เวลานานหรือไม่ ?

สังเกตไหมว่า เราคิดทีละเล็ก ๆ
ค่อย ๆ สร้างระบบขึ้นมาเล็ก ๆ
ค่อย ๆ แก้ไขปัญหาเล็ก ๆ
ค่อย ๆ เพิ่มความซับซ้อนเล็ก ๆ เข้ามา
ไม่ทำการเพิ่มครั้งละมาก ๆ นะครับ
เมื่อผิดพลาด เราสามารถกลับตัว หรือ แก้ไขได้ทันที

แต่บางคนอาจจะบอกว่า
ปัญหาเหล่านี้จะหมดไป ถ้าเราใช้ ORM framework
ผมแนะนำว่า จะเพิ่งใช้ หรือ อย่าใช้มันเลย !!
เพราะว่า เราจะถูกปิดกั้นความคิดอยู่กับ fraemwork
จงสร้างด้วยตัวเราเองก่อน
ก่อนที่จะนำ framework มาใช้เพื่อทุ่นแรง

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