

Declarative vs Imperative — บอกคอมพิวเตอร์ว่า 'ทำยังไง' หรือ 'อยากได้อะไร'
ทำไมโค้ดบางอันสั่งทีละขั้น แต่บางอันบอกแค่ผลลัพธ์ที่อยากได้แล้วจบ — มาทำความเข้าใจสอง paradigm ที่คุณใช้อยู่ทุกวันโดยไม่รู้ตัว
ลองนึกภาพว่าคุณเขียนโค้ดวนลูปนับเลขทีละตัว สร้างตัวแปรเก็บผลรวม แล้วค่อย ๆ บวกเข้าไป — โค้ดยาวเหยียด แถมต้องคอยระวัง off-by-one error จนหัวหมุน
แล้ววันหนึ่งเพื่อนข้างโต๊ะเขียน SELECT SUM(amount) FROM orders บรรทัดเดียวจบ ได้ผลรวมเหมือนกัน แต่ไม่เห็นมีลูปสักตัว
ความต่างตรงนี้ไม่ใช่เรื่องภาษาไหนเก่งกว่า แต่เป็นวิธีคิดสองแบบที่อยู่เบื้องหลังโค้ดทุกบรรทัดที่เราเขียน — Imperative กับ Declarative
ถ้าเข้าใจสองคำนี้ คุณจะอ่านโค้ดของคนอื่นออกเร็วขึ้น และเลือกเครื่องมือให้เหมาะกับงานได้ดีขึ้น
🎯 แก่นความต่าง: HOW กับ WHAT#
วิธีจำที่ง่ายที่สุดคือ Imperative บอก “ทำยังไง” (HOW) ส่วน Declarative บอก “อยากได้อะไร” (WHAT)
Imperative programming คือการเขียนคำสั่งทีละขั้น ที่คอยเปลี่ยน state ของโปรแกรมไปเรื่อย ๆ — สร้างตัวแปร วนลูป เช็คเงื่อนไข อัปเดตค่า ทุกอย่างคุณต้องสั่งเองหมด
Declarative programming คือการบอกแค่ผลลัพธ์ที่ต้องการ แล้วปล่อยให้ภาษาหรือ framework จัดการรายละเอียด control flow ให้เอง
เปรียบเทียบให้เห็นภาพง่าย ๆ คือเรื่องอาหาร:
- Imperative = สูตรอาหาร บอกขั้นตอนทีละขั้น ตั้งไฟกี่นาที ใส่อะไรก่อนหลัง
- Declarative = สั่งอาหารจากเมนู บอกแค่ว่า “เอาผัดกะเพราหนึ่งจาน” ที่เหลือเป็นเรื่องของครัว
👀 ตัวอย่างที่เห็นภาพชัดที่สุด#
ลองดูโจทย์เดียวกัน: เอา array ของตัวเลขมา เลือกเฉพาะเลขคู่ คูณสอง แล้วหาผลรวม
แบบ Imperative ด้วย JavaScript จะเป็นแบบนี้ — สั่งทุกขั้นตอนเอง:
const numbers = [1, 2, 3, 4, 5, 6];
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
const doubled = numbers[i] * 2;
sum += doubled;
}
}javascriptแบบ Declarative ด้วย array methods จะเหลือแค่นี้ — บอกเป็นขั้น ๆ ว่าต้องการอะไร โดยไม่ต้องจัดการ index หรือตัวแปรสะสมเอง:
const numbers = [1, 2, 3, 4, 5, 6];
const sum = numbers
.filter(n => n % 2 === 0)
.map(n => n * 2)
.reduce((total, n) => total + n, 0);javascriptที่เห็นได้ชัดคือโค้ดแบบ imperative มักยาวกว่า ขณะที่แบบ declarative อ่านแล้วเข้าใจ “เจตนา” ได้ทันที — กรองคู่ คูณสอง บวกรวม
ความต่างเชิงเทคนิคที่ซ่อนอยู่คือ ฝั่ง imperative จะเข้าถึงและแก้ state โดยตรง (sum +=) ขณะที่ declarative ใช้ expression ที่ประเมินออกมาเป็นค่า โดยไม่ไปแตะตัวแปรภายนอก
🌳 Declarative ไม่ได้มีแค่แบบเดียว#
หลายคนเข้าใจว่า declarative คือ functional programming อย่างเดียว แต่จริง ๆ แล้ว declarative เป็นร่มใหญ่ที่ครอบหลาย sub-paradigm:
- Functional programming — เช่น Haskell
- Logic programming — เช่น Prolog
- Constraint programming — บอกเงื่อนไขที่ต้องเป็นจริง แล้วให้ระบบหาคำตอบ
ตัวอย่าง declarative ที่เป็น canonical และอ้างได้แน่นอนคือ SQL กับ Prolog เวลาเขียน SQL คุณบอกแค่ว่าอยากได้ recordset แบบไหน ไม่ได้บอกว่าให้ไล่อ่าน table ทีละแถวยังไง — ตรงนี้แหละคือหัวใจของ declarative ส่วน Prolog หาคำตอบด้วยการให้เหตุผลเชิงตรรกะ — คุณบอกข้อเท็จจริงและกฎ แล้วให้ระบบ deduce คำตอบเอง
ส่วนภาษาฝั่ง imperative ที่เจอบ่อยคือ C, Java, Python ซึ่งมีรากมาจาก von Neumann architecture (เก็บ instruction กับ data ไว้ใน memory แล้วรันทีละคำสั่งแบบ sequential ผ่านการแก้ค่าตัวแปรด้วย assignment)
น่าสนใจตรงที่ภาษายอดนิยมหลายตัว — Python, JavaScript, C++, C# — เป็น multi-paradigm เขียนได้ทั้งสองสไตล์ในภาษาเดียวกัน อยู่ที่ว่าคุณเลือกคิดแบบไหน
⚖️ ข้อดีข้อเสีย: ไม่มีฝั่งไหนชนะขาด#
Declarative — ข้อดี
- อ่านง่าย กระชับ เพราะแยก “อยากได้อะไร” ออกจาก “ทำยังไง” ทำให้โฟกัสที่ปัญหาไม่ใช่ implementation
- มีคุณสมบัติ idempotent ในหลายบริบท — รันคำสั่งซ้ำได้ผลลัพธ์เดิม (มีประโยชน์มากกับงาน config)
- state ถูกจัดการอัตโนมัติโดยภาษาหรือ framework ไม่ต้อง track เอง
Declarative — ข้อเสีย
- เสีย control เหนือขั้นตอนย่อย เพราะปล่อยให้ engine ตัดสินใจ
- performance อาจสู้ไม่ได้ถ้า engine optimize ได้ไม่ดี บางทีการ tune ด้วยมือยังเร็วกว่า
- debug ยากขึ้น เพราะรายละเอียดเชิง operation อย่าง evaluation order ถูกซ่อนไว้ (ในภาษาอย่าง Haskell เรื่องนี้ชัดเจน)
Imperative — ข้อดี
- control ละเอียดทุกขั้นตอน เหมาะกับงาน low-level และ algorithm ซับซ้อน
- ปรับจูน performance ได้เต็มที่
Imperative — ข้อเสีย
- พอโปรแกรมโตขึ้น การจัดการ mutable state เริ่มยุ่งยาก
- error มักเกิดจาก state เปลี่ยนแบบไม่คาดคิด ทำให้ debug เหนื่อย
- ทำ parallel ยาก เพราะมี shared mutable state
🧭 แล้วเมื่อไหร่ควรใช้แบบไหน#
เลือก Declarative เมื่อ ปัญหาแก้ได้ด้วยการนิยาม rules หรือ transformations — เช่น query database (SQL), จัดการ config / Infrastructure as Code (Terraform, Puppet), โครงสร้าง UI (เช่น map data ไปเป็น DOM), data pipeline และ data transformation — งานเหล่านี้จะได้ความ readable และ maintainable มาเป็นของแถม
เลือก Imperative เมื่อ control flow และ state เปลี่ยนแปลงซับซ้อน หรือต้อง optimize ทุกรายละเอียด — เช่น game development, real-time processing, การคุมฮาร์ดแวร์ระดับล่าง, system / OS programming, graphics และงาน performance-critical
มีสองกรณีที่ declarative ไม่เหมาะ และควรจำไว้:
- embedded systems ที่ต้องการ timing แน่นอน — เพราะคำตอบที่ถูกต้องแต่มาช้าเกินไป ก็กลายเป็นคำตอบที่ผิด
- งานแก้ไขเล็ก ๆ ที่ CLI script ธรรมดาทำได้ — การ wrap ด้วย declarative tooling จะซับซ้อนเกินจำเป็น
ที่สำคัญกว่านั้น โปรเจกต์ส่วนใหญ่ในโลกจริง ไม่ได้เลือกข้างใดข้างหนึ่ง แต่ผสมทั้งสองแบบ อยู่แล้ว แนวทางที่เจอบ่อยคือเขียน business logic แบบ declarative ให้อ่านง่ายเป็นหลัก แล้วค่อยสลับมาใช้ imperative เฉพาะจุดที่ต้องคุม performance หรือจัดการ error / retry ที่ซับซ้อน — คำถามจึงไม่ใช่ “เลือกแบบไหน” แต่เป็น “ตรงไหนควรใช้แบบไหน”
⚠️ กับดักที่เจอบ่อยที่สุด#
เข้าใจผิดยอดฮิตคือคิดว่า “พอเปลี่ยนมาใช้ map / filter / reduce หรือแยก logic เป็น function แล้ว โค้ดจะกลายเป็น declarative อัตโนมัติ”
จริง ๆ แล้วไม่ใช่อย่างนั้น เพราะคุณยังคิดแบบ procedural ได้อยู่ ทั้งที่ใช้ array methods — เครื่องมือพวกนี้เป็นกลาง ไม่ได้การันตีว่าคุณจะคิดแบบ declarative
แก่นจริง ๆ ของ declarative คือ การแสดงความสัมพันธ์ระหว่าง operation โดยไม่ผูกกับลำดับการ execute ส่วน procedural / imperative คือการเรียงลำดับขั้นตอนตาม temporal ordering — แก่นของเรื่องนี้คือการเปลี่ยน “วิธีคิด” ไม่ใช่แค่เปลี่ยน syntax
กับดักอื่นที่เจอบ่อยในงาน UI เช่น React คือไปแก้ DOM ตรง ๆ (ติดนิสัยมาจาก jQuery) หรือยัด logic เข้าไปใน template จนซับซ้อน ทั้งที่ paradigm พวกนี้ออกแบบมาให้บอก “ผลลัพธ์ที่อยากได้” ไม่ใช่ไปสั่งแก้ทีละขั้น
📝 สรุป#
Imperative บอกคอมพิวเตอร์ว่า “ทำยังไง” ทีละขั้น พร้อมจัดการ state เอง ส่วน Declarative บอกแค่ “อยากได้อะไร” แล้วปล่อยที่เหลือให้ระบบจัดการเอง ไม่มีฝั่งไหนดีกว่าโดยสมบูรณ์ — declarative ชนะเรื่อง readability และ maintainability ส่วน imperative ชนะเรื่อง control และ performance งานจริงจึงเป็นเรื่องของการเลือกแบบที่เหมาะกับแต่ละจุด ไม่ใช่ยึดติดแบบใดแบบหนึ่ง
ครั้งหน้าที่คุณเขียน for loop ลองหยุดคิดสักนิดว่า “อันนี้เขียนแบบ declarative ได้ไหม จะอ่านง่ายขึ้นหรือเปล่า” — แล้วลองหยิบ SQL หรือ array methods ในภาษาที่คุณถนัดมาเขียนโจทย์เดิมทั้งสองสไตล์ดู คุณจะเริ่ม “เห็น” สอง paradigm นี้ในโค้ดทุกบรรทัดที่เจอ
😎 ☕