Statecharts: เครื่องสถานะแบบลำดับชั้น
(statecharts.dev)- เป็นรูปแบบสำหรับจัดโครงสร้าง พฤติกรรมของระบบที่ซับซ้อน ในเชิงภาพ โดยขยายจาก state machine พื้นฐานเพื่อรับมือปัญหา state explosion
- สามารถ แยกพฤติกรรมออกจากคอมโพเนนต์ ได้ ทำให้เปลี่ยนการทำงานและให้เหตุผลกับโค้ดได้ง่ายขึ้น และเหมาะกับการทดสอบที่เป็นอิสระจากคอมโพเนนต์รวมถึงการ สำรวจกรณียกเว้น
- ในกระบวนการสร้าง statechart จะมีการสำรวจสถานะที่เป็นไปได้ทั้งหมด และยังมี ผลการวิจัยที่พบว่า โค้ดที่อิง statechart มี จำนวนบั๊กต่ำกว่า โค้ดแบบดั้งเดิม
- ผ่าน มาตรฐาน SCXML และเครื่องมือหรือไลบรารีในหลายภาษา ทำให้สามารถอ่าน เขียน และรันโมเดลได้ พร้อมช่วยจัดการลำดับการทำงานอย่าง entry/exit action ได้อย่างถูกต้อง
- หากใช้ machine format ที่รันได้จริง ก็สามารถใช้คำนิยามเดียวเป็น single source of truth เพื่อดูแลทั้งพฤติกรรมขณะรันและไดอะแกรมร่วมกัน ทำให้การ คงการซิงก์ ระหว่างการออกแบบกับการพัฒนามีความสำคัญ
ภาพรวมของ Statecharts
- Statechart คือรูปแบบเชิงภาพสำหรับจัดการระบบที่ซับซ้อน โดยเป็นการขยายจาก state machine พื้นฐาน
- มีการเสริมเพื่อรับมือปัญหา state explosion ที่เกิดขึ้นเมื่อ state machine มีขนาดใหญ่ขึ้น
- แม้จะใช้ภาพเพื่อแสดงการทำงานได้ แต่ในวิศวกรรมซอฟต์แวร์ สิ่งนี้ใกล้เคียงกับ การสร้างแบบจำลองพฤติกรรม และการจัดโครงสร้าง มากกว่าการทำภาพให้อ่านง่ายเพียงอย่างเดียว
- คำอธิบายพื้นฐานที่เกี่ยวข้องมีต่อใน What is a state machine?, What is a statechart?
เหตุผลที่ใช้ Statecharts
- มี โครงสร้างที่เข้าใจง่าย จึงมักอ่านได้ง่ายกว่าโค้ดในรูปแบบอื่นจำนวนมาก
- สามารถ แยกพฤติกรรมออกจากคอมโพเนนต์ ได้
- เปลี่ยนการทำงานได้ง่ายขึ้น
- ให้เหตุผลกับโค้ดได้ง่ายขึ้น
- ทดสอบพฤติกรรมแยกจากคอมโพเนนต์ได้
- ในการสร้าง statechart จะมีการ สำรวจสถานะที่เป็นไปได้ทั้งหมด
- มี ผลการวิจัยที่พบว่า โค้ดที่อิง statechart มี จำนวนบั๊กต่ำกว่า โค้ดแบบดั้งเดิม
- เหมาะกับการจัดการ กรณียกเว้น ที่มักถูกมองข้าม
- ยิ่งความซับซ้อนเพิ่มขึ้น ก็ยิ่งมี ความสามารถในการขยาย ที่ดี
- คนที่ไม่ใช่นักพัฒนาก็เข้าใจได้ง่าย และ QA สามารถใช้เป็น เครื่องมือสำรวจ ได้
- โค้ดจำนวนมากมี state machine แฝงอยู่แล้วโดยปริยาย และ statechart ทำหน้าที่ ทำให้สิ่งนั้นชัดเจนอย่างเป็นรูปธรรม
ภาระและปัจจัยคัดค้านของ Statecharts
- ต้องมี ต้นทุนในการเรียนรู้สิ่งใหม่
- แม้แนวคิดพื้นฐานอย่าง state machine เองอาจคุ้นเคยกับโปรแกรมเมอร์จำนวนมากอยู่แล้ว
- ต่างจากวิธีเขียนโค้ดแบบเดิมพอสมควร จึงอาจรู้สึกเป็น กระบวนทัศน์ที่ไม่คุ้นเคย
- ระดับทีมอาจเกิดแรงต้านได้
- ใน statechart ขนาดเล็ก กระบวนการแยกพฤติกรรมอาจทำให้ จำนวนบรรทัดโค้ดเพิ่มขึ้น
- เหตุผลที่ยังไม่แพร่หลายมาจากทั้ง การรับรู้ที่ยังน้อย และ YAGNI
- เหตุผลคัดค้านที่พบบ่อยคืออาจไม่จำเป็นจริง ไม่สอดคล้องกับกระแสเทคโนโลยีบางแบบ และทำให้จำนวนไลบรารีเพิ่มขึ้น
- ในเว็บแอปพลิเคชัน เวลาโหลดอาจเพิ่มขึ้น
- แม้พิจารณาทั้งข้อดีและข้อเสียร่วมกันแล้ว ผลของการนำมาใช้โดยรวมก็ยังใกล้เคียงกับ ผลได้สุทธิ
วิธีใช้งานและ SCXML
- SCXML คือรูปแบบที่ W3C ทำให้เป็นมาตรฐานระหว่างปี 2005 ถึง 2015 โดยกำหนดกฎเชิงความหมายของ statechart แบบต่าง ๆ และการจัดการ edge case
- มีเครื่องมือในหลายภาษาที่สามารถอ่าน เขียน และรัน SCXML ได้
- ยังมีรูปแบบอนุพันธ์ที่คง โมเดล เดิมไว้ แต่ต่างกันที่ไวยากรณ์
- มีไลบรารี statechart สำหรับหลายแพลตฟอร์ม ซึ่งรองรับกฎเชิงความหมายของ SCXML ในระดับที่แตกต่างกัน
- การใช้ไลบรารีเหล่านี้ช่วยจัดการลำดับการทำงานอย่าง entry/exit action ได้อย่างถูกต้อง
- แนวทางการใช้งานเพิ่มเติมมีต่อใน how to use statecharts
Statecharts แบบรันได้จริง
- แทนที่จะใช้ statechart เป็นเพียงเอกสาร สามารถใช้ machine format ที่รันได้จริง ร่วมกันทั้งในงานออกแบบและตอนรันจริง
- สามารถใช้คำนิยามเดียวเป็น single source of truth เพื่อขับเคลื่อนทั้งพฤติกรรมขณะรันจริงและไดอะแกรมเชิงภาพ
- ไม่จำเป็นต้อง แปลงไดอะแกรมเป็นโค้ด อีก
- ลดบั๊กที่เกิดจากการแปลด้วยมือ
- ทำให้ไดอะแกรมและการใช้งานจริงอยู่ในสถานะ ซิงก์กันเสมอ
- ไดอะแกรมมีความละเอียดแม่นยำมากขึ้น
- ในทางกลับกัน ไดอะแกรมก็อาจซับซ้อนขึ้นมากได้
- ตัวเลือกของฟอร์แมตและเครื่องมือ สำหรับ statechart แบบรันได้จริงยังมีจำกัด
- เป็นเรื่องยากที่จะรับประกัน type safety อย่างเข้มงวดระหว่าง statechart กับคอมโพเนนต์
- หากมีคำนิยาม statechart อยู่ในโค้ด ก็สามารถใช้การแสดงผลนั้นสร้าง statechart เชิงภาพโดยอัตโนมัติได้
- จะยิ่งง่ายขึ้นหากคำนิยามอยู่ในไฟล์แยกอย่าง JSON หรือ XML
ชุมชนและแหล่งข้อมูลเพิ่มเติม
- บทสนทนาในชุมชนดำเนินต่อที่ gitter.im และสามารถดูแชตได้โดยไม่ต้องล็อกอิน
- การสนทนาแนวถามตอบมีต่อที่ statecharts GitHub discussions
- หนังสือและสื่อประกอบการบรรยายรวมอยู่ที่หน้า resources
- สามารถแชร์เนื้อหาที่เขียนเองได้ใน GitHub Discussions
-
อ่านเพิ่มเติม
- Use case: Statecharts in User Interfaces
- Concepts — แนวคิดหลักของ statechart และลักษณะที่ปรากฏในไดอะแกรม
- Glossary — คำศัพท์ที่ใช้บ่อยและคำจำกัดความ
- FizzBuzz — อธิบายแนวคิด statechart โดยใช้ FizzBuzz
- Acknowledgements
1 ความคิดเห็น
ความเห็นจาก Hacker News
ดีใจที่เห็น statecharts ยังได้รับความสนใจอย่างต่อเนื่อง
ผมเป็นคนสร้าง XState ซึ่งเป็นไลบรารีสำหรับเขียน/รัน/ทำภาพสถานะ machine และ statecharts สำหรับ JS/TS ดูได้ที่ https://github.com/statelyai/xstate
สิ่งสำคัญที่สุดที่ได้เรียนรู้จากการทำงานมากว่า 10 ปีคือ statecharts มีคุณค่ามากที่สุดเมื่อเราปฏิบัติต่อมันไม่ใช่แค่เอกสาร แต่เป็น พฤติกรรมที่รันได้จริง
ไม่จำเป็นต้องใช้มันทุกที่ แต่จะทรงพลังเป็นพิเศษเมื่อคำถามว่า "จะเกิดอะไรขึ้นต่อไป?" ขึ้นอยู่ทั้งกับสถานะปัจจุบันและ event
แผนภาพแบบนี้ใช้เป็นเหมือนออราเคิลที่ตอบคำถามว่า "ถ้าอยู่ในสถานะนี้แล้ว event นี้มา สถานะถัดไปคืออะไร และจะเกิด effect อะไรบ้าง?"
XState เวอร์ชันหลักถัดไปแบบอัลฟ่าก็ใกล้พร้อมแล้วเช่นกัน โดยเน้นที่ ergonomics, type safety, composability และ visualizer/editor ตัวใหม่
เครื่องมือ visualization แบบโอเพนซอร์สพื้นฐานมีอยู่ที่ https://sketch.stately.ai
ฝั่ง formal specification นั้น SCXML ก็น่าอ่านมาก: https://www.w3.org/TR/scxml
และงานต้นฉบับของ David Harel ก็มีคุณค่ามาก: https://www.weizmann.ac.il/math/harel/sites/math.harel/files/users/user50/Statecharts.pdf
ยังมีวิดีโอจาก Laracon ที่คุณสรุปแนวคิดเกี่ยวกับ state machines และ statecharts ไว้ด้วย
https://www.youtube.com/watch?v=1A1xFtlDyzU
เป็น implementation ที่ค่อนข้างสุกงอม ซึ่งเดินตาม SCXML ได้ใกล้พอสมควร และโดยเฉพาะในส่วนของ executable content ก็ไม่บังคับให้ต้องใช้ XML
ในส่วน prior art ก็มีอ้างถึง XState เป็นกรณีอ้างอิงด้วย
ผมใช้มันร่วมกับ lit.js กับคอมโพเนนต์นำทางแบบ drawer ที่ตอบสนองต่อความกว้างหน้าเว็บและมีทั้ง props กับสถานะภายในจำนวนมาก นึกไม่ออกเลยว่าถ้าไม่มี XState มันจะเละขนาดไหน
ตั้งตารอเวอร์ชันถัดไป และขอบคุณจริง ๆ
มันมี TS type inference อัตโนมัติที่ค่อนข้างดี เลยเหมาะกับจุดที่ต้องการ logic ของ state machine แบบเบา ๆ
เมื่อก่อนดูเหมือนว่า statecharts กำลังค่อย ๆ ได้แรงส่งใน frontend/UI ecosystem แต่ก็น่าเสียดายที่กระแสนั้นเหมือนจะหายไปเฉย ๆ
ถ้าใช้ state machine โดยเฉพาะการประกอบ state machine แบบ statecharts กับ interaction ของ UI มันจะทำให้การทำความเข้าใจกับ flow ที่ซับซ้อนง่ายขึ้นมาก
ถ้ายังไม่เคยแตะมาก่อน ผมแนะนำ Ian Horrucks เรื่อง "Constructing the user interface with statecharts" อย่างมาก
แม้จะเป็นหนังสือปี 1999 แต่ในฐานะหนังสือเริ่มต้นที่อธิบายว่าควรนำไปใช้และใช้งานจริงอย่างไร มันยังยอดเยี่ยมมากอยู่
https://archive.org/details/isbn_9780201342789/mode/2up
ยอดดาวน์โหลดรายสัปดาห์บน npm เกิน 4 ล้านแล้ว และเครื่องมือ animation อย่าง Rive กับ LottieFiles ก็ชูความสามารถด้าน state machine อย่างชัดเจน
เครื่องมือ AI อย่าง LangGraph ก็สร้างอยู่บนฐานของ state machine เช่นกัน
แน่นอนว่าแอปและเครื่องมือเหล่านี้อาจยังต้องใช้เวลาอีกกว่าจะดึงศักยภาพของ statecharts ออกมาได้เต็มที่ แต่จุดเริ่มต้นถือว่าดีมาก
https://github.com/derkork/godot-statecharts
สิ่งที่หนังสือเริ่มต้นมักตกหล่นคือ history pseudo-states
เมื่อใช้ H, H แล้ว ถ้ามองจากภายนอก statechart จะกลายเป็น non-deterministic อย่างเป็นทางการ
มักมีคำอธิบายว่า "สถานะปัจจุบันเป็น pure function ของ input" แต่ history ทำลายสมมติฐานนั้น
หากกลับเข้าสู่ parent state ผ่าน H มันจะย้อนกลับไปยัง child ที่ active ล่าสุด ดังนั้นแม้ event และสถานะภายนอกจะเหมือนกัน ก็ยังเข้าไปสู่สถานะภายในที่ต่างกันได้
"child ที่ active ล่าสุด" ที่ซ่อนอยู่นั้นเองก็เป็น state แต่ในแผนภาพมักไม่ได้วาดไว้
ทั้งงานต้นฉบับของ Harel, SCXML และ XState ต่างก็ยอมรับและรองรับเรื่องนี้ แต่กลับแทบไม่มีใครพูดถึงมัน
เพราะงั้นถ้าคุณใช้ deep history เพื่อคงสถานะของ subtree ไว้ตอน re-enter เท่ากับคุณย้ายภาระ bookkeeping ไปไว้ที่ฝั่ง chart engine
มันเป็นทางเลือกที่โอเค แต่หมายความว่าภาพวาดเพียงอย่างเดียวอธิบายพฤติกรรมทั้งหมดไม่ได้ และ transition แบบ history ก็ควรต้องมีการทดสอบแยกเหมือน state logic อื่น ๆ
ถ้าใช้การตีความแบบหลัง เครื่องก็ deterministic สมบูรณ์อยู่ดี และ deep history pointer ก็เป็นเพียงส่วนหนึ่งของ state ของ state machine
เช่นคลี่ H, H node ออกเป็นหลาย node แล้วให้ H' เป็นเหมือน write-ahead log ที่วางไว้หน้าทุก node
สงสัยว่าสามารถผสาน durable execution engine อย่าง Temporal, DBOS, Restate เข้ากับ statecharts ได้ไหม
ที่บริษัท เราใช้ Cloudflare Workflows จัดการ onboarding และ payment workflow และ diagram แบบ flowchart ที่ได้มาอัตโนมัติก็ช่วยให้เข้าใจการทำงานของ workflow ได้เร็วมาก
สิ่งนี้ดูคล้ายกับคุณค่าที่ statecharts พยายามมอบให้พอสมควร
https://zindex.ai/
ไดอะแกรมที่ AI สร้างขึ้นส่วนใหญ่มักจบแค่ Mermaid/SVG/PNG ที่สร้างครั้งเดียวแล้วจบ จึงไม่มี persistent diagram state ที่อัปเดต ตรวจสอบ ทำ diff หรือ reuse ได้
Zindex ปฏิบัติต่อไดอะแกรมเป็น structured state โดยตรง
ให้เอเจนต์ patch node, edge, group, relation, constraint และ revision ผ่าน Diagram Scene Protocol (DSP) แล้ว Zindex จะรับหน้าที่ validation, layout, rendering, versioning และ storage
เพราะแบบนี้จึงน่าจะวางไว้ข้าง Temporal/DBOS/Restate/Cloudflare Workflows ได้ โดยให้ engine เป็นแหล่งความจริงของการรัน ส่วน Zindex ดูแล visual model แบบ persistent และตรวจสอบได้ซึ่งได้มาจากโค้ดหรือประวัติการรัน
จริง ๆ แล้วถ้าเพิ่ม durable execution เข้าไป statecharts ก็ทำได้สบายมาก
ช่วงหนึ่งเหมือน Cloudflare จะเอนเอียงไปทางโมเดล actor ของ durable object แต่ผมก็ไม่แน่ใจว่าพวกเขาพับโปรเจกต์นั้นไปแล้วหรือยัง
เป็นความสามารถที่ฝังมาใน Cloudflare Workers หรือว่าทีมคุณทำขึ้นเองกันแน่
ผมชอบ XState มากจริง ๆ
มันช่วยแก้ปัญหาในหลาย codebase ให้ผมมาเยอะมาก และช่วงหลังกลายเป็นแกนหลักของแอปเสียงที่เรากำลังทำให้ภาคธนาคาร
ขอบคุณที่ทุ่มเวลาและแรงเพื่อสร้างมันออกมาได้ยอดเยี่ยมแบบนี้
ผมยังเขียนสรุปประสบการณ์กับ finite state machines และสถาปัตยกรรมที่ใช้ XState + Mastra ไว้นิดหน่อยในบล็อกด้วย
หลังเผยแพร่แล้วผมก็ย้ายจาก Mastra ไปใช้ Pipecat
https://blog.davemo.com/posts/2026-02-14-deterministic-core-agentic-shell.html
ขอโยนอันนี้เพิ่มไว้ด้วย
ETL State Chart และ Hierarchial FSM:
https://www.etlcpp.com/state_chart.html / https://www.etlcpp.com/hfsm.html
Quantum Leaps:
https://www.state-machine.com
ผมใช้สิ่งเหล่านี้กับระบบ safety-critical เป็นหลัก ซึ่งในบริบทนั้นเรื่องความซับซ้อน จังหวะเวลา และความสามารถในการตรวจพิสูจน์พฤติกรรมสำคัญมากเป็นพิเศษ
การแยก decision ออกจาก action ช่วยได้มาก
วิธีลดรูปการตัดสินใจให้เหลือ "ถ้า event นี้มาในสถานะนี้ เราควรทำอะไรต่อ" อาจต่างจากโครงสร้างโปรแกรมทั่วไปอยู่บ้าง แต่ช่วยสร้างการแยกส่วนที่ดี และทำให้ reasoning ต่อพฤติกรรมภายใต้เงื่อนไขต่าง ๆ ง่ายขึ้น
ผมหวังเสมอว่าการยอมรับใช้ state machine จะมากขึ้นกว่านี้
ในยุคที่เราเข้าใจโค้ดที่ AI สร้างขึ้นได้ไม่ลึกเท่ากับโค้ดที่มนุษย์เขียน ความเข้าใจ state แบบมองเห็นได้ จะยิ่งสำคัญขึ้นเรื่อย ๆ
ถึงอย่างนั้นในเฟรมเวิร์กฝั่งฟรอนต์เอนด์ก็ดูเหมือนยังนิยม reactive state แบบ store-based มากกว่า
ตัวผมเองก็ใช้แนวนั้นเป็นค่าเริ่มต้นเหมือนกัน เลยไม่ได้ฝืนเปลี่ยน และไลบรารีอย่าง xstate ก็ยังมีภาพลักษณ์ว่า syntax เรียนยากกว่าและค่อนข้าง verbose
แต่พอมี AI อุปสรรคนั้นก็แทบหายไป จึงสงสัยว่ามีเหตุผลอื่นที่ผมมองไม่เห็นหรือเปล่า หรือ statechart แค่ยังไปไม่ถึงจุดพีก
พื้นผิวของ API จะเล็กลง learning curve ก็จะต่ำลง และทั้งนักพัฒนากับเอเจนต์จะเขียนได้ง่ายขึ้น
ขณะเดียวกัน frontier model รุ่นใหม่ ๆ ก็เขียนโค้ด XState ได้ค่อนข้างดีอยู่แล้ว
ตอนทำโปรเจกต์ https://github.com/xlnfinance/xln ผมตระหนักว่าจำเป็นต้องมีวิธี emulate เครือข่ายจริงแบบ deterministic
แล้วก็คิดขึ้นมาว่าบล็อกเชนทุกตัวสุดท้ายแล้วก็คือ replicated state machine ถ้าอย่างนั้นก็ครอบ node ของผู้ใช้แต่ละตัวด้วย ลำดับชั้น state machine 3 ระดับ คือ Runtime -> Entity -> Account ได้ไม่ใช่หรือ
เป็นโครงสร้างที่ machine ชั้นนอกควบคุม machine ชั้นในได้ทั้งหมด จึงคล้ายภาพของ "blockchain inside blockchain" ที่มี consensus mode ต่างกัน
หลังจากนั้นผมค้นคำว่า "hierarchical state machines" แล้วก็เจอ statecharts และรู้สึกว่าสองแนวคิดนี้คล้ายกันมาก
ผมคิดว่าซอฟต์แวร์ควรใช้ลำดับชั้นของ state machine กันมากขึ้น เพื่อลดบั๊กเลวร้ายที่เกิดจาก non-determinism
ในวงการยานยนต์ วิธีแบบนี้ใช้กันมา นานมาก แล้ว
ถ้าดู matlab/simulink คุณสามารถวาดอัลกอริทึมเป็น state machine แล้วสร้างโค้ดจากมันได้เลย
ไม่นานมานี้ผมก็เพิ่งทำ state machine ขึ้นมาเพื่อจัดการ React component ที่ค่อนข้างซับซ้อน ซึ่งต้องไล่ผ่าน CSS transition และเปลี่ยนผ่านหลาย visual state
ตัว state machine เองไม่ได้ยากมาก แต่ดูเหมือนคนส่วนใหญ่ยังไม่ค่อยคุ้นเคยกับแนวคิดนี้นัก
ที่บริษัท หลังจากผมสร้าง interpreter ภายในของ Postgres เราก็รันทุก business process ด้วย statecharts
ประสบการณ์ดีมาก process ทนต่อการเปลี่ยนแปลงได้สูงมาก และแม้กลับมาดูอีกหลายปีให้หลังก็ยังเข้าใจได้ง่าย
ผมยังเปิดซอร์สไลบรารีนี้ไว้ด้วย
https://github.com/kronor-io/statecharts