ตอนที่ 8: Repository ใน Domain-Driven Design – ทำไมไม่ใช่แค่ CRUD

บทนำ

เมื่อพูดถึงคำว่า Repository นักพัฒนาจำนวนมากมักจะนึกถึงไฟล์ที่มีแต่ create, read, update, delete

แต่ใน Domain-Driven Design (DDD) นั้น Repository มีความหมายและบทบาทที่ลึกกว่านั้นมาก

บทความตอนนี้จะอธิบายว่า Repository ใน DDD คืออะไร, แตกต่างจาก CRUD แบบทั่วไปอย่างไร และควรออกแบบอย่างไรให้ Domain สะอาดและยั่งยืน โดยใช้ตัวอย่าง ระบบพนักงาน (Employee Management System)


Repository ใน Domain-Driven Design คืออะไร

Repository คือ abstraction ที่ทำหน้าที่:

  • ทำให้ Domain รู้สึกเหมือนกำลังทำงานกับ object ในหน่วยความจำ
  • ซ่อนรายละเอียดของ database, ORM, API หรือ storage ใด ๆ
  • ให้ Domain Model โฟกัสกับ business logic โดยไม่ผูกกับเทคโนโลยี

Repository คือ “ภาพลวงตา” ที่ทำให้ Domain คิดว่า object ยังมีชีวิตอยู่ตลอดเวลา


Repository ไม่ใช่ DAO และไม่ใช่ CRUD

ความเข้าใจผิดที่พบบ่อยคือ:

Repository = DAO + CRUD

ใน DDD แนวคิดนี้ ผิดโดยหลักการ

เปรียบเทียบ Repository vs CRUD

หัวข้อRepository (DDD)CRUD / DAO
มุมมองDomain-centricDatabase-centric
คืนค่าAggregateRecord / Row
เมธอดใช้ภาษา Domainใช้ภาษาเทคนิค
ผู้ใช้งานDomain / Application ServiceController / Service

Repository ถูกออกแบบมาเพื่อ Aggregate ไม่ใช่ table


ตัวอย่างจากระบบพนักงาน

Aggregate: Employee

สิ่งที่ Repository ควรมี:

  • findById(EmployeeId id)
  • save(Employee employee)
  • findActiveEmployees()

สิ่งที่ Repository ไม่ควรมี:

  • updateSalaryById()
  • deleteByDepartmentId()
  • findBySalaryGreaterThan() (ถ้าไม่ใช่ภาษา Domain)

ถ้า method ไหนอ่านแล้วไม่ใช่ภาษาของธุรกิจ นั่นคือสัญญาณเตือน


Repository ทำงานร่วมกับ Application Service อย่างไร

Repository ไม่ควรถูกเรียกโดย UI หรือ Controller โดยตรง

โครงสร้างที่เหมาะสมคือ:

UI / API
   ↓
Application Service / Use Case
   ↓
Repository
   ↓
Domain Model (Aggregate)

Application Service:

  • ตัดสินใจว่า use case ต้องโหลดอะไร
  • เรียก Repository
  • ส่ง Aggregate ให้ Domain ทำงานต่อ

ทำไม Repository ควรคืนค่าเป็น Aggregate

เพราะ:

  • Aggregate คือ boundary ของ consistency
  • Business rule ถูกคุมอยู่ภายใน
  • ป้องกันการแก้ state แบบข้ามกฎ

ถ้า Repository คืนค่าเป็น DTO หรือ Map:

  • Domain จะอ่อนแรง
  • Invariant จะถูกละเมิดง่าย
  • Logic จะไหลไปอยู่ผิดที่

Repository กับ Infrastructure

ใน DDD:

  • Interface ของ Repository อยู่ใน Domain Layer
  • Implementation อยู่ใน Infrastructure Layer

Domain:

  • ไม่รู้จัก database
  • ไม่รู้จัก ORM
  • ไม่รู้จัก framework

Infrastructure:

  • แปลง Aggregate ↔ persistence model
  • จัดการ transaction ระดับเทคนิค

สัญญาณว่า Repository ของคุณเริ่มผิดทาง

  • Repository มี method เยอะผิดปกติ
  • Method name เต็มไปด้วยเงื่อนไขเชิง query
  • Business logic เริ่มไหลเข้า Repository
  • Aggregate กลายเป็น data holder

ถ้าเห็นสัญญาณเหล่านี้ แปลว่าคุณกำลังหลุดจาก DDD


สรุป

  • Repository ใน Domain-Driven Design ไม่ใช่ CRUD
  • ถูกออกแบบเพื่อ Aggregate ไม่ใช่ table
  • ใช้ภาษา Domain ไม่ใช่ภาษา database
  • ช่วยปกป้อง business rule และโครงสร้างของ Domain

ในตอนถัดไป เราจะพูดถึง Domain Event – เมื่อระบบธุรกิจขับเคลื่อนด้วยเหตุการณ์ ซึ่งเป็นก้าวสำคัญของระบบที่ scale ได้จริง