Screen Shot 2557-08-14 at 11.19.33 PM
ในการ review code ของทีม พบว่า ปัญหาเรื่องความซ้ำซ้อนของ code มีอยู่มากมาย
หนึ่งในนั้นก็คือ code ที่ซ้ำซ้อนในส่วนของการติดต่อกับฐานข้อมูล
ในโลกของภาษา Java นั้น เป็นปัญหาที่น่าจะเจอมากมาย
สำหรับคนที่ยังใช้งานผ่าน JDBC (Java Database Conectivity) แบบเดิมๆ
แต่ถ้าใครใช้งานผ่านพวก OR mapping และ Spring framework ก็น่าจะไม่ค่อยมีปัญหา
แต่สิ่งที่น่าถามคือ คุณรู้หรือไม่ว่าด้านหลังมันทำงานหรือสร้างอย่างไร ?

แต่ในบทความนี้จะเน้นเรื่องการ refactor code ส่วนของการติดต่อฐานข้อมูลผ่าน JDBC แบบเดิม
ซึ่งมักจะถูกเรียกว่า DAO ( Data Access Object ) หรือว่า Repository
ดังนั้นมาดูกันว่ามีขั้นตอนการลดความซ้ำซ้อนของ code ลงอย่างไร

เริ่มต้นจากปัญหากันก่อน

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

  • การ prepare statement
  • การดึงข้อมูลจากฐานข้อมูล อยู่ในรูปของ ResultSet
  • การแปลงข้อมูลใน ResultSet เข้าไปยัง object ที่เราต้องการ
  • ส่งข้อมูลกลับไปยังผู้เรียกใช้

ตัวอย่างของ code ที่ซ้ำซ้อนกัน ประกอบไปด้วย 3 method คือ

  • getPerson() ดึงรายละเอียดของ person
  • getAll() ดึงข้อมูลทั้งหมดของ person
  • countPerson() นับจำนวนข้อมูลของ person

มี code ดังนี้

ข้อสังเกตจากทั้งสอง method พบว่า สิ่งที่ซ้ำซ้อนชัดๆ เลย ก็คือ

การแปลงข้อมูลใน ResultSet ไปยัง Person object ดังนี้

Person person = new Person();
person.setID(resultSet.getInt("ID"));
person.setFirstName(resultSet.getString("FIRSTNAME"));

ดังนั้นในส่วนนี้ สามารถทำการ refactor code ด้วยการแยก code ส่วนดังกล่าว
ไปยัง method ใหม่ โดยผมตั้งชื่อ method ใหม่ว่า mappingPerson() ดังนี้

โดย code ในส่วนของ method getAll() และ getPerson() ก็จะลดความซ้ำซ้อนลงนิดหน่อย

แต่ว่า code ทั้งสอง method ก็ยังซ้ำซ้อนอีกเยอะเลย จะทำอย่างไรดีล่ะ

เมื่อลองนั่งดู code แล้วจะพบว่าการซ้ำซ้อนมันจะมีรูปแบบที่ชัดเจน เหมือนกับ Template
ทำให้ผมนึกถึง Spring JDBC ดังนั้น ผมจึงนั่งออกแบบโครงสร้างของ class ที่ผมต้องการ ดังรูป

Screen Shot 2557-08-14 at 4.20.35 PM

ประกอบไปด้วย

  • คลาส JdbcTemplate สำหรับเตรียม method เพื่อดึงข้อมูล เช่น การดึงข้อมูลออกมาเป็น List และ การดึงข้อมูลออกมา 1 object เป็นต้น
  • RowMapper สำหรับการแปลงข้อมูลจาก ResultSet มายัง Object ที่ต้องการ โดยใช้แนวคิดของ Template Method Pattern

ในการพัฒนาเราจะนำความสามารถของ Java Generic มาใช้อีกแล้ว เพื่อให้สามารถทำงานกับ Object ต่างๆ ได้

ตัวอย่าง code ของคลาส RowMapper เป็นดังนี้

และจากตัวอย่างผมต้องการแปลงข้อมูลมาใส่ Person object ดังนั้นจึงต้องมีคลาส PersonRowMapper ขึ้นมา ดังนี้

จากนั้นในคลาส JdbcTemplate เป็นเหมือนตัวแทนที่รวบรวมขั้นตอนการทำงาน
สำหรับดึงข้อมูลต่างๆ จากฐานข้อมูลไว้ที่เดียว โดยสิ่งที่เราต้องส่งค่าไปให้แต่ละ method นั้นประกอบไปด้วย

  • ชุดคำสั่ง sql ที่ใช้ดึงข้อมูล
  • List ของ parameter ที่ต้องการส่งเข้าไปในชุดคำสั่ง sql
  • RowMapper ที่ต้องการใช้งาน ซึ่งใช้ความสามารถของ Java Generic มาช่วย

ตัวอย่างใน method  executeQuery() ของคลาส JdbcTemplate เป็นดังนี้

เมื่อสร้างทุกอย่างเรียบร้อยแล้ว ทำการแก้ไขวิธีการทำงานใน PersonDAO
เพื่อให้เรียกใช้งานผ่าน JdbcTemplate ที่เราสร้างขึ้นมา ดังนี้

เมื่อทำการสั่งให้ run unit test ที่เขียนไว้ จะพบว่ายังทำงานผ่านเช่นเดิมนะ

Screen Shot 2557-08-14 at 10.52.39 PM

โดยรวมแล้ว

จะเห็นว่าในการลดความซ้ำซ้อนใน code ส่วน Data Access Object หรือ Repository นั้น
สามารถนำแนวคิดที่เรียบง่ายที่สุด จนไปถึง แนวคิดเชิง Object Oriented มาช่วย
ส่งผลให้ code ของเราอ่านง่าย แก้ไขง่าย รวมทั้งยังลดความซ้ำซ้อนลงไปพอสมควร

ข้อเสียก็คือ จำนวนของคลาสและไฟล์ที่สูงขึ้น
แต่ถ้าในแต่ละคลาสและไฟล์ มีจำนวน LoC ที่น้อย
ก็น่าจะช่วยลดเวลาในการทำความเข้าใจลงเช่นกัน
รวมทั้งจะต้องมี unit test เพื่อทดสอบส่วนการทำงานต่างๆ
ก็ยิ่งจะช่วยอธิบายการทำงานของ code ได้ดียิ่งขึ้น

สิ่งที่สำคัญมากๆ ก็คือ จะต้องมี unit test เสมอ ไม่เช่นนั้นคุณจะมั่นใจในการ refactor code ได้อย่างไร