- Đây là một hình thức cấu trúc hóa trực quan hành vi của các hệ thống phức tạp, được mở rộng từ state machine cơ bản để xử lý vấn đề state explosion
- Có thể tách biệt hành vi và component, giúp việc thay đổi cách hoạt động và suy luận về mã nguồn trở nên dễ hơn, đồng thời phù hợp cho việc kiểm thử độc lập với component và khám phá các tình huống ngoại lệ
- Trong quá trình xây dựng statechart, ta sẽ đi qua toàn bộ các trạng thái có thể có; cũng có kết quả nghiên cứu cho thấy mã dựa trên statechart có ít bug hơn so với mã truyền thống
- Thông qua chuẩn SCXML và các công cụ, thư viện ở nhiều ngôn ngữ, có thể đọc, viết và thực thi mô hình; đồng thời hỗ trợ xử lý đúng thứ tự hành vi như entry/exit action
- Nếu dùng định dạng machine có thể thực thi, có thể lấy một định nghĩa làm single source of truth để duy trì đồng thời hành vi runtime và sơ đồ, nên việc giữ đồng bộ giữa triển khai và thiết kế trở nên quan trọng
Tổng quan về Statecharts
- Statechart là một định dạng trực quan để xử lý các hệ thống phức tạp, là dạng mở rộng của state machine cơ bản
- Nó được tăng cường để xử lý vấn đề state explosion xuất hiện khi state machine ngày càng lớn
- Dù có thể biểu diễn hành vi bằng sơ đồ, trong kỹ thuật phần mềm nó gần với mô hình hóa hành vi và cấu trúc hóa hơn là chỉ đơn thuần trực quan hóa
- Phần giải thích nền tảng liên quan được nối tiếp tại What is a state machine?, What is a statechart?
Vì sao dùng Statecharts
- Có cấu trúc dễ hiểu, nên thường dễ nắm bắt hơn nhiều dạng mã khác
- Có thể tách biệt hành vi và component
- Việc thay đổi cách hoạt động trở nên dễ hơn
- Việc suy luận về mã nguồn trở nên dễ hơn
- Có thể kiểm thử hành vi độc lập với component
- Trong quá trình tạo statechart, ta sẽ khám phá toàn bộ các trạng thái có thể có
- Có nghiên cứu cho thấy mã dựa trên statechart có ít bug hơn so với mã truyền thống
- Phù hợp để xử lý các tình huống ngoại lệ dễ bị bỏ sót
- Khi độ phức tạp tăng lên, khả năng mở rộng tốt hơn
- Ngay cả người không phải lập trình viên cũng dễ hiểu, và QA có thể dùng như một công cụ khám phá
- Nhiều mã hiện có vốn đã ngầm chứa state machine, và statechart hoạt động như một cách làm cho điều đó trở nên tường minh
Gánh nặng và các yếu tố phản đối Statecharts
- Cần chi phí học tập mới
- Dù vậy, khái niệm nền tảng là state machine có thể đã quen thuộc với nhiều lập trình viên
- Nó khá khác với cách viết mã hiện có nên có thể bị cảm nhận như một paradigm xa lạ
- Ở cấp độ đội nhóm, điều này có thể gây ra sự e ngại
- Với statechart nhỏ, quá trình tách hành vi có thể khiến số dòng mã tăng lên
- Lý do nó chưa được dùng rộng rãi gồm thiếu nhận thức và YAGNI cùng tác động
- Các lập luận phản đối phổ biến gồm: không thật sự cần thiết, không hợp với một số xu hướng công nghệ cụ thể, và làm tăng số lượng thư viện
- Trong ứng dụng web, thời gian tải có thể tăng lên
- Dù xét cả ưu và nhược điểm, hiệu quả khi áp dụng nhìn chung vẫn gần với lợi ích ròng
Cách sử dụng và SCXML
- SCXML là định dạng được W3C chuẩn hóa từ năm 2005 đến 2015, định nghĩa nhiều quy tắc ngữ nghĩa của statechart và cách xử lý edge case
- Có các công cụ ở nhiều ngôn ngữ để đọc, viết và thực thi SCXML
- Cũng có các định dạng dẫn xuất khác cú pháp nhưng vẫn giữ cùng một mô hình
- Có nhiều thư viện statechart cho các nền tảng khác nhau, hỗ trợ các quy tắc ngữ nghĩa SCXML ở các mức độ khác nhau
- Dùng các thư viện này giúp xử lý đúng thứ tự hành vi như entry/exit action
- Hướng dẫn sử dụng thêm được nối tiếp tại how to use statecharts
Statecharts có thể thực thi
- Thay vì chỉ dùng statechart như tài liệu, có thể dùng định dạng machine có thể thực thi cho cả thiết kế và runtime
- Có thể lấy một định nghĩa làm single source of truth để vận hành đồng thời hành vi runtime thực tế và sơ đồ trực quan
- Không còn cần chuyển sơ đồ thành mã
- Có thể giảm bug phát sinh khi dịch thủ công
- Sơ đồ và phần triển khai luôn giữ trạng thái đồng bộ
- Sơ đồ trở nên chính xác hơn
- Ngược lại, sơ đồ cũng có thể trở nên khá phức tạp
- Các lựa chọn định dạng và công cụ cho statechart có thể thực thi còn hạn chế
- Khó bảo đảm mạnh mẽ type safety giữa statechart và component
- Nếu định nghĩa statechart nằm trong mã, có thể dùng chính biểu diễn đó để tự động sinh statechart trực quan
- Việc này đơn giản hơn khi định nghĩa nằm trong tệp riêng như JSON hoặc XML
Cộng đồng và tài liệu bổ sung
1 bình luận
Ý kiến trên Hacker News
Thật vui khi thấy statecharts tiếp tục được chú ý
Tôi là người tạo ra XState, thư viện để viết/thực thi/trực quan hóa state machine và statecharts cho JS/TS, có thể xem tại https://github.com/statelyai/xstate
Điều cốt lõi tôi học được sau hơn 10 năm làm việc với nó là statecharts có giá trị lớn nhất khi được xem như hành vi có thể thực thi, chứ không chỉ là tài liệu
Không cần dùng ở mọi nơi, nhưng nó đặc biệt mạnh khi câu hỏi "điều gì sẽ xảy ra tiếp theo?" phụ thuộc cả vào trạng thái hiện tại lẫn sự kiện
Những biểu đồ như vậy có thể được dùng như một oracle để trả lời: "nếu đang ở trạng thái này mà sự kiện này đến, thì trạng thái tiếp theo là gì và hiệu ứng nào sẽ được chạy?"
Bản alpha cho major version tiếp theo của XState cũng gần như đã sẵn sàng, tập trung vào ergonomics, type safety, composability và visualizer/editor mới
Công cụ trực quan hóa mã nguồn mở cơ bản có tại https://sketch.stately.ai
Về mặt đặc tả hình thức, SCXML rất đáng đọc: https://www.w3.org/TR/scxml
Bài báo gốc của David Harel cũng rất giá trị: https://www.weizmann.ac.il/math/harel/sites/math.harel/files/users/user50/Statecharts.pdf
Cũng có một video ở Laracon, nơi bạn trình bày lại suy nghĩ của mình về state machines và statecharts
https://www.youtube.com/watch?v=1A1xFtlDyzU
Đây là một implementation khá trưởng thành, bám khá sát SCXML nhưng loại bỏ yêu cầu XML, đặc biệt với nội dung có thể thực thi
Trong phần prior art cũng có đưa XState vào như một trường hợp tham khảo
Tôi đã dùng nó cùng lit.js cho một component điều hướng kiểu drawer phản ứng theo độ rộng trang và có nhiều props lẫn state nội bộ; thật khó tưởng tượng sẽ khủng khiếp đến mức nào nếu không có XState
Tôi cũng rất mong đợi phiên bản tiếp theo, cảm ơn bạn thật nhiều
Tính năng TS type inference tự động của nó khá tốt, nên rất tiện ở những chỗ chỉ cần logic state machine nhẹ
Trước đây có vẻ frontend/UI ecosystem đang dần tạo đà cho statecharts, nên thật tiếc vì không rõ sao làn sóng đó lại biến mất
Với tương tác UI, dùng state machine, đặc biệt là cách kết hợp state machine như statecharts, giúp việc suy luận các luồng phức tạp dễ hơn rất nhiều
Nếu đây là lần đầu bạn tiếp cận, tôi cực kỳ khuyên đọc "Constructing the user interface with statecharts" của Ian Horrucks
Dù là sách từ năm 1999, nó vẫn thuộc hàng tốt nhất như một tài liệu nhập môn giải thích cách áp dụng và sử dụng trong thực tế
https://archive.org/details/isbn_9780201342789/mode/2up
Lượt tải npm hằng tuần đã vượt 4 triệu, và các công cụ animation như Rive và LottieFiles cũng nhấn mạnh mạnh mẽ vào tính năng state machine
Các công cụ AI như LangGraph cũng được xây trên nền state machine
Có thể sẽ còn cần thêm thời gian để các app và công cụ này khai thác hết tiềm năng của statecharts, nhưng khởi đầu là rất tốt
https://github.com/derkork/godot-statecharts
Một phần hay bị bỏ sót trong sách nhập môn là history pseudo-states
Nếu dùng H, H thì nhìn từ bên ngoài, statechart sẽ trở nên không quyết định về mặt hình thức
Người ta thường giải thích rằng "trạng thái hiện tại là một hàm thuần của đầu vào", nhưng history phá vỡ giả định đó
Khi đi vào lại trạng thái cha thông qua H, nó sẽ quay về đứa con đã được kích hoạt gần nhất, nên ngay cả với cùng sự kiện và cùng trạng thái bên ngoài, bạn vẫn có thể đi vào những trạng thái nội bộ khác nhau
Cái "đứa con được kích hoạt gần nhất" bị ẩn đó bản thân nó cũng là state, nhưng thường không được vẽ trên sơ đồ
Bài báo gốc của Harel cũng thừa nhận điều này, và SCXML cùng XState đều triển khai nó, nhưng lạ là phần này hầu như không được nhắc đến
Vì vậy, nếu bạn dùng deep history để giữ nguyên trạng thái của cả cây con khi tái nhập, thì thực chất bạn đã chuyển phần bookkeeping sang phía chart engine
Đây vẫn là một lựa chọn hợp lý, nhưng chỉ riêng hình vẽ thì không thể mô tả hết toàn bộ hành vi, và các history transition cũng cần được test riêng như mọi logic trạng thái khác
Nếu theo cách hiểu thứ hai thì cỗ máy hoàn toàn quyết định, và deep history pointer đơn giản chỉ là một phần của trạng thái state machine
Ví dụ có thể bung các node H, H thành nhiều node, và đặt H' như một write-ahead log gắn trước từng node
Tôi tự hỏi liệu có thể kết hợp statecharts với các durable execution engine như Temporal, DBOS, Restate hay không
Ở công ty, chúng tôi dùng Cloudflare Workflows để quản lý onboarding và payment workflow, và nhờ biểu đồ flowchart được sinh tự động mà có thể hiểu rất nhanh cách workflow hoạt động
Điều này cuối cùng trông khá giống với giá trị mà statecharts hướng tới
https://zindex.ai/
Các sơ đồ do AI tạo ra thường chỉ là Mermaid/SVG/PNG sinh một lần rồi thôi, nên không có trạng thái sơ đồ bền vững để cập nhật/xác minh/diff/tái sử dụng
Zindex xử lý chính sơ đồ như một trạng thái có cấu trúc
Khi agent patch node, edge, group, relationship, constraint và revision bằng Diagram Scene Protocol (DSP), Zindex sẽ đảm nhiệm validation, layout, rendering, versioning và storage
Vì vậy tôi nghĩ có thể gắn nó bên cạnh Temporal/DBOS/Restate/Cloudflare Workflows, để engine giữ vai trò nguồn chân lý cho việc thực thi, còn Zindex quản lý mô hình trực quan bền vững, có thể kiểm tra, được suy ra từ code hoặc lịch sử thực thi
Thực ra chỉ cần gắn thêm durable execution là statecharts cũng hoàn toàn làm được
Cloudflare trước đây có vẻ đi theo hướng mô hình actor durable object một thời gian, nhưng tôi không rõ họ đã bỏ dự án đó hay chưa
Đó là tính năng tích hợp sẵn trong Cloudflare Workers, hay là thứ đội của bạn tự làm?
Tôi cực kỳ thích XState
Nó đã giải quyết vô số vấn đề trong nhiều codebase, và gần đây còn trở thành bộ khung cốt lõi cho ứng dụng giọng nói mà chúng tôi làm cho ngành ngân hàng
Cảm ơn bạn vì đã bỏ rất nhiều thời gian và công sức để làm ra nó tốt đến vậy
Tôi cũng có viết chút ít trên blog về trải nghiệm với finite state machines, và kiến trúc mà tôi đã dựng bằng XState + Mastra
Sau khi bài được đăng, tôi đã chuyển từ Mastra sang Pipecat
https://blog.davemo.com/posts/2026-02-14-deterministic-core-agentic-shell.html
Ném thêm cái này vào đây nữa
ETL State Chart và Hierarchial FSM:
https://www.etlcpp.com/state_chart.html / https://www.etlcpp.com/hfsm.html
Quantum Leaps:
https://www.state-machine.com
Tôi chủ yếu đã dùng chúng trong các hệ thống safety-critical, nơi độ phức tạp, timing và khả năng kiểm chứng hành vi đặc biệt quan trọng
Khả năng tách biệt giữa ra quyết định và hành động là một lợi ích rất lớn
Cách gọt việc ra quyết định thành câu hỏi "nếu đang ở trạng thái này mà sự kiện này đến, thì tiếp theo sẽ làm gì" hơi khác với cấu trúc chương trình thông thường, nhưng nó tạo ra sự tách biệt tốt và giúp suy luận hành vi dưới nhiều điều kiện khác nhau dễ hơn nhiều
Tôi luôn mong việc áp dụng state machine sẽ rộng hơn nữa
Trong thời đại con người không hiểu sâu code do AI tạo ra bằng code do người viết, sự hiểu biết trực quan về state sẽ ngày càng quan trọng
Dù vậy, trong các framework frontend người ta dường như vẫn ưu tiên reactive state dựa trên store hơn
Bản thân tôi cũng thường dùng đó làm mặc định nên không chủ động đổi, và các thư viện như xstate cũng có cảm giác cú pháp khó học hơn và dài dòng hơn
Nhưng với AI thì rào cản đó gần như giảm mạnh, nên tôi tự hỏi có lý do nào khác mà tôi chưa thấy, hay là statechart đơn giản vẫn chưa đạt đỉnh
Bề mặt API cũng sẽ nhỏ hơn, đường cong học tập thấp hơn, và cả lập trình viên lẫn agent đều sẽ viết dễ hơn
Đồng thời, các frontier model hiện đại đã viết code XState khá tốt rồi
Khi làm dự án https://github.com/xlnfinance/xln, tôi nhận ra mình cần một cách để mô phỏng mạng thật theo cách quyết định
Rồi tôi nghĩ mọi blockchain rốt cuộc đều là replicated state machine, vậy thì có thể bọc mỗi user node bằng một hệ phân cấp state machine 3 tầng theo Runtime -> Entity -> Account hay không
Đây là cấu trúc mà máy bên ngoài kiểm soát hoàn toàn máy bên trong, giống kiểu "blockchain bên trong blockchain" với các mode đồng thuận khác nhau
Sau đó tôi tìm kiếm "hierarchical state machines" và gặp statecharts, và cảm thấy hai ý tưởng này khá giống nhau
Theo tôi, nhiều phần mềm hơn nên dùng phân cấp state machine để giảm những lỗi tệ hại nhất do tính không quyết định gây ra
Trong lĩnh vực ô tô, cách này đã được dùng từ rất lâu
Nếu nhìn vào matlab/simulink, bạn có thể vẽ thuật toán dưới dạng state machine rồi sinh code luôn
Gần đây tôi cũng đã tự triển khai state machine để quản lý một React component khá phức tạp, có cấu trúc đi qua nhiều visual state khác nhau bằng CSS transition
Bản thân state machine không quá khó, nhưng có vẻ mọi người vẫn chưa thật sự quen với cách này
Ở công ty, từ sau khi tôi làm ra trình thông dịch bên trong Postgres, chúng tôi đã chạy mọi quy trình kinh doanh bằng statecharts
Trải nghiệm rất tốt, các quy trình trở nên cực kỳ bền vững trước thay đổi và dù quay lại sau vài năm vẫn rất dễ hiểu
Tôi cũng đã mở mã nguồn thư viện này
https://github.com/kronor-io/statecharts