Dec 10, 2016 • Arnout Roemers
In a previous blog post the mount-lite
library was introduced.
In short, it explained why I like the premise of mount,
and what moved me to create a spin-off.
This time I want to talk about what has changed between the 0.9.x
versions of that blog post and the recently released 2.0.0
version.
With the 0.9.x
versions, the mount-lite
library used to be bigger.
It was different from the original mount
, with features such as a composable data-driven API, bindings, parallel starting and stopping, starting and stopping “up to” a particular state, automatic dependency graphs, and cleaner substitutions.
In the mean time, the original mount
has dropped unnecessary features, has also created a composable API, and is improving substitutions as well.
It is good to see this, as mount
is more popular, and all kudos should still go to the original author of course.
The 2.0.0
version introduces the ability to run multiple systems of states simultaneously.
In other words, a single defstate
can be started multiple times in different contexts.
One major reason for introducing this feature, is to be able to run test suites in parallel.
As this is a breaking change, it was a good opportunity to get rid of the excess, based on experience in several larger projects.
With the new version, mount-lite
still has it’s own take and feature set with respect to the original mount
.
In short, apart from the multiple-instances feature, the following has changed:
@
or deref
when using a started state.
This enables the multiple-instances feature.bindings
feature and the parallel
start/stop feature have been removed, as those were rarely used and only added complexity.only
and except
features have been removed as well, as the up-to
feature is all you (should) need.
The unique up-to
feature is now standard. The only
and except
features could be harmful - they could leave your system in a bad state - and they rarely used.
They could get your system in a bad state.start
function.
This means that you don’t have to change anything within the (start)
expression or its immediate vicinity.Because of these feature changes, the API has been trimmed down to a simple mininium, not requiring it to be composable or data-driven.
In my experience, most mount-lite
users were not the power user I expected them to be.
So many options the data-driven composabe API offered, were rarely used.
The new API comprises of only the bare minimum of features that are actually used.
The API has become simpler because of this, and therefore easier to learn and understand.
The API now comes down to:
(defstate ...)
, only having a :start
and :stop
expression.(start)
and (stop)
, or starting and stopping up to a certain state var using (start #'my-state)
or (stop #'my-state)
.(status)
.(with-substitutes [#'my-state (state ...)] ...)
macro, which can be nested.(with-session ...)
macro.That’s it.
If you can’t live without the removed features, know that you can add some of them yourself by using the extension point mount-lite now offers. Otherwise, keep using the 0.9.x
version, as it will still be supported.
But how do you use that new feature, having multiple systems of states simultateously living next to each other?
The mount-lite
library does this in a transparent way, i.e. there is no difference in how the library is used, whether this feature is utilized or not.
This is in contrast with the yurt library from the original mount
.
When you just (start)
your states, you start them in the default context.
The entire application accesses those states as normal.
By wrapping your (start)
with the with-session
macro, the thread that is then spawned - and all of its subthreads - will use a new system of states.
The states themselves and the code that uses them does not change a bit.
The states in that session are automatically stopped when the thread is done.
The example below shows how we use the with-session
macro to spin up a new thread and execute its body.
The example starts up two systems of states this way, and the use of CountDownLatch
es ensures the systems run concurrently when printing the value of the foo
state.
The printed output is shown below.
As you can see, two different values are printed, and subthreads use running states from parent threads.
The order in which 1
and 2
are printed, or the order in which stopping
and sub stopping
are printed, might of course be swapped.
The mount-lite
library now truly fulfills the “lite” part. With version 2.0.0
it has gone back to the core of its functionality, based on real world projects and user experience. I hope you like it. The documentation has been updated to reflect this new version, including a migration guide. If you have questions or suggestions, I’d love to hear them, for example on twitter or the #mount channel on Clojurians Slack.
As always, have fun!