Bad OOP Design
วันนี้เป็นวันที่เริ่ม Implement Windows Service แบบจริงๆ จังๆ ดู พอดูโค้ดเก่าที่เคยทำไว้ ผมพบว่าบางสิ่งที่ผมคิดว่าเป็น Bad Design ใน OOP - การนำ ErrorMessage เข้าไปรวมในคลาสรับส่งข้อมูล จริงอยู่ว่าการรับส่งข้อมูลระหว่างฐานข้อมูล เน็ตเวิร์ก หรือ Thread ต่างๆ บนโปรแกรมเดียวกัน ควรจะมีตัวบ่งบอกว่าการรับส่งข้อมูลสำเหร็จมั้ย และถ้าไม่สำเร็จเกิดจากอะไร แต่ที่ผมพบคือ การรวม ErrorMessage และ Error ที่เกิดเข้าไปในคลาสรับส่งข้อมูลเลยทันที เช่น class SomeMessage { object Content1; object Content2; bool IsSuccess; string ErrorMessage; } การ Design Class แบบนี้นั้นถึงใครจะมองว่ายังไง แต่ผมคิดว่ามันแย่มากๆ เหตุผลเพราะเมื่อมี Instance ของคลาสดังกล่าวออกมา เราจำเป็นต้องเช็คตลอดเวลาว่ามันมี ErrorMessage ติดมาด้วยหรือเปล่าก่อนใช้ ซึ่งเรามีเครื่องมือที่มีประสิทธิภาพอย่าง OOP แล้วทำไมเราต้องมานั่งเช็คแบบนี้อีก ลองนึกภาพของหลักการ OOP ที่มองทุกๆ Instance เป็นวัตถุ ถ้าเราต้องมานั่งเช็คด้วยมือตลอดเวลาว่าวัตถุที่เราใช้งานมีตำหนิหรือเปล่า (Error หรือไม่) มันก็ดูผิดประหลาด ถ้าเอาให้เห็นภาพผมลองยกตัวอย่างว่าเรามีคำสั่ง ProcessMessage(SomeMessage Parameter) ถ้าเรา Design แบบข้างบนแปลว่าทุกครั้งที่เราเรียก ProcessMessage ต้องใช้อย่างน้อย 2 บรรทัดเสมอ If (Message.IsSuccess) ProcessMessage(Message); ซึ่งถ้าเรามี Method ที่รับ SomeMessage เยอะๆ แล้วเราจะทำยังไงล่ะ มานั่งเช็คทุกรอบเหรอ??? จริงๆ เราอาจจะเช็คแต่แรกก็ได้ เช่น var message=GetMessage(); if (!message.IsSuccess) message=null; แต่เราจะมั่นใจได้อย่างไรว่าเราจะไม่เผลอพลาดลืมเช็คไปเมื่อเขียนโค้ดเยอะๆ แถม null reference นี่เป็นปัญหา debug ยากอันดับต้นๆ วิธีการออกแบบที่ดีเราควรจะแยกส่วน Content และ ErrorMessage ออกจากกัน แล้วคลาสที่รับส่งข้อมูลผ่านเน็ตเวิร์ก ฐานข้อมูล หรือ Threading ควรจะไม่สามารถทำอย่างอื่นได้เลยจนกว่าจะเช็คแล้วว่าการรับส่งสมบูรณ์ ถ้าการ Design แบบสมบูรณ์จริงๆ ผมคิดว่าน่าจะเป็นแบบนี้ class SomeMessage { object Content1; object Content2; } class ConnectionMessage { private object Content; int ErrorCode; string ErrorMessage; public object GetContent() { if (ErrorCode!=0) throw new Exception("Error Getting Data"); return Content; } } แล้วจึงเอา SomeMessage ไปยัดไว้ใน ConnectionMessage อีกที การทำแบบนี้จะทำให้รับประกันว่าไม่ว่าอนาคตเราจะเขียนตกหล่นยังไง แต่ถ้าเราพยายามจะดึงข้อมูลที่ไม่สมบูรณ์มี Error ออกมาเมื่อไหร่ จะได้ Exception ตามมาทันที แล้วเราจะเอา ConnectionMessage ไปใส่ใน Method ต่างๆ โดยไม่ดึง Content ออกมาก่อนก็ไม่ได้ จึงรับประกันได้เลยว่าถ้าเราซุ่มซ่ามพยายามดึงข้อมูลที่ส่งผ่านกันไม่สำเร็จเมื่อไหร่ มันจะเกิด Exception ทันที ซึ่งจะดีกว่าเกิด Bug เอามากๆ ปล. แต่รับสารภาพว่าตัวเองก็ไม่ได้เขียนถึงขั้นล็อกไว้ให้ GetContent ยิง Exception ออกมา เพราะขี้เกียจครับ ก็แค่ห่อไว้ใน ConnectionMessage เท่านั้น นิสัยเสียจริงๆ
Create Date : 30 สิงหาคม 2555 |
Last Update : 30 สิงหาคม 2555 21:28:27 น. |
|
0 comments
|
Counter : 437 Pageviews. |
|
|