{"id":18822934,"url":"https://github.com/adaptiveconsulting/rfqstatemachine","last_synced_at":"2026-03-08T07:31:41.077Z","repository":{"id":75325956,"uuid":"21063645","full_name":"AdaptiveConsulting/RfqStateMachine","owner":"AdaptiveConsulting","description":"A sample event driven state machine using Stateless","archived":false,"fork":false,"pushed_at":"2014-06-25T12:42:09.000Z","size":1190,"stargazers_count":68,"open_issues_count":0,"forks_count":24,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-14T01:35:58.608Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AdaptiveConsulting.png","metadata":{"files":{"readme":"README.html","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-21T08:04:43.000Z","updated_at":"2025-02-19T20:26:03.000Z","dependencies_parsed_at":"2023-02-26T17:30:32.812Z","dependency_job_id":null,"html_url":"https://github.com/AdaptiveConsulting/RfqStateMachine","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AdaptiveConsulting/RfqStateMachine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdaptiveConsulting%2FRfqStateMachine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdaptiveConsulting%2FRfqStateMachine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdaptiveConsulting%2FRfqStateMachine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdaptiveConsulting%2FRfqStateMachine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AdaptiveConsulting","download_url":"https://codeload.github.com/AdaptiveConsulting/RfqStateMachine/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdaptiveConsulting%2FRfqStateMachine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30248862,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T05:41:50.788Z","status":"ssl_error","status_checked_at":"2026-03-08T05:41:39.075Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T00:52:08.963Z","updated_at":"2026-03-08T07:31:41.062Z","avatar_url":"https://github.com/AdaptiveConsulting.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003eRFQ State Machine\u003c/h1\u003e\n\n\u003cp\u003eWe highlighted quite a few techniques to deal with reactive systems in \u003ca href=\"https://github.com/AdaptiveConsulting/ReactiveTrader\"\u003eReactive Trader\u003c/a\u003e. There is another one, that we commonly use, that was not demonstrated. \nA \u003cem\u003estate machine\u003c/em\u003e is a simple yet powerfull way of decomposing some functionality into \u003cem\u003estates\u003c/em\u003e and a set of valid \u003cem\u003etransitions\u003c/em\u003e between them. \nWhen you find yourself dealing for instance with user input and/or server events and see lots of branching in your code (if/switch statements) on some _state variables, chances are high that a statemachine could be introduced to simplify things.\u003c/p\u003e\n\n\u003cp\u003eIn this post we will look at a concreate usecase, we will define a state machine for it and we will see how we can organise our code around the state machnine and interact with it. I've also created a \u003ca href=\"https://github.com/AdaptiveConsulting/RfqStateMachine\"\u003ecompanion GitHub project\u003c/a\u003e where you can find the \nfull example.\u003c/p\u003e\n\n\u003ch2\u003eExample: RFQ workflow\u003c/h2\u003e\n\n\u003cp\u003eIn finance Request For Quote (RFQ) is a common mechanism used to request a price electronically: the client submits a request to the pricing server. \nAt some point the server provides a quote (or a serie of quotes) and the client can decide to execute (HIT the price) or pass (cancel).\nWe are going to build a state machine that would live client side, in some UI application like \u003ca href=\"https://github.com/AdaptiveConsulting/ReactiveTrader\"\u003ereactive trader\u003c/a\u003e, to control the state of a RFQ.\u003c/p\u003e\n\n\u003cp\u003eThe following diagram describes the different states of the RFQ and the possible transitions.\u003c/p\u003e\n\n\u003cp\u003e\u003cimg src=\"https://raw.githubusercontent.com/AdaptiveConsulting/RfqStateMachine/master/StateMachine.PNG?token=1256913__eyJzY29wZSI6IlJhd0Jsb2I6QWRhcHRpdmVDb25zdWx0aW5nL1JmcVN0YXRlTWFjaGluZS9tYXN0ZXIvU3RhdGVNYWNoaW5lLlBORyIsImV4cGlyZXMiOjE0MDQwMzI4NDN9--33bd8eef1b0c9c1064f9d1844ed8f99cb19b96b4\" alt=\"state machine diagram\" /\u003e\u003c/p\u003e\n\n\u003cp\u003eThis is a visual representation of a statemachine, it contains \u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003estates:\n\u003cul\u003e\n\u003cli\u003ean initial state (at the top),\u003c/li\u003e\n\u003cli\u003eintermediate states (requesting, quoted, Executing)\u003c/li\u003e\n\u003cli\u003eterminal states (Error, Done, Canceled)\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eand transitions between states (arrows)\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eI find those diagrams very helpfull to think about the system, while building them I will generally go through all the states I already discovered and ask myself the following questions: \u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003ecould anything else happen in this state? \u003c/li\u003e\n\u003cli\u003eAny unhappy path? (ie. timeout, error, etc) \u003c/li\u003e\n\u003cli\u003eDo we have a representation of this particular state for the corresponding UI? (if you are building a UI).\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eThose diagrams are also very usefull to discuss with non developers: business people, UX, etc.\u003c/p\u003e\n\n\u003ch2\u003eFrom diagram to code\u003c/h2\u003e\n\n\u003cp\u003eStatemachines can be implemented in many differents ways, either from scratch or using some library. \nFor any decent size statemachine I tend to use \u003ca href=\"https://code.google.com/p/stateless/\"\u003eStateless\u003c/a\u003e but the recommendations that follow would stand for any library or hand written statemachine.\u003c/p\u003e\n\n\u003cp\u003eI like to define state machines in a single place: I find that spreading the definition accross multiple files/classes makes it harder to understand.\u003c/p\u003e\n\n\u003cp\u003eStateless offers a nice fluent syntax to define states and possible transitions. \u003c/p\u003e\n\n\u003ch3\u003eDefining states\u003c/h3\u003e\n\n\u003cp\u003eThe first thing we need to do is to define the set of states, we can use an enum for that:\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003ecsharp\npublic enum RfqState\n{\n    Input,\n    Requesting,\n    Cancelling,\n    Cancelled,\n    Quoted,\n    Executing,\n    Error,\n    Done\n}\n\u003c/code\u003e\n\u003ca href=\"https://gist.github.com/odeheurles/9160c1b3e0687d3ebf38#file-rfqstates\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003ch3\u003eEvents\u003c/h3\u003e\n\n\u003cp\u003eThen we define the events which will trigger transitions between states. In our case those are events coming from the client or from the server. \u003c/p\u003e\n\n\u003cp\u003eAgain we can use an enum to define those events.\u003c/p\u003e\n\n\u003cp\u003e```csharp\npublic enum RfqEvent\n{\n    UserRequests,\n    UserCancels,\n    UserExecutes,\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eServerNewQuote,\nServerQuoteError,\nServerQuoteStreamComplete,\nServerSendsExecutionReport,\nServerExecutionError,\nServerCancelled,\nServerCancellationError,\n\nInternalError,\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e}\n```\n\u003ca href=\"https://gist.github.com/odeheurles/14bbd2a0b8040a808356#file-rfqevent\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003cp\u003eI like to prefix those events with their origin, just to makes things explicit (here we have 'Server', 'User', 'Internal')\u003c/p\u003e\n\n\u003cp\u003eAs you can see events coming from the server always expose a happy path (for instance ServerNewQuote when the server sends a new quote) and at least one corresponding error event (ServerQuoteError).\u003c/p\u003e\n\n\u003cp\u003e\u003cimg src=\"https://raw.githubusercontent.com/AdaptiveConsulting/RfqStateMachine/master/Components.PNG?token=1256913__eyJzY29wZSI6IlJhd0Jsb2I6QWRhcHRpdmVDb25zdWx0aW5nL1JmcVN0YXRlTWFjaGluZS9tYXN0ZXIvQ29tcG9uZW50cy5QTkciLCJleHBpcmVzIjoxNDA0MDMyOTYxfQ%3D%3D--f635d386ef4ee480652de98f62d9903fc2660e25\" alt=\"Components\" /\u003e\u003c/p\u003e\n\n\u003cp\u003eYou will also often have internal events, for instance a timer expiring can raise an internal event to trigger a state transition.\u003c/p\u003e\n\n\u003cp\u003eEvents may or not carry some data: for instance UserRequests event needs to contain the description of the product being priced.\nFor those events requiring parameters it is useful to define strongly typed events. \u003c/p\u003e\n\n\u003cp\u003eThis is how we declare them with Stateless, for instance for the ServerSendsQuote event:\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003ecsharp\n_rfqEventServerSendsQuote = _stateMachine.SetTriggerParameters\u0026lt;IQuote\u0026gt;(RfqEvent.ServerNewQuote);\n\u003c/code\u003e\n\u003ca href=\"https://gist.github.com/odeheurles/dea91fa626e6b468ef07#file-stronglytypedevent\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003ch3\u003eDefining transitions\u003c/h3\u003e\n\n\u003cp\u003eNow we can define transitions. For each state we define which events are allowed and when they are triggered to which state we will transition.\nThis is very straight forward with stateless:\u003c/p\u003e\n\n\u003cp\u003e```csharp\n_stateMachine.Configure(RfqState.Input)\n             .Permit(RfqEvent.UserRequests, RfqState.Requesting);\u003c/p\u003e\n\n\u003cp\u003e_stateMachine.Configure(RfqState.Requesting)\n             .Permit(RfqEvent.ServerNewQuote, RfqState.Quoted)\n             .Permit(RfqEvent.UserCancels, RfqState.Cancelling)\n             .Permit(RfqEvent.InternalError, RfqState.Error);\u003c/p\u003e\n\n\u003cp\u003e_stateMachine.Configure(RfqState.Quoted)\n             .PermitReentry(RfqEvent.ServerNewQuote)\n             .Permit(RfqEvent.UserCancels, RfqState.Cancelling)\n             .Permit(RfqEvent.UserExecutes, RfqState.Executing);\u003c/p\u003e\n\n\u003cp\u003e_stateMachine.Configure(RfqState.Executing)\n             .Permit(RfqEvent.ServerSendsExecutionReport, RfqState.Done);\u003c/p\u003e\n\n\u003cp\u003e_stateMachine.Configure(RfqState.Cancelling)\n             .Permit(RfqEvent.ServerCancelled, RfqState.Cancelled);\n```\n\u003ca href=\"https://gist.github.com/odeheurles/2a0ef6112f33d9f2425d\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003ch3\u003eTriggering events\u003c/h3\u003e\n\n\u003cp\u003eWhen the user performs an action or the server sends back a message we want to fire an event at the state machine.\nThis is straight forward with stateless\u003c/p\u003e\n\n\u003cp\u003e```csharp\n// for an event without parameters\n_stateMachine.Fire(RfqEvent.ServerQuoteStreamComplete)\u003c/p\u003e\n\n\u003cp\u003e// for a strongly typed event\n\u003cem\u003estateMachine.Fire(\u003c/em\u003erfqEventServerSendsExecutionReport, executionReport)\n```\n\u003ca href=\"https://gist.github.com/odeheurles/35dae01a47b3d807b97c\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003ch3\u003eDefining actions\u003c/h3\u003e\n\n\u003cp\u003eWhen we send an event to the state machine, two things can happen, the current state has a valid transition for this event or not. \u003c/p\u003e\n\n\u003cp\u003eIf the current state can accept an event we generally want to execute our code at some point around the transition:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003ewhen you enter a state (or re-enter a state since it's also possible to have transitions looping back on the same state)\u003c/li\u003e\n\u003cli\u003ewhen you exit a state\u003c/li\u003e\n\u003cli\u003eupon transition, if you have different behavior to implement for different transitions leading to a same state\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eI tend to apply actions upon entry into a state and use the other variants only in specific scenarios.\u003c/p\u003e\n\n\u003cp\u003e\u003cstrong\u003eImportant: when implementing a statemachine, you want to put all your logic inside those actions (on state entry, on state exit, on transition) because the state machine has already checked that the incoming event was valid for the current state.\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp\u003eHere is an example with Stateless syntax. When the user requests a quote we want to log the transition and also to perform some logic on entry in the requesting state:\u003c/p\u003e\n\n\u003cp\u003e```csharp\n\u003cem\u003estateMachine.Configure(RfqState.Requesting)\n                .OnEntry(LogTransition)\n                .OnEntryFrom(\u003c/em\u003erfqEventUserRequests, OnEntryRequesting)\n                .Permit(RfqEvent.ServerNewQuote, RfqState.Quoted)\n                .Permit(RfqEvent.UserCancels, RfqState.Cancelling)\n                .Permit(RfqEvent.InternalError, RfqState.Error);\u003c/p\u003e\n\n\u003cp\u003eprivate void OnEntryRequesting(IQuoteRequest quoteRequest)\n{\n    // here goes the code to send a quote request to the server\n}\n```\n\u003ca href=\"https://gist.github.com/odeheurles/fce8fdb029501f754df4\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cstrong\u003eTip\u003c/strong\u003e: you can think of the OnExit action as a Dispose() method for the corresponding state. It is very useful if for instance you had a timer runing during that state and you need to cancel it or you have whatever active Rx query that you want to unsubscribe.\u003c/p\u003e\n\n\u003ch3\u003eHandling errors\u003c/h3\u003e\n\n\u003cp\u003eWhen an event is fired at the state machine and the state machine has no transition defined for this event in the current state we can implement 2 behaviors: ignoring the event or raising an exception.\u003c/p\u003e\n\n\u003cp\u003eBy default Stateless will raise an exception but you can handle yourself invalid transitions:\u003c/p\u003e\n\n\u003cp\u003e```csharp\n_stateMachine.OnUnhandledTrigger(OnUnhandledTrigger);\u003c/p\u003e\n\n\u003cp\u003eprivate void OnUnhandledTrigger(RfqState state, RfqEvent trigger)\n{\n    var message = string.Format(\"State machine received an invalid trigger '{0}' in state '{1}'\", trigger, state);\n    Console.WriteLine(message);\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e_rfqUpdateSubject.OnError(new ApplicationException(message));\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e}\n```\n\u003ca href=\"https://gist.github.com/odeheurles/a0f838e4b83e53f88379\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003cp\u003eYou can also ignore individual events on a state with the Stateless \u003cem\u003e.Ignore()\u003c/em\u003e method.\u003c/p\u003e\n\n\u003ch3\u003eEncapsulation\u003c/h3\u003e\n\n\u003cp\u003eWe have now defined everything we need for the state machine:\n - states,\n - events and strongly typed events\n - possible transitions\n - actions on entry and on exit\n - error handling\n - how to fire events at the state machine\u003c/p\u003e\n\n\u003cp\u003eThe next step is to encapsulate everything in a single class so we don't leak the specifics of Stateless and the state machine to the rest of our code.\u003c/p\u003e\n\n\u003cp\u003eFor our example I've created a class \u003cstrong\u003eRfq\u003c/strong\u003e that you can find \u003ca href=\"https://github.com/AdaptiveConsulting/RfqStateMachine/blob/master/RfqStateMachine/Rfq.cs\"\u003ehere\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eThis class implements the following interface:\u003c/p\u003e\n\n\u003cp\u003e```csharp\npublic interface IRfq : IDisposable\n{\n    void RequestQuote(IQuoteRequest quoteRequest);\n    void Cancel(long rfqId);\n    void Execute(IExecutionRequest quote);\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eIObservable\u0026lt;RfqUpdate\u0026gt; Updates { get; } \n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e}\n```\n\u003ca href=\"https://gist.github.com/odeheurles/911258d648ceb3f1eaba\"\u003egist\u003c/a\u003e\u003c/p\u003e\n\n\u003cp\u003eThis is very much CQRS style: a view model can call the RequestQuote, Cancel and Execute methods which act as Commands and internally fire events. Don't get confused by 'Command' and 'Event', they are the same, it's just that in the context of CQRS we talk about commands and for state machine I've use the term event from the beginning (we could use message as well if we want).\u003c/p\u003e\n\n\u003cp\u003eThe view model also subscribes to the Updates stream which will notify when the state machine transitions and provide the relevant data (a quote, an execution report, etc).\u003c/p\u003e\n\n\u003cp\u003eYou can find some sample usage of this API in the \u003ca href=\"https://github.com/AdaptiveConsulting/RfqStateMachine/blob/master/Tests/RfqStateMachineTests.cs\"\u003etest project\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003e\u003cimg src=\"https://raw.githubusercontent.com/AdaptiveConsulting/RfqStateMachine/master/Encapsulation.PNG?token=1256913__eyJzY29wZSI6IlJhd0Jsb2I6QWRhcHRpdmVDb25zdWx0aW5nL1JmcVN0YXRlTWFjaGluZS9tYXN0ZXIvRW5jYXBzdWxhdGlvbi5QTkciLCJleHBpcmVzIjoxNDA0MTMyMzkwfQ%3D%3D--33adc46c203e50b1adbb54dcdbc27c98faf1d0be\" alt=\"Encapsulation\" /\u003e\u003c/p\u003e\n\n\u003ch3\u003eConcurrency\u003c/h3\u003e\n\n\u003cp\u003eI would strongly suggest to get your state machine running on a single thread. In my example the view model MUST call from the UI thread (Dispatcher) and I explicitly marshal server side initiated messages to the UI thread using ObserveOn in my Rx queries.\u003c/p\u003e\n\n\u003cp\u003eIf you are not building a UI you should consider running your statemachine in an actor or an event loop: anything that will guarantee that calls made on the state machine are sequenced and do not have to be synchronized.\u003c/p\u003e\n\n\u003cp\u003eWhy? Simply because otherwise you will have to synchronise all accesses to the state machine (and other states in your encasulating class) with locks. If for instance you take a lock while firing an event, all the actions will run under that lock. Those actions will likely call on code external to this class and you now have risks of deadlock.. \u003c/p\u003e\n\n\u003ch3\u003eRace conditions\u003c/h3\u003e\n\n\u003cp\u003eNever forget that in an event driven system things can happen in an order you do not expect, and your state machine should be ready for that.\u003c/p\u003e\n\n\u003cp\u003eHere is an example, which use a slightly different protocol for the RFQ:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003ethe user receives a valid quote Q1 from the server\u003c/li\u003e\n\u003cli\u003ethe server sends an invalid quote message (to invalidate the quote because the market has moved or for whatever reason)\u003c/li\u003e\n\u003cli\u003ethe user HIT the quote Q1 (executes) while the invalidation message is still in flight (ie. still travelling somewhere between the server and the client)\u003c/li\u003e\n\u003cli\u003ethe state machine transitions to the state 'Executing'\u003c/li\u003e\n\u003cli\u003ethe client receives the invalidate quote message/event but the state machine is in a state where you might not have expected to receive such event...\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eBecause there is a propagation delay between a client and a server, you will see behaviors in your systems that you did not thought about initially and that you have probably not covered in your unit tests. \u003c/p\u003e\n\n\u003cp\u003eWhat to do about it?\u003c/p\u003e\n\n\u003col\u003e\n\u003cli\u003eFor each state go through the list of all possible events and ask yourself: could this one possibly happen in this state? If it does, how should it be handled?\u003c/li\u003e\n\u003cli\u003eLog all transitions of the state machine and all events fired. This is priceless while investigating for such issues.\u003c/li\u003e\n\u003cli\u003eUnit testing is not enough, you will need to test in a deployed environment.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch3\u003eVisualisation\u003c/h3\u003e\n\n\u003cp\u003e\u003ca href=\"http://weareadaptive.com/author/matt/\"\u003eMatt\u003c/a\u003e wrote \u003ca href=\"https://github.com/AdaptiveConsulting/RfqStateMachine/blob/master/Tests/StateMachineDiagramPrinter.cs\"\u003esome code\u003c/a\u003e which reflectively retrieves the definition of the State machine and is able to produce a graph definition in \u003ca href=\"http://www.graphviz.org/doc/info/lang.html\"\u003eDOT code\u003c/a\u003e  (a language to represent graphs).\u003c/p\u003e\n\n\u003cp\u003eTo generate a diagram from the output of the graph generation code, you can either download \u003ca href=\"http://www.graphviz.org/\"\u003eGraphviz\u003c/a\u003e and run it locally, or simply use an \u003ca href=\"http://sandbox.kidstrythisathome.com/erdos/\"\u003eonline GraphViz webapp\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eThis is the output I got using the webapp:\u003c/p\u003e\n\n\u003cp\u003e\u003cimg src=\"https://raw.githubusercontent.com/AdaptiveConsulting/RfqStateMachine/master/Generated.png\" alt=\"Generated diagram\" /\u003e\u003c/p\u003e\n\n\u003ch2\u003eWrap up\u003c/h2\u003e\n\n\u003cp\u003eIt takes a bit of time to get your head around state machines but once you get it those little things yield very nice clean code and it's also very simple to introduce new state and transitions if you follow the few guidelines we discussed here.\u003c/p\u003e\n\n\u003cp\u003eThere are a few other things I'd like to talk about with state machines (for instance visualising them while the system is running, code generation, etc) but we will cover that in a future blog post.\u003c/p\u003e\n\n\u003cp\u003eI would also suggest to have a look to the work of Pieter Hintjens (ZeroMQ) on state machines and code generation, he has done some \u003ca href=\"https://github.com/zeromq/zproto\"\u003every cool stuff in this area\u003c/a\u003e \u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadaptiveconsulting%2Frfqstatemachine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadaptiveconsulting%2Frfqstatemachine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadaptiveconsulting%2Frfqstatemachine/lists"}