Blog

  • การ Print Debug ใน Flutter

    การ Print Debug ใน Flutter

    Dart แนะนำว่า เราไม่ควรใช้ฟังชั่น Print ใน flutter production code

    วิธีการที่ถูกต้องคือ ให้ใช้ debugPrint แทน และต้องตรวจสอบด้วย kDebugMode ด้วย

    Code ตัวอย่างเป็นแบบนี้

    FilledButton(
                  onPressed: () {
                    if (kDebugMode) {
                      debugPrint('This is filled button');
                    }
                  },
                  child: Text('This is filled button'),
                ),

    เมื่อ run โปรแกรม จะพิมพ์ข้อความ debug ใน console ดังนี้

  • ตอนที่ 3: FlutterFlow เหมาะกับใคร

    ตอนที่ 3: FlutterFlow เหมาะกับใคร

    บทนี้คือ ด่านตัดสินใจ สำหรับคนที่อ่านมาถึงตรงนี้และเริ่มถามตัวเองจริง ๆ ว่า

    “สรุปแล้ว FlutterFlow เหมาะกับเราหรือเปล่า”

    ถ้าคุณอยู่ในช่วงจะเลือกเครื่องมือ พลาดบทนี้ไปอาจเลือกผิดทางได้ง่าย ๆ


    FlutterFlow เหมาะกับมือใหม่ไหม

    คำตอบคือ เหมาะ แต่ต้องเข้าใจขอบเขต

    FlutterFlow ช่วยลดกำแพงสำหรับมือใหม่ได้มาก เพราะ

    • ไม่ต้องเริ่มจากการเขียนโค้ดทั้งหมด
    • เห็น UI และ flow ของแอปทันที
    • เข้าใจโครงสร้างแอปได้ง่ายกว่าการอ่านโค้ดล้วน

    อย่างไรก็ตาม มือใหม่ควรเข้าใจว่า

    • FlutterFlow ไม่ได้แทนความรู้พื้นฐานทั้งหมด
    • ถ้าไม่เข้าใจ concept อย่าง state, data flow, backend เลย จะเริ่มตันเร็ว

    สรุปคือ FlutterFlow เหมาะกับมือใหม่ที่อยากเรียนรู้การทำแอปเชิงระบบ มากกว่ามือใหม่ที่อยากหลีกเลี่ยงเทคนิคทั้งหมด


    FlutterFlow เหมาะกับ startup หรือไม่

    คำตอบคือ เหมาะมาก โดยเฉพาะช่วงเริ่มต้น

    Startup ส่วนใหญ่มักมีข้อจำกัดเรื่องเวลา ทีม และงบประมาณ FlutterFlow ตอบโจทย์ตรงนี้ได้ดี เพราะ

    • สร้าง MVP ได้เร็ว
    • ปรับแก้ตาม feedback ได้ไว
    • ใช้ทีมเล็กหรือ solo founder ได้
    • Demo ให้ลูกค้า นักลงทุน หรือ partner ได้ทันที

    FlutterFlow เหมาะกับ startup ในช่วง

    • Idea validation
    • Pre-seed / Seed
    • ทดลอง product–market fit

    แต่เมื่อธุรกิจเริ่มโต ควรวางแผนเรื่องการ export code และคุม architecture ต่อด้วย Flutter ปกติ


    FlutterFlow เหมาะกับ dev ระดับไหน

    FlutterFlow ไม่ได้เหมาะแค่คนไม่เขียนโค้ด แต่ dev ก็ได้ประโยชน์มาก หากใช้ถูกจุด

    Junior Developer

    • เข้าใจ flow ของแอปได้เร็ว
    • ลดเวลางงกับ UI boilerplate
    • โฟกัสที่ logic และ data มากขึ้น

    Mid-level Developer

    • ใช้ FlutterFlow เร่งงาน UI
    • ทำ MVP หรือ internal tool ได้เร็ว
    • export code แล้ว refactor ต่อได้

    Senior Developer

    • ใช้เป็นเครื่องมือ prototyping
    • ลดเวลางานซ้ำ ๆ
    • ไม่เหมาะเป็น core tool ระยะยาวโดยไม่ควบคุม code

    สรุปคือ ยิ่ง dev เข้าใจ Flutter มากเท่าไร ยิ่งใช้ FlutterFlow ได้คุ้มขึ้น


    ใคร “ไม่ควร” ใช้ FlutterFlow

    FlutterFlow ไม่ได้เหมาะกับทุกสถานการณ์ กลุ่มที่ควรหลีกเลี่ยง ได้แก่

    • โปรเจกต์ที่มี business logic ซับซ้อนมาก
    • ระบบที่ต้อง optimize performance ขั้นสูง
    • แอปที่ต้อง custom animation ลึก ๆ
    • Enterprise system ขนาดใหญ่
    • ทีมที่ไม่ต้องการพึ่งเครื่องมือ third-party เลย

    ในกรณีเหล่านี้ การเขียน Flutter ปกติจะให้ความยืดหยุ่นและควบคุมได้ดีกว่า


    สรุปการเลือกใช้ FlutterFlow

    ให้ถามตัวเองง่าย ๆ ก่อนตัดสินใจ

    • ต้องการความเร็วมากกว่าความยืดหยุ่นหรือไม่
    • กำลังทำ MVP หรือโปรเจกต์ระยะสั้น–กลางหรือไม่
    • พร้อม export code และพัฒนาต่อหรือไม่

    ถ้าคำตอบส่วนใหญ่คือ “ใช่” → FlutterFlow คือทางเลือกที่เหมาะมาก

    ถ้าต้องการควบคุมทุกอย่างตั้งแต่วันแรก → Flutter ปกติอาจเหมาะกว่า


    บทถัดไป เราจะลงลึกเรื่อง ข้อดี–ข้อเสียของ FlutterFlow แบบไม่อวย เพื่อช่วยตัดสินใจขั้นสุดท้าย

    ทดลองใช้ flutterflow -> www.flutterflow.io

  • ตอนที่ 2: FlutterFlow ใช้ทำอะไรได้บ้าง

    ตอนที่ 2: FlutterFlow ใช้ทำอะไรได้บ้าง

    บทความตอนนี้เหมาะสำหรับคนที่กำลังถามตัวเองว่า FlutterFlow เอาไปใช้ทำงานจริงได้แค่ไหน เหมาะกับโปรเจกต์แบบใด และควรหรือไม่ควรใช้ในสถานการณ์ไหน

    ถ้าคุณกำลังจะทำแอป ทำ MVP หรือกำลังมองหาทางลัดในการพัฒนา บทนี้จะช่วยให้ตัดสินใจได้ชัดขึ้น


    FlutterFlow ใช้ทำแอปแบบไหนได้บ้าง

    FlutterFlow เหมาะกับแอปที่มีโครงสร้างค่อนข้างชัดเจน เน้นการแสดงผลข้อมูล การจัดการฟอร์ม และการเชื่อมต่อ backend ผ่าน Firebase หรือ API

    ประเภทแอปที่ FlutterFlow ทำได้ดี ได้แก่

    • แอปข้อมูล (Data-driven App)
    • แอปที่มีระบบสมาชิก / Login
    • แอปฟอร์ม กรอกข้อมูล สมัคร จองคิว
    • แอป Content เช่น บทความ ข่าว คอร์ส
    • แอปภายในองค์กร (Internal Tool)
    • แอป Prototype หรือ Demo
    flutter flow template
    Flutter flow มี template ให้เลือกใช้มากมาย ทั้งแบบฟรี และมีค่าใช้จ่าย ทำให้เราเริ่มต้นสร้างแอปและเว็บต่างๆได้อย่างง่ายดาย

    แนวคิดสำคัญคือ FlutterFlow เหมาะกับแอปที่ logic ไม่ซับซ้อนเชิง algorithm แต่มีหลายหน้าจอและ flow การใช้งานชัดเจน


    ตัวอย่างแอปที่เหมาะกับ FlutterFlow

    ตัวอย่างการใช้งาน FlutterFlow ในงานจริงที่พบได้บ่อย ได้แก่

    • แอปจองคิวร้านอาหาร คลินิก โรงพยาบาล
    • แอป To-do / Task Management
    • แอปคอร์สออนไลน์ หรือ Learning Platform
    • แอป Community / Member Area
    • แอป Dashboard ดึงข้อมูลจาก API
    • แอป E-commerce ขนาดเล็กถึงกลาง

    แอปกลุ่มนี้มีจุดร่วมคือ ต้องการพัฒนาเร็ว ปรับ UI บ่อย และไม่ต้องการเขียน logic ลึกมากในช่วงแรก

    flutter flow new project with template
    ตอนสร้าง Project ใหม่ มี template ให้เลือกมากมาย ทำให้เราไม่ต้องเริ่มต้นจากศูนย์

    FlutterFlow ใช้ทำ MVP ได้ไหม

    คำตอบคือ ได้ และเป็นหนึ่งในจุดแข็งที่สุดของ FlutterFlow

    FlutterFlow ถูกออกแบบมาให้เหมาะกับการสร้าง MVP (Minimum Viable Product) โดยเฉพาะ เพราะช่วยลดเวลาและต้นทุนในการพัฒนาอย่างมาก

    ข้อดีของการใช้ FlutterFlow ทำ MVP ได้แก่

    • สร้างแอปใช้งานได้จริงในเวลาสั้น
    • ปรับ UX/UI ได้เร็วจาก feedback ผู้ใช้
    • เชื่อม Firebase หรือ API ได้ทันที
    • สามารถนำไปทดสอบกับผู้ใช้จริงหรือเสนอ Demo ได้

    หลายทีมใช้ FlutterFlow เพื่อทดสอบไอเดียธุรกิจ ก่อนตัดสินใจลงทุนเขียน Flutter เต็มรูปแบบในระยะถัดไป


    FlutterFlow ใช้ทำเว็บได้หรือไม่

    FlutterFlow สามารถสร้าง Web App ได้ผ่าน Flutter Web โดยตรง

    เหมาะสำหรับการทำ

    • เว็บ Dashboard
    • เว็บระบบหลังบ้าน (Admin Panel)
    • เว็บ MVP สำหรับทดลองตลาด

    อย่างไรก็ตาม Flutter Web จาก FlutterFlow มีข้อจำกัดบางประการ เช่น

    • ไม่เหมาะกับเว็บที่เน้น SEO หนัก ๆ
    • Performance อาจไม่เท่าเว็บที่เขียนด้วย Framework ฝั่งเว็บโดยตรง

    ดังนั้น FlutterFlow เหมาะกับเว็บเชิงระบบมากกว่าเว็บบทความหรือเว็บ Content ขนาดใหญ่


    ข้อจำกัดด้านฟีเจอร์

    แม้ FlutterFlow จะช่วยให้พัฒนาแอปได้เร็วมาก แต่ก็มีข้อจำกัดที่ควรรู้ก่อนใช้งานจริง

    • การเขียน business logic ซับซ้อนทำได้ยาก
    • Custom animation หรือ interaction ขั้นลึกยังจำกัด
    • การจัดการ state ซับซ้อนอาจเริ่มลำบากเมื่อแอปขยายใหญ่
    • โครงสร้างแอปอาจไม่เหมาะกับการ scale ระยะยาว หากไม่ export code

    แนวทางที่นิยมคือ

    ใช้ FlutterFlow ทำ MVP หรือเวอร์ชันแรก → export code → พัฒนาต่อด้วย Flutter ปกติ


    สรุปบทที่ 2

    FlutterFlow ไม่ใช่เครื่องมือที่เหมาะกับทุกโปรเจกต์ แต่เหมาะมากกับงานที่ต้องการ ความเร็ว ความยืดหยุ่นในช่วงเริ่มต้น และการทดลองตลาด

    ถ้าคุณกำลังมองหาเครื่องมือสำหรับทำ MVP หรือแอปที่ logic ไม่ซับซ้อน FlutterFlow คือหนึ่งในตัวเลือกที่คุ้มค่าที่สุดในตอนนี้

    External link

    flutterflow.io

  • FlutterFlow คืออะไร? แพลตฟอร์มสร้างแอป Flutter แบบไม่ต้องเขียนโค้ดทั้งหมด

    FlutterFlow คืออะไร? แพลตฟอร์มสร้างแอป Flutter แบบไม่ต้องเขียนโค้ดทั้งหมด

    FlutterFlow คืออะไร

    FlutterFlow คือเครื่องมือ Visual App Builder สำหรับสร้างแอปด้วย Flutter Framework โดยใช้แนวคิดแบบ Low-Code / No-Code ผู้ใช้สามารถออกแบบหน้าจอ วางโครงสร้างแอป เชื่อมต่อฐานข้อมูล และตั้งค่า logic ได้ผ่านหน้าเว็บ โดยไม่จำเป็นต้องเขียนโค้ดทั้งหมดตั้งแต่ต้น

    แอปที่สร้างจาก FlutterFlow ใช้ Flutter จริง และสามารถ export ออกมาเป็น Flutter Source Code เพื่อนำไปพัฒนาต่อได้


    FlutterFlow ทำงานยังไง

    FlutterFlow ทำงานโดยแบ่งการพัฒนาแอปออกเป็นส่วนสำคัญดังนี้

    1. UI Builder

    ผู้ใช้สามารถออกแบบหน้าจอแอปด้วยการลากวาง Widget ซึ่งอิงจาก Flutter Widget จริง รองรับ Responsive Design และเห็นผลลัพธ์ใกล้เคียงของจริงแบบเรียลไทม์

    2. Logic & Action

    สามารถตั้งค่า Action ต่าง ๆ ได้โดยไม่ต้องเขียนโค้ด เช่น การเปลี่ยนหน้า การเรียก API การบันทึกข้อมูล รวมถึงรองรับ Custom Function สำหรับเขียน Dart เพิ่มในจุดที่จำเป็น

    3. Backend Integration

    FlutterFlow รองรับการเชื่อมต่อ Firebase เช่น Authentication, Firestore และ Storage รวมถึงการเรียก REST API และการจัดการ State ภายในแอป

    4. Build & Export

    ผู้ใช้สามารถ Preview แอปได้ทันที และ export ออกมาเป็น Flutter Code หรือ build เป็นแอปสำหรับ iOS, Android และ Web ได้ (แต่จะต้องมีการ subscribe เสียก่อน โดยใช้การ export ได้ตั้งแต่ basic plan เป็นต้นไป)


    FlutterFlow ต่างจาก Flutter ยังไง

    Flutter เป็น Framework สำหรับพัฒนาแอปที่ต้องเขียนโค้ดเองทั้งหมด ในขณะที่ FlutterFlow เป็นเครื่องมือที่ช่วยลดขั้นตอนการเขียนโค้ด โดยเน้นการพัฒนาแบบ Visual

    Flutter เหมาะกับโปรเจกต์ที่ต้องการควบคุมรายละเอียดเชิงลึกและ performance สูง ส่วน FlutterFlow เหมาะกับการพัฒนาแอปอย่างรวดเร็ว โดยเฉพาะในช่วงเริ่มต้นหรือทำ MVP


    FlutterFlow เหมาะกับใคร

    FlutterFlow เหมาะกับกลุ่มผู้ใช้งานดังต่อไปนี้

    • Startup ที่ต้องการสร้าง MVP อย่างรวดเร็ว
    • Solo Founder หรือ Indie Developer
    • Designer ที่ต้องการสร้างแอปด้วยตัวเอง
    • Developer ที่ต้องการลดเวลาการทำ UI
    • ผู้ที่มีพื้นฐาน Flutter/Dart เล็กน้อยและต้องการเพิ่มความเร็วในการพัฒนา

    ไม่เหมาะกับโปรเจกต์ที่มี logic ซับซ้อนมาก ต้องการ custom animation ขั้นสูง หรือระบบ enterprise ขนาดใหญ่


    ข้อดีของ FlutterFlow

    • พัฒนาแอปได้รวดเร็วมาก
    • เห็นภาพ UI ชัดเจนตั้งแต่ต้น
    • ใช้ Flutter Framework จริง
    • เชื่อมต่อ Firebase ได้ง่าย
    • ลด Learning Curve สำหรับผู้เริ่มต้น

    ข้อจำกัดที่ควรรู้

    • การเขียน business logic ซับซ้อนทำได้ยากกว่า Flutter ปกติ
    • โค้ดที่ export ออกมาอาจต้อง refactor เพิ่ม
    • มีความเสี่ยงเรื่อง vendor lock-in หากไม่ export code
    • การปรับแต่ง UI และ animation ขั้นลึกยังมีข้อจำกัด

    FAQ: คำถามที่พบบ่อยเกี่ยวกับ FlutterFlow

    FlutterFlow ใช้แทน Flutter ได้ไหม

    ไม่สามารถแทนได้ทั้งหมด FlutterFlow เหมาะกับการเริ่มต้นและทำ MVP ส่วน Flutter เหมาะกับงานที่ต้องการควบคุมเต็มรูปแบบ

    FlutterFlow ฟรีหรือไม่

    มีแผนฟรี แต่การ export code และ feature ขั้นสูงจำเป็นต้องใช้แผนแบบชำระเงิน

    แอปจาก FlutterFlow สามารถขึ้น Store ได้หรือไม่

    สามารถเผยแพร่ได้ทั้ง App Store และ Google Play

    คนไม่เขียนโค้ดสามารถใช้ได้ไหม

    สามารถใช้ได้ในระดับหนึ่ง แต่ถ้ามีพื้นฐาน Flutter หรือ Dart จะใช้งานได้มีประสิทธิภาพมากขึ้น

    FlutterFlow เหมาะกับโปรเจกต์ระยะยาวหรือไม่

    เหมาะหากมีการวางแผน export code และดูแล architecture ต่อด้วย Flutter ปกติ

    ลิงค์เข้าใช้งานไปลองตำกันเลยครับ

    FlutterFlow : https://www.flutterflow.io/

  • ตอนที่ 10: Layered, Clean และ Hexagonal Architecture – โครงสร้างที่พา DDD ไปใช้ได้จริง

    ตอนที่ 10: Layered, Clean และ Hexagonal Architecture – โครงสร้างที่พา DDD ไปใช้ได้จริง

    บทนำ

    เมื่อคุณเข้าใจ Domain-Driven Design ครบทั้ง Entity, Aggregate, Domain Service, Application Service, Repository และ Domain Event แล้ว

    คำถามถัดไปที่เลี่ยงไม่ได้คือ:

    แล้วเราควรจัดโครงสร้างระบบ (Architecture) แบบไหน ถึงจะทำให้ DDD ใช้งานได้จริงในระยะยาว?

    บทความตอนนี้จะพาคุณทำความเข้าใจความสัมพันธ์ระหว่าง DDD กับสถาปัตยกรรมยอดนิยม 3 แบบ:

    • Layered Architecture
    • Clean Architecture
    • Hexagonal Architecture

    โดยอธิบายผ่านมุมมอง ระบบธุรกิจ / ระบบพนักงาน เช่นเดิม


    DDD ไม่ใช่ Architecture แต่ต้องพึ่ง Architecture

    สิ่งสำคัญที่ต้องเข้าใจก่อนคือ:

    • DDD ไม่ใช่ framework
    • DDD ไม่ใช่ architecture
    • DDD คือ แนวคิดในการออกแบบ Domain

    แต่ถ้าไม่มี architecture ที่เหมาะสม:

    • Domain จะโดนเทคโนโลยีรุกล้ำ
    • Business logic จะรั่วออกไปทุก layer
    • DDD จะเหลือแค่ชื่อ

    Layered Architecture – จุดเริ่มต้นที่คุ้นเคย

    Layered Architecture แบ่งระบบออกเป็นชั้น ๆ เช่น:

    Presentation
    Application
    Domain
    Infrastructure

    ข้อดี

    • เข้าใจง่าย
    • เหมาะกับทีมที่เริ่มใช้ DDD
    • Mapping กับ DDD ได้ตรงไปตรงมา

    ข้อจำกัด

    • Dependency มักไหลผิดทิศ
    • Domain เสี่ยงผูกกับ framework
    • Test Domain แยกยากถ้า discipline ไม่ดี

    Layered ใช้ได้ แต่ต้อง “เคร่ง” เรื่อง dependency


    Clean Architecture – ปกป้อง Domain เป็นศูนย์กลาง

    Clean Architecture วาง Domain และ Use Case ไว้ตรงกลาง

    หลักการสำคัญ:

    • Dependency ต้องชี้เข้าใน
    • Domain ไม่รู้จักโลกภายนอก
    • Framework เป็น detail

    โครงสร้างเชิงแนวคิด:

    Entities
    Use Cases
    Interface Adapters
    Frameworks & Drivers

    เหมาะกับ DDD อย่างไร

    • Domain สะอาด
    • Test ง่าย
    • เปลี่ยน UI / DB ได้โดยไม่กระทบ Domain

    ข้อแลกเปลี่ยนคือ:

    • โครงสร้างซับซ้อนขึ้น
    • ต้องเข้าใจ abstraction ดี

    Hexagonal Architecture – โลกภายนอกเข้ามาทาง Port

    Hexagonal Architecture (Ports & Adapters) มองระบบเป็นแกนกลางที่ถูกล้อมด้วย adapter

    แนวคิดหลัก:

    • Domain อยู่ตรงกลาง
    • ติดต่อโลกภายนอกผ่าน Port
    • Adapter เปลี่ยนได้โดยไม่กระทบ Domain
    UI Adapter → Port → Application / Domain ← Port ← DB Adapter

    ข้อดี

    • แยก concern ชัดมาก
    • เหมาะกับระบบที่มี integration เยอะ
    • รองรับ event-driven architecture ได้ดี

    ข้อจำกัด

    • Conceptual overhead สูง
    • ไม่เหมาะกับระบบเล็กมาก

    แล้วควรเลือก Architecture แบบไหน

    คำตอบคือ: ไม่มีแบบไหนดีที่สุดเสมอไป

    แนวทางแนะนำ:

    • ระบบเล็ก / ทีมใหม่ → Layered (แต่คุม dependency)
    • ระบบธุรกิจจริง / scale ได้ → Clean หรือ Hexagonal
    • ระบบที่ event-driven / integration หนัก → Hexagonal

    สิ่งสำคัญไม่ใช่ชื่อ Architecture แต่คือการปกป้อง Domain


    สรุป

    • DDD ต้องการ Architecture ที่ปกป้อง Domain
    • Layered, Clean และ Hexagonal ล้วนใช้กับ DDD ได้
    • เลือกให้เหมาะกับบริบททีมและระบบ
    • ถ้า Domain แข็งแรง Architecture จะเป็นพลัง ไม่ใช่ภาระ

    ด้วยตอนที่ 10 นี้ แกนหลักของ DDD series ถือว่าครบถ้วนแล้ว

    ถัดจากนี้ คุณสามารถต่อยอดไปสู่ DDD in Practice เช่น:

    • Transaction & Consistency Boundary
    • Eventual Consistency
    • Refactoring Legacy System ด้วย DDD

    SEO Meta (สำหรับ Yoast)

    Focus Keyphrase: DDD Architecture

    Meta Description:

    Layered, Clean และ Hexagonal Architecture ต่างกันอย่างไร และแบบไหนเหมาะกับ Domain-Driven Design บทความนี้อธิบายการเลือก architecture เพื่อปกป้อง business logic และทำให้ DDD ใช้งานได้จริงในระบบธุรกิจ

  • ตอนที่ 9: Domain Event – เมื่อระบบธุรกิจขับเคลื่อนด้วยเหตุการณ์

    ตอนที่ 9: Domain Event – เมื่อระบบธุรกิจขับเคลื่อนด้วยเหตุการณ์

    บทนำ

    ในระบบธุรกิจจริง หลายสิ่งไม่ได้เกิดขึ้นเพราะ “มีคนสั่ง” เสมอไป แต่เกิดขึ้นเพราะ เหตุการณ์บางอย่างได้เกิดขึ้นแล้ว

    เช่น:

    • พนักงานผ่านทดลองงาน
    • พนักงานลาออก
    • เงินเดือนถูกปรับ
    • แผนกถูกยุบ

    เหตุการณ์เหล่านี้คือหัวใจของแนวคิดที่เรียกว่า Domain Event ใน Domain-Driven Design (DDD)


    Domain Event คืออะไร

    Domain Event คือ object ที่ใช้แทน “เหตุการณ์สำคัญทางธุรกิจ” ที่ได้เกิดขึ้นแล้วใน Domain

    คุณสมบัติสำคัญ:

    • เป็นเหตุการณ์ในอดีต (past tense)
    • มีความหมายทางธุรกิจชัดเจน
    • เกิดจาก Domain Model ไม่ใช่ UI

    ตัวอย่าง Domain Event:

    • EmployeePassedProbation
    • EmployeeSalaryAdjusted
    • EmployeeResigned

    ทำไม Domain Event ถึงสำคัญ

    หากไม่มี Domain Event:

    • ระบบจะ tightly coupled
    • Logic จะกระจุกอยู่ที่ Use Case
    • Feature ใหม่เพิ่มยาก

    Domain Event ช่วยให้:

    • ระบบขยายได้โดยไม่ต้องแก้โค้ดเดิม
    • แยกผลกระทบออกจากต้นเหตุ
    • Domain สื่อสารสิ่งที่เกิดขึ้นได้ชัดเจน

    ธุรกิจคิดเป็น “เหตุการณ์” ไม่ใช่ “ฟังก์ชัน”


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

    เหตุการณ์: พนักงานผ่านทดลองงาน

    เมื่อเหตุการณ์นี้เกิดขึ้น:

    • เปลี่ยนสถานะพนักงานเป็น permanent
    • แจ้งฝ่าย payroll
    • ส่งอีเมลแจ้ง HR
    • เปิดสิทธิประโยชน์ใหม่

    แทนที่จะเขียนทั้งหมดใน Use Case เดียว

    Domain Model จะ:

    • สร้าง Domain Event: EmployeePassedProbation

    ส่วนระบบอื่นจะ:

    • subscribe เหตุการณ์นี้ไปจัดการงานของตัวเอง

    Domain Event ทำงานร่วมกับ Aggregate อย่างไร

    Domain Event:

    • ถูกสร้างภายใน Aggregate
    • สะท้อนการเปลี่ยนแปลง state ที่สำคัญ
    • ไม่ควรรู้ว่าใครจะรับไปใช้

    ตัวอย่างเชิงแนวคิด:

    Employee Aggregate
      └─ changeStatus()
            └─ raise EmployeePassedProbation event

    Domain Event vs Application Event

    หัวข้อDomain EventApplication / Integration Event
    แหล่งที่มาDomain ModelApplication / Infra
    ความหมายธุรกิจเทคนิค / integration
    ภาษาภาษา Domainภาษาระบบ

    Domain Event ต้องใช้ Ubiquitous Language เสมอ


    Domain Event ควรถูก handle ที่ไหน

    โดยทั่วไป:

    • Aggregate → สร้าง event
    • Application Service → publish event
    • Event Handler → ทำงานต่อ

    Event Handler:

    • ส่ง email
    • เรียก external system
    • update read model

    Domain Model ไม่ควรรู้จัก event handler


    ข้อควรระวังในการใช้ Domain Event

    • อย่าใช้กับทุกการเปลี่ยนแปลงเล็ก ๆ
    • ใช้เฉพาะเหตุการณ์ที่ธุรกิจ “สนใจจริง”
    • อย่าใส่ logic หนักใน event handler

    Domain Event ที่ดี:

    • เล็ก
    • ชัด
    • สื่อความหมายธุรกิจ

    สรุป

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

    ตอนถัดไป เราจะเชื่อมทุกอย่างเข้าด้วยกันด้วย Architecture Patterns (Layered, Clean, Hexagonal) เพื่อปิดแกนหลักของ DDD


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

    ตอนที่ 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 ได้จริง

  • ตอนที่ 7: Application Service / Use Case – ตัวกลางระหว่างโลกธุรกิจกับโลกเทคนิค

    ตอนที่ 7: Application Service / Use Case – ตัวกลางระหว่างโลกธุรกิจกับโลกเทคนิค

    บทนำ

    หลังจากตอนที่ 6 เราได้รู้จัก Domain Service ซึ่งเป็นที่อยู่ของ business logic ที่ไม่ควรผูกกับ Entity ใดโดยตรง

    คำถามถัดมาที่มักจะตามมาคือ:

    แล้วโค้ดที่รับ request จาก UI, เรียก Domain Service, ใช้ Repository และจัดการ transaction ควรอยู่ที่ไหน?

    คำตอบคือ Application Service (หรือที่หลายทีมเรียกว่า Use Case)


    Application Service คืออะไร

    Application Service คือชั้นที่ทำหน้าที่:

    • รับคำสั่งจากภายนอก (UI, API, Controller)
    • ประสานงานระหว่าง Domain Objects
    • ควบคุม flow ของ use case หนึ่ง ๆ
    • จัดการ transaction, permission, orchestration

    ❗ Application Service ไม่ใช่ ที่อยู่ของ business rule เชิงลึก

    มันคือ “ผู้จัดการกระบวนการ” ไม่ใช่ “ผู้ตัดสินกฎธุรกิจ”


    เปรียบเทียบง่าย ๆ ด้วยระบบพนักงาน

    สมมติ use case: ปรับเงินเดือนพนักงาน

    สิ่งที่ Application Service ทำ:

    1. รับคำสั่งปรับเงินเดือนจาก UI
    2. โหลด Employee Aggregate จาก Repository
    3. เรียก Domain Service เพื่อตรวจสอบกฎธุรกิจ
    4. สั่งให้ Aggregate เปลี่ยนสถานะ
    5. บันทึกผลลัพธ์กลับ Repository

    สิ่งที่ Application Service ไม่ควรทำ:

    • คำนวณสูตรเงินเดือนเอง
    • ตรวจสอบ policy เชิงลึกของบริษัท
    • เขียน if/else ธุรกิจยาว ๆ

    ตัวอย่างโครงสร้าง (เชิงแนวคิด)

    UI / API
       ↓
    Application Service (Use Case)
       ↓
    Domain Model (Entity, Value Object, Domain Service)
       ↓
    Repository

    Application Service คือสะพานเชื่อมโลกภายนอกกับ Domain


    ตัวอย่างเชิงโค้ด (pseudo code)

    class AdjustSalaryUseCase {
      execute(command) {
        employee = employeeRepository.getById(command.employeeId)
    
        salaryPolicyService.validate(employee, command.newSalary)
    
        employee.adjustSalary(command.newSalary)
    
        employeeRepository.save(employee)
      }
    }

    สังเกตว่า:

    • ไม่มี logic ธุรกิจซับซ้อนอยู่ใน Use Case
    • Business rule อยู่ใน Domain
    • Use Case ทำหน้าที่เรียงลำดับขั้นตอนเท่านั้น

    Application Service vs Domain Service

    หัวข้อApplication ServiceDomain Service
    โฟกัสFlow / Use caseBusiness rule
    รู้จัก UIรู้ไม่รู้
    รู้จัก Persistenceรู้ไม่รู้
    Statelessส่วนใหญ่ใช่ใช่

    ถ้า logic นั้นเปลี่ยนเพราะ ขั้นตอนทำงานเปลี่ยน → Application Service

    ถ้า logic นั้นเปลี่ยนเพราะ กฎธุรกิจเปลี่ยน → Domain Service


    ทำไม Application Service ถึงสำคัญมาก

    ถ้าไม่มี Application Service:

    • Controller จะอ้วน
    • Business logic กระจัดกระจาย
    • Test ยาก
    • Domain ถูกใช้ผิดวิธี

    Application Service ช่วยให้:

    • Use case ชัดเจน
    • อ่านโค้ดแล้วรู้ว่า “ระบบทำอะไรได้บ้าง”
    • Domain สะอาดและคงทนต่อการเปลี่ยนแปลง

    สรุป

    • Application Service คือ ผู้ควบคุม flow ของระบบ
    • ไม่ใช่ที่อยู่ของ business rule
    • เป็นสะพานเชื่อม UI กับ Domain
    • ทำให้ระบบ scale ทางความซับซ้อนได้โดยไม่เละ

    ตอนนี้ Domain ของคุณเริ่มแข็งแรงแล้ว

    ตอนถัดไป เราจะลงลึกเรื่อง Repository – มุมมองแบบ DDD vs CRUD ซึ่งเป็นอีกจุดที่หลายทีมเข้าใจผิดมาก

  • Domain Service – เมื่อ logic ไม่ควรอยู่ใน Entity

    Domain Service – เมื่อ logic ไม่ควรอยู่ใน Entity

    ตอนที่ 6 ของซีรีส์ Domain-Driven Design ฉบับระบบธุรกิจจริง

    Theme หลัก: ระบบบริหารพนักงาน (Staff / Employee Management System)

    ในตอนที่ 5 เราใช้ Aggregate เพื่อกำหนดขอบเขตและปกป้อง invariant ของ domain

    แต่เมื่อเริ่มออกแบบจริง คุณจะเจอสถานการณ์แบบนี้:

    logic นี้เป็นกฎของธุรกิจแน่ ๆ … แต่ไม่รู้จะใส่ไว้ใน entity ตัวไหนดี

    นี่คือจุดที่ Domain Service เข้ามามีบทบาท


    ปัญหาที่เจอบ่อยในระบบพนักงาน

    ลองดู use case ต่อไปนี้:

    • พนักงานขอเปลี่ยนกะ
    • ระบบต้องตรวจสอบว่า
      • ไม่ชนกับกะอื่นของพนักงาน
      • ไม่ชนกับกะที่ได้รับอนุมัติแล้ว
      • ไม่เกินนโยบายที่ HR กำหนด

    คำถามคือ:

    • logic นี้ควรอยู่ใน ShiftRequest?
    • หรืออยู่ใน Staff?

    คำตอบคือ: ไม่ชัดเจนทั้งคู่


    ความเข้าใจผิดเกี่ยวกับ Service

    ในระบบทั่วไป เรามักเห็น:

    • ShiftService
    • StaffService
    • RequestService

    ที่ภายในเต็มไปด้วย if-else

    DDD แยก Service ออกเป็น 3 ประเภท:

    1. Application Service (Use Case)
    2. Domain Service
    3. Infrastructure Service

    ตอนนี้เราจะโฟกัสที่ข้อ 2


    Domain Service คืออะไร

    Domain Service คือ:

    class ที่รวม logic ทางธุรกิจ

    ซึ่ง ไม่เป็นเจ้าของข้อมูลเอง

    และ ไม่เหมาะจะอยู่ใน entity ใด entity หนึ่ง

    คุณสมบัติสำคัญ:

    • อยู่ใน layer ของ domain
    • ใช้ภาษาเดียวกับธุรกิจ (Ubiquitous Language)
    • ไม่มี state ระยะยาว

    ตัวอย่าง Domain Service: ShiftPolicy

    class ShiftPolicy {
      bool canRequestShift(
        Staff staff,
        WorkingPeriod period,
        List<ShiftRequest> existingRequests,
      ) {
        if (staff.status != StaffStatus.active) return false;
    
        for (final request in existingRequests) {
          if (request.period.overlaps(period)) {
            return false;
          }
        }
    
        return true;
      }
    }

    จุดสำคัญ:

    • ไม่เก็บข้อมูลเอง
    • รับทุกอย่างผ่าน parameter
    • สื่อความหมายเชิงธุรกิจ

    Domain Service ไม่ใช่ Utility

    ข้อผิดพลาดที่พบบ่อยคือ:

    class DateUtils {
      static bool overlap(DateTime a, DateTime b) {}
    }

    นี่คือ Technical Utility

    แต่ Domain Service:

    • ต้องสะท้อนกฎของธุรกิจ
    • ชื่อบอก intent ชัดเจน

    ShiftPolicy ดีกว่า ShiftHelper


    Domain Service ทำงานร่วมกับ Aggregate

    Aggregate Root ยังคงเป็นผู้ตัดสินขั้นสุดท้าย

    ตัวอย่างใน ShiftRequest:

    class ShiftRequest {
      void request(
        Staff staff,
        WorkingPeriod period,
        ShiftPolicy policy,
        List<ShiftRequest> existing,
      ) {
        if (!policy.canRequestShift(staff, period, existing)) {
          throw Exception('Shift request not allowed');
        }
    
        // สร้าง request
      }
    }

    Policy ช่วยตัดสิน แต่ aggregate รับผิดชอบ invariant


    สัญญาณว่าคุณควรใช้ Domain Service

    คุณควรพิจารณา Domain Service เมื่อ:

    • logic ใช้หลาย entity
    • logic ไม่ belong กับ entity เดียว
    • การยัด logic ลง entity ทำให้มันอ้วนเกินไป

    แต่ถ้า logic เป็นพฤติกรรมของ entity โดยตรง:

    อย่ารีบใช้ Domain Service


    สิ่งที่ Domain Service ไม่ควรทำ

    • เรียก database
    • รู้จัก framework
    • มี side effect ภายนอก

    Domain Service ควร:

    • pure
    • test ง่าย
    • ย้ายได้โดยไม่กระทบ infrastructure

    สรุปตอนที่ 6

    • Domain Service = logic ธุรกิจที่ไม่มีตัวตน
    • ใช้เมื่อ entity ไม่เหมาะจะรับภาระนั้น
    • อย่าใช้แทน entity แบบพร่ำเพรื่อ

    ถ้า service ของคุณรู้จัก database

    นั่นไม่ใช่ Domain Service


    ตอนต่อไป

    ตอนที่ 7: Application Service / Use Case – หัวใจของการไหลของระบบ

    เราจะประกอบ domain ทั้งหมดเข้าด้วยกัน และดูว่า controller ควรบางแค่ไหน

  • Aggregate & Aggregate Root – กำแพงป้องกัน Domain ไม่ให้เละ

    Aggregate & Aggregate Root – กำแพงป้องกัน Domain ไม่ให้เละ

    ตอนที่ 5 ของซีรีส์ Domain-Driven Design ฉบับระบบธุรกิจจริง
    Theme หลัก: ระบบบริหารพนักงาน (Staff / Employee Management System)

    หลังจากตอนที่ 4 เราแยก Entity และ Value Object ได้แล้ว

    ขั้นต่อไปที่สำคัญไม่แพ้กันคือคำถามนี้:

    ใครมีสิทธิ์แก้ใครได้บ้าง?

    ถ้าไม่กำหนดขอบเขตให้ชัด Domain จะเริ่ม “เละ” แบบไม่รู้ตัว

    DDD ใช้แนวคิดนี้เพื่อแก้ปัญหา: Aggregate


    ปัญหาที่เจอบ่อยในระบบพนักงาน

    ลองดูสถานการณ์คุ้น ๆ:

    • หน้าจอหนึ่งแก้ ShiftRequest.status
    • อีกหน้าหนึ่งแก้ approvedBy
    • Batch job มาแก้ approvedAt

    ทุกอย่างเขียนถูก type

    แต่สุดท้ายเกิดคำถามว่า:

    • กฎยังครบไหม?
    • ใครเป็นคนรับผิดชอบ?
    • invariant ถูกทำลายไปหรือเปล่า?

    นี่คือสัญญาณว่า ยังไม่มี Aggregate


    Aggregate คืออะไร

    Aggregate คือ:

    กลุ่มของ Entity และ Value Object ที่ต้องถูกดูแลเป็นหน่วยเดียวกัน

    โดยมี Aggregate Root เป็นประตูทางเข้าเพียงทางเดียว

    หลักการสำคัญ:

    • แก้ข้อมูลภายใน aggregate ได้ ผ่าน root เท่านั้น
    • Root เป็นผู้ปกป้องกฎ (invariants)

    Aggregate Root คืออะไร

    Aggregate Root คือ Entity ตัวหลักที่:

    • มี identity
    • เป็นจุดเดียวที่ภายนอกเรียกใช้ได้
    • รับผิดชอบความถูกต้องของทั้ง aggregate

    ในระบบพนักงาน ตัวอย่าง Aggregate Root:

    • ShiftRequest
    • Staff

    ตัวอย่าง Aggregate: ShiftRequest

    มาดูโครงสร้างแบบง่าย:

    class ShiftRequest {
      final ShiftRequestId id;
      ShiftRequestStatus status;
      StaffId staffId;
      WorkingPeriod period;
      Approval approval;
    
      void approve(Staff approver) {
        if (status != ShiftRequestStatus.pending) {
          throw Exception('Only pending request can be approved');
        }
    
        approval = Approval.by(approver.id);
        status = ShiftRequestStatus.approved;
      }
    }
    

    Approval อาจเป็น Value Object ภายใน aggregate

    ภายนอก ไม่ควร ไปแก้ approval ตรง ๆ


    Invariant: กฎที่ห้ามถูกละเมิด

    Invariant คือกฎที่ต้องเป็นจริง เสมอ ภายใน aggregate

    ตัวอย่าง invariant ของ ShiftRequest:

    • request ที่ approved แล้ว ห้ามกลับเป็น pending
    • request หนึ่งรายการ อนุมัติได้เพียงครั้งเดียว
    • approver ต้องมีสิทธิ์ตามกฎธุรกิจ

    กฎเหล่านี้:

    ต้องถูกบังคับโดย Aggregate Root

    ไม่ใช่ controller หรือ service


    ทำไม “ห้ามข้าม Aggregate”

    ข้อผิดพลาดที่พบบ่อย:

    request.approval.approvedBy = approverId; // ❌
    

    โค้ดนี้:

    • ข้าม root
    • bypass กฎ
    • ทำลาย invariant

    ถ้าจำเป็นต้องเปลี่ยน:

    request.approve(approver); // ✅
    

    ขนาดของ Aggregate สำคัญมาก

    Aggregate ที่ดีควร:

    • เล็กที่สุดเท่าที่จำเป็น
    • ไม่ดึงทุกอย่างมารวมกัน

    ตัวอย่างที่ควรแยก:

    • Staff ไม่ควรเป็น aggregate เดียวกับ ShiftRequest
    • ใช้ StaffId อ้างอิงแทน object เต็ม

    เหตุผล:

    • performance
    • concurrency
    • ลด coupling

    Repository ทำงานกับ Aggregate

    Repository ควร:

    • load / save ทั้ง aggregate
    • ไม่ expose object ภายใน
    abstract class ShiftRequestRepository {
      ShiftRequest? findById(ShiftRequestId id);
      void save(ShiftRequest request);
    }
    

    Repository ไม่ควรมี method อย่าง:

    • updateApprovalStatus()
    • setApprovedBy()

    นั่นคือการรั่วของ domain


    สรุปตอนที่ 5

    • Aggregate = ขอบเขตของความถูกต้อง
    • Aggregate Root = ผู้เฝ้าประตู
    • Invariant ต้องอยู่ใน aggregate

    ถ้าคุณแก้ entity ไหนก็ได้จากที่ไหนก็ได้

    นั่นแปลว่า domain ของคุณยังไม่มีเจ้าของ


    ตอนต่อไป

    ตอนที่ 6: Domain Service – เมื่อ logic ไม่ควรอยู่ใน Entity

    เราจะดูกรณีที่ logic บางอย่างไม่เหมาะจะอยู่ใน entity แต่ก็ไม่ควรไปอยู่ใน service ทั่วไป