ในฐานะ System Architect การออกแบบระบบที่ยืดหยุ่นและสามารถบำรุงรักษาได้ในระยะยาวถือเป็นสิ่งสำคัญที่สุด Clean Architecture เป็นแนวคิดที่ช่วยให้เราแยกส่วนประกอบของแอปพลิเคชันออกจากกันอย่างชัดเจน โดยมีหัวใจหลักคือการปฏิบัติตามหลักการ Dependency Inversion Principle (DIP) ซึ่งเป็นหนึ่งใน SOLID Principles ที่ช่วยให้ระบบของเราไม่ผูกติดกับรายละเอียดการทำงานของเทคโนโลยีใดเทคโนโลยีหนึ่ง
Dependency Inversion Principle (DIP) ในบริบทของ PostgreSQL
DIP ระบุว่าโมดูลระดับสูง (High-level modules) ไม่ควรขึ้นอยู่กับโมดูลระดับล่าง (Low-level modules) แต่ควรขึ้นอยู่กับ Abstraction (นามธรรม) แทน ในบริบทของการใช้ PostgreSQL ซึ่งเป็นฐานข้อมูลที่ทรงพลัง การนำ DIP มาใช้หมายความว่าชั้น Business Logic ของเราไม่ควรเรียกใช้ฟังก์ชันหรือตารางที่ผูกติดกับรายละเอียดของ ORM หรือ Driver โดยตรง แต่ควรเรียกใช้ผ่าน Interface หรือ Contract ที่เรากำหนดขึ้นมาเอง
เมื่อเราออกแบบ Repository Layer ที่ทำงานกับ PostgreSQL เราจะสร้าง Abstraction (เช่น PostgreSQL Function หรือ Custom Type) เพื่อให้ Business Layer สามารถ ‘ร้องขอ’ การทำงานได้ โดยไม่สนใจว่าการทำงานจริงจะเกิดขึ้นด้วย SQL Query ที่ซับซ้อนแค่ไหน นี่คือการพลิกกลับ (Inversion) ของการพึ่งพาการทำงาน
การจำลอง DIP ด้วย PostgreSQL Functions
เราสามารถใช้ PostgreSQL Functions เพื่อกำหนด Contract หรือ Port ที่ Business Logic จะต้องเรียกใช้ได้ ตัวอย่างเช่น แทนที่จะให้ Service Layer เรียกใช้ `SELECT * FROM users WHERE id = $1` โดยตรง เราจะสร้างฟังก์ชันที่ทำหน้าที่เป็นตัวกลาง (Abstraction) ให้ Service Layer เรียกใช้แทน
SQL
-- 1. สร้าง Abstraction (Port) ที่ Service Layer จะเรียกใช้<br>CREATE OR REPLACE FUNCTION get_user_data_by_id(p_user_id INT) RETURNS JSON AS $$<br>BEGIN<br> -- ฟังก์ชันนี้ทำหน้าที่เป็น Contract ที่ Business Layer ต้องพึ่งพา<br> RETURN json_build_object('id', p_user_id, 'status', 'active');<br>END;<br>$$ LANGUAGE plpgsql;<br><br>-- 2. Business Logic (Service Layer) เรียกใช้ Abstraction นี้เท่านั้น<br>SELECT get_user_data_by_id(101);<br>
ในตัวอย่างนี้ Service Layer ไม่จำเป็นต้องรู้ว่าข้อมูลถูกดึงมาจากตารางใด หรือใช้ SQL Query แบบใด มันเพียงแค่รู้ว่าต้องเรียกใช้ `get_user_data_by_id()` ซึ่งเป็นการพึ่งพา Abstraction ที่เรากำหนดไว้
ประโยชน์ของการใช้ DIP ใน Clean Architecture
การยึดมั่นใน DIP ด้วย PostgreSQL ช่วยให้ระบบของเราได้รับประโยชน์หลักๆ คือ:
- Testability: เราสามารถ Mock (จำลอง) การทำงานของ `get_user_data_by_id` ได้ง่ายๆ ใน Unit Test โดยไม่ต้องเชื่อมต่อกับฐานข้อมูลจริง
- Maintainability: หากเราเปลี่ยนจาก PostgreSQL ไปใช้ฐานข้อมูลอื่น (เช่น CockroachDB) เราเพียงแค่เปลี่ยน Implementation ของ Abstraction นั้นๆ โดยที่ Business Logic ไม่ต้องเปลี่ยนแปลงเลย
- Flexibility: ช่วยให้เราสามารถเพิ่ม Use Case ใหม่ๆ ได้โดยไม่กระทบต่อโค้ดเดิม (Open/Closed Principle)
บทสรุป
การนำ Dependency Inversion Principle มาใช้ในการออกแบบระบบที่ใช้ PostgreSQL ไม่ใช่แค่การเขียนโค้ด แต่คือการออกแบบสถาปัตยกรรมที่คำนึงถึงการแยกความรับผิดชอบ (Separation of Concerns) อย่างเคร่งครัด การใช้ Functions หรือ Schema Abstraction ใน PostgreSQL อย่างชาญฉลาด จะช่วยให้เราสร้างระบบที่แข็งแกร่ง ยืดหยุ่น และพร้อมรับการเปลี่ยนแปลงทางธุรกิจในอนาคตได้อย่างแท้จริง