วันอาทิตย์ที่ 20 ธันวาคม พ.ศ. 2558

ไม่ใช้ DAO แต่ควรใช้ Repository?

วันก่อนอ่านบทความเรื่อง Don’t use DAO, use Repository มันเป็นยังไงนะ?

>> DAO ย่อมาจาก Data Access Object คือหลักการเพื่อต้องการให้จาวาคลาสธรรมดาสามารถสร้างความสัมพันธ์กับข้อมูลในฐานข้อมูลในรูปแบบ Relational Database ง่ายๆว่าหนึ่งคลาสคือหนึ่งตารางในฐานข้อมูล (จริงๆทำได้มากกว่านี้) เวลาจะอ้างถึงฟิลด์ (หรือคอลัมน์) ใดๆในตารางก็ให้เรียกไปที่เมธอด getters หรือ setters ของคลาสนั้นๆแทน

>> DAO ตามหลักการนั้นเราจะต้องออกแบบ Relational Database ให้ดีเสียก่อน เป็นไปได้เพื่อความง่ายต่อการนำไปใช้งาน ก็ควรให้มีหนึ่งตารางคู่กับหนึ่งคลาสเท่านั้น และคลาสดังกล่าวก็ควรเป็น POJO (Plain Old Java Object) ด้วยนะครับ

>> ทีนี้มาเข้าประเด็นไม่เอา DAO แต่ให้ใช้ Repository แทน? เรื่องเป็นมาอย่างนี้ครับ
- เดิมทีเขา (ผู้เขียนบทความไง) มีคลาส Account ที่ implement หลักการ DAO และตั้งชื่อว่า AccountDAO
- AccountDAO ประกอบด้วยบริการพื้นฐานสำหรับทำงานกับข้อมูลในตาราง โดยใช้หลักการ CRUD อีกที ได้แก่ การสร้าง (Create), การค้นหา (Retrieve), การแก้ไข (Update) และการลบ (Delete)
- หากเขาประสงค์ร้องขอ Account โดยกำหนดแค่นามสกุลของลูกค้า (last name) เพื่อไปค้นหาล่ะ? การค้นหาที่มีอยู่ตอบสนองเขาได้หรือไม่? มีสองคำตอบคือ 1) ไม่ได้ เพราะไม่มีบริการนี้อยู่ หรือ 2) ได้สิ ถ้าสร้างบริการที่ค้นด้วยนามสกุล (เพิ่มเมธอด)
- หากเขาประสงค์ร้องขอ Account โดยกำหนดเป็นหมายเลขบัญชีแทนนามสกุลล่ะ? คำตอบนั้นก็ยังเป็นเช่นเดิมใช่ไหมครับ
- จะเห็นได้ว่า AccountDAO ของเขากำลังอ้วนเมื่อเวลาผ่านไป (ว้ายตายแล้ว!) เนื่องจากเงื่อนไขที่กระทำต่อ CRUD เพิ่มมากขึ้น (และเพี้ยน) นั่นเท่ากับว่าความเป็น DAO นั้นลดน้อยลงไป (ถ้าคุณยอมรับได้ก็อีกเรื่อง จะผืนเรียกมันว่า DAO ต่อไปก็ตามใจ)
- แต่สำหรับเขาแล้ว เรื่องนี้มันสุดทานทน

>> ใช้หลักการ Repository ดีกว่า ซึ่งงานจริงๆก็ควรเป็นอย่างนี้ เอาล่ะ Repository ก็คือเซตของออบเจ็กต์ที่มีความสัมพันธ์ต่อกันในแง่ใดแง่หนึ่ง มันยังเป็นเหมือนกับ Collection หรือก็คือที่สะสมของปานนั้น
- เปลี่ยนคลาส Account ที่ implement หลักการ DAO เป็นหลัการ Repository โดยให้ชื่อว่า AccountRepository
- AccountRepository ประกอบด้วยบริการ addAccount, removeAccount และ updateAccount นอกจากนี้ให้เพิ่มบริการ query เข้าไป หัวใจของมันก็คือพารามิเตอร์ที่ชื่อ AccountSpecification ซึ่งเป็น interface ครับ ฮั่นแน่! ใครอ่านถึงตอนนี้คงเริ่มงงว่าเจ้า AccountSpecification นี้มันทำหน้าที่อะไร
- AccountSpecification จะเป็นตัวบริการคอยบอกว่า ข้อมูล จากฐานข้อมูล อยู่ใน หน่วยความจำหลัก แล้วหรือยัง? เรื่องนี้สำคัญมากนะครับ เพราะข้อมูลที่ต้องดึงจากฐานข้อมูลอยู่บ่อยๆนั้น ควรได้รับการบริหารจัดการที่ดี หนึ่งในวิธีการดังกล่าวคือ เมื่อไปดึงมาครั้งหนึ่งแล้ว (อยู่ในหน่วยความจำหลักเรียบร้อย) ครั้งต่อไปก็ไม่ต้องไปดึงมาอีก ให้หาเอาจากหน่วยความจำหลักได้เลย (ของที่อยู่ใน RAM อย่างไรก็ค้นไวกว่าของที่ต้องดึงจากดิสก์หลายสิบหลายร้อยเท่า) ฉะนั้น AccountSpecification จึงมีบริการ specified เตรียมไว้ให้ใช้ไงล่ะครับ (^^)
- AccountRepository ไม่เพียงแต่ต้องประกอบด้วย interface ที่ชื่อ AccountSpecification เพราะว่างาน query นั้นมักมากไปด้วยเงื่อนไข เขาได้เพิ่ม interface ที่ชื่อ SqlSpecification เข้าไปด้วย
- SqlSpecification ให้บริการ toSqlClauses เพื่อสร้างเงื่อนไข WHERE ต่อกันเป็นทอดๆนั่นเอง

>> ทั้งหมดนี้ผมอ่านจาก http://thinkinginobjects.com/2012/08/26/dont-use-dao-use-repository/

>> เขียนโปรแกรม 'ได้' นั้นไม่ยากครับ ดูไวยากรณ์ + business logic ให้เข้าใจก็เขียนได้ แต่เขียนโปรแกรม 'เป็น' นั้นยากกว่าหลายเท่านัก ไม่เพียงแต่ต้องเข้าใจ business logic ยังต้องเข้าใจวิธีการ implement งานด้วยหลักการต่างๆได้ด้วย อาชีพนักเขียนโปรแกรมนี้จึงจะเรียกได้ว่าถูกเติมเต็มอย่างภาคภูมิครับ

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

1 ความคิดเห็น: