This is an experimental repository where I’m working on a more complete integration with Fulcro and statecharts. The idea is to move towards encouraging all application logic live in statecharts, with very few exceptions (e.g. except layout/side-effects on the DOM).
In my own development work there are many cases where a lack of a cohesive unit makes it difficult to manage the application. Some common problems:
-
Application state management, especially when dealing with the traditional idea of URL route. Routes that have nested state, implied by the URL. E.g.
/event/23/subroute/foo
. Switching to a related subroute/event/23/other
needs to track that event 23 is the context. The RESTful re-evaluation of this fact is a terrible source of incidental complexity. Add in bookmarks and browser reload and it is even worse. Managing this with some kind of UI routing system that is composable is "nice" for a certain value of "nice", but in the large it becomes quite messy, with users often using UI hooks and other rendering-based triggers to execute side-effects. The result is write-only code that is very hard to work with, and reason about. -
Complex sequences, like onboarding/subscription management/sign-up. These tasks usually have literally dozens of cross-cutting concerns that are usually very poorly modelled. Statecharts dramatically improve the overall quality of such systems.
My general goals are:
-
Composition of application elements that leverage statecharts:
-
Global top-level statechart where modules can compose in some literal composite state.
-
Invocations for co-located statecharts on components (local reasoning around a component whose statechart can start/stop when that component is active)
-
Routing and all associated logic as part of some statechart, even if it is just a composition by inclusion or invocation.
-
-
Better management of browser-mutable state
-
URL management/history via statechart as a "controlled component", instead of a browser-controlled "stack". Makes much better sense in general for SPAs.
-
-
Visualization/Simulation
-
The ability to see statecharts visually, ideally as an inspect tool that shows current information about running charts. Support in CLJ and CLJS.
-
Some other things that I’m considering:
*
You must compile the CLJS source to run the client. If you want to be able to edit it, just start a shadow-cljs watch:
$ yarn
$ shadow-cljs watch main
if you don’t have yarn
, use npm install
instead.
The Datomic database used in the demo is Datomic Local. It uses an in-memory database, which makes writing an easy-to-run demo simple. To start the webapp in Datomic, use:
$ clj -A:dev
user=> (clojure.core/require 'development)
user=> (development/go)
This will seed the database and start the web server. The development
namespace includes helpers for stopping/starting
and restarting (with code reload) the server-side code.
(development/restart)
will stop the server, reload source, and start the server.
The development I’m doing may make changes to many projects at once (Fulcro, Fulcro RAD, Fulcro, my statecharts library, and this demo). I do not guarantee I will keep everything in sync as far as versions in the deps file go. I personally set the following in my top-level ~/.clojure/deps.edn
:
{:aliases {:f3-dev {:override-deps {com.fulcrologic/fulcro {:local/root "/Users/tonykay/fulcrologic/fulcro"
:exclusions [com.taoensso/sente]}}}
:statecharts-dev {:override-deps {com.fulcrologic/statecharts {:local/root "/Users/username/fulcrologic/statecharts"}}}
:rad-dev {:override-deps {com.fulcrologic/fulcro-rad {:local/root "/Users/username/fulcrologic/fulcro-rad"}
com.fulcrologic/fulcro-rad-sql {:local/root "/Users/username/fulcrologic/fulcro-rad-sql"}
com.fulcrologic/fulcro-rad-semantic-ui {:local/root "/Users/username/fulcrologic/fulcro-rad-semantic-ui"}
com.fulcrologic/fulcro-rad-datomic {:local/root "/Users/username/fulcrologic/fulcro-rad-datomic"
:exclusions [com.datomic/datomic-free]}}}}}
so that in IntelliJ (or at the command line) I can work from local sources for all of them. I try to remember to push SNAPSHOTS daily, but if I forget and you see some missing symbol error or things are broken, that is almost certainly why.
Running shadow and clj would look like this from the command line:
# in one terminal
$ shadow-cljs -A:f3-dev:statecharts-dev:rad-dev watch main
# in another terminal
$ clj -A:dev:f3-dev:rad-dev:statecharts-dev
In IntelliJ, you’d simply make sure to run a CLJ REPL with current classpath, and use the alias checkboxes and +
button in the Clojure Deps tab to set it up.
The MIT License (MIT) Copyright (c), Fulcrologic, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.