ป้ายกำกับ: เดิน

Clean Architecture: Data Transfer Objects (DTOs) & Crossing BoundariesClean Architecture: Data Transfer Objects (DTOs) & Crossing Boundaries

ในฐานะ Senior Architect การออกแบบระบบที่ยืดหยุ่นและบำรุงรักษาง่ายเป็นสิ่งสำคัญยิ่ง Clean Architecture ช่วยให้เราแยกส่วนประกอบของแอปพลิเคชันออกจากกันอย่างชัดเจน โดยเฉพาะอย่างยิ่งเมื่อเราต้องจัดการกับการสื่อสารระหว่าง Use Case Layer (Business Logic) กับ Persistence Layer (Database) หัวใจสำคัญของการแยกส่วนนี้คือการใช้ Data Transfer Objects (DTOs) เพื่อทำหน้าที่เป็นสัญญา (Contract) ของข้อมูลที่บริสุทธิ์

The Role of DTOs in PostgreSQL Context

DTOs คือรูปแบบข้อมูลที่ถูกออกแบบมาเพื่อส่งผ่านข้อมูลระหว่างขอบเขต (Boundaries) ต่างๆ ของระบบ โดยมีวัตถุประสงค์หลักคือการป้องกันไม่ให้ Entity หรือ Model ของ Domain ถูกเปิดเผยไปยังชั้นที่ต่ำกว่า (เช่น Database Schema) การใช้ DTOs ทำให้ Use Case Layer ไม่ต้องขึ้นอยู่กับรายละเอียดของตารางหรือคอลัมน์ของ PostgreSQL โดยตรง

เมื่อเราทำงานกับ PostgreSQL ข้อมูลดิบจะอยู่ในรูปแบบของ Record Set ซึ่งมีโครงสร้างที่ผูกติดกับ Schema อย่างแน่นหนา การแปลงข้อมูลเหล่านี้ให้เป็น DTOs ที่สะอาดและเป็นอิสระจึงเป็นกระบวนการสำคัญที่เรียกว่า ‘Crossing Boundaries’

Example: Mapping Database Records to DTOs using PostgreSQL

สมมติว่าเรามีตาราง `products` และเราต้องการดึงข้อมูลเพื่อส่งให้ Use Case Layer โดยไม่ให้ชั้นนั้นรู้ถึงรายละเอียดของคอลัมน์ภายใน เราสามารถใช้ PostgreSQL Function เพื่อทำการแปลง (Mapping) ข้อมูลให้เป็นโครงสร้าง DTO ที่กำหนดไว้:

SQL

-- 1. Define the structure (Simulating the DTO output) --
CREATE TYPE product_dto AS (product_id INT, name VARCHAR, price NUMERIC);

-- 2. Function to fetch and transform data (Crossing the boundary) --
CREATE OR REPLACE FUNCTION get_product_dto(p_id INT) RETURNS product_dto AS $$
BEGIN
    RETURN ROW(p_id, name, price)::product_dto
    FROM (SELECT 1 AS id, 'Laptop' AS name, 1200.00::numeric AS price) AS raw_data
    WHERE raw_data.id = p_id;
END;$$

-- 3. Usage Example: The application calls the function, receiving a clean DTO
SELECT get_product_dto(1);

ในตัวอย่างนี้ ฟังก์ชัน `get_product_dto` ทำหน้าที่เป็นตัวกลางในการรับข้อมูลดิบจากตาราง (Persistence Layer) และส่งออกเป็น `product_dto` ซึ่งเป็นรูปแบบข้อมูลที่ Use Case Layer คาดหวัง ทำให้เกิดการแยกส่วนที่ชัดเจน (Decoupling) อย่างสมบูรณ์

Best Practices for Boundary Crossing

เพื่อรักษาความสะอาดของสถาปัตยกรรม ควรปฏิบัติตามหลักการเหล่านี้:

  • Immutability: DTOs ควรเป็นข้อมูลที่ไม่สามารถเปลี่ยนแปลงได้ (Immutable) เมื่อถูกส่งผ่านขอบเขตแล้ว
  • Minimalism: DTOs ควรมีเฉพาะฟิลด์ที่ Use Case Layer ต้องการเท่านั้น ไม่ควรส่งข้อมูลทั้งหมดจาก Database
  • Repository Pattern: ใช้ Repository Pattern ในการจัดการการเรียกใช้ข้อมูลจาก PostgreSQL โดยให้ Repository รับผิดชอบในการแปลง Record Set ให้เป็น DTO เสมอ

Conclusion

การใช้ DTOs ในการจัดการ Boundary Crossing คือการยกระดับความแข็งแกร่งของระบบให้เป็นไปตามหลัก Clean Architecture มันช่วยให้เราสามารถเปลี่ยน Database Schema หรือเปลี่ยนฐานข้อมูลได้โดยที่ Business Logic หลักของเราไม่ได้รับผลกระทบใดๆ ทำให้ระบบมีความยืดหยุ่นสูง ทดสอบได้ง่าย และพร้อมสำหรับการขยายตัวในอนาคต