I have been doing interactive programming in ClojureScript recently. After having spent some time with it, I can easily say that when I return to projects that don’t have an interactive workflow I feel like I am in the stone ages.
When I say interactive programming I explicitly mean that as I make changes to a ClojureScript file, the compiled javascript makes its way to the browser so that I can see changed program behavior almost immediately as I save the file. This workflow is distinctly different from REPL based interactivity, where you cherry pick what to reload and what processes to execute.
I recently hunkered down and wrote a leinigen plugin/browser client combo that handles the reloading of changed files and enables this interactive workflow.
Flappy Bird live on figwheel
Here is a demo of changing flappy bird code live:
Can’t wait?
So … just in case you don’t want to read the rest of the post (I totally understand). You can get the above demo from github:
git clone https://github.com/bhauman/flappy-bird-demo.git
After it has downloaded, cd
into the flappy-bird-demo
directory and
type:
lein figwheel
You can now goto localhost:3449/index.html
and open up
src/flappy_bird_demo/core.cljs
your favorite editor and start
coding. Make sure you open the development console so you can get
feedback about code reloads.
Keep in mind this is all pre-post-pre-alpha stuff, so when you find bugs in figwheel please let me know.
The flappy bird code is rough and has many refactoring opportunities. I wish I could say I did that on purpose.
Suggestions:
- make the game display the nth Fibonacci of your score (thanks to @KanYang)
- change the game play parameters (make the game harder or easier)
- change the pitch of flappy in relation to to his velocity
- make a protocol called animate and have a list of things that you call animate on
- make flappy flap his wings
Greenfield?
Want to jump into live coding? Try the leinigen template:
lein new figwheel hello-world
Not magic
Figwheel only causes the browser to reload the correct files and offers a reload hook that you can use. Writing reloadable code is up to the programmer.
When I refer to reloadable code I am talking about code that can be evaluated in the same runtime repeatedly without disrupting the state of the running program.
Why interactive programming now?
Writing reloadable code has traditionally been a daunting software requirement. In an imperative system, it requires scrupulous thinking about how to persist state though behavior changes. This often involved serializing the state out of stateful components and then reinitializing new components with the serialized state.
Recent events have significantly reduced the cost of writing reloadable code in the browser. The first was the advent of ClojureScript and its accompanying philosophy of immutable state and how it should be separate from behavior. Much of ClojureScript code is innately reloadable. You can reload pure function definitions all day long. They are side-effect free and not tied into the local state of a running system.
The second thing that happened is React. Hooking into browser APIs and creating event based processes is the weak point of writing reloadable code and is normally not optional. If you add an event listener to something, you better remove it and add it back again on code reload (the same serialization strategy mentioned above).
React allows you to write functions that express what the DOM state should be given the current domain state. This movement from imperative expression to functional expression is huge and allows us to write reloadable code without having to think too much about it.
Here’s an example of a React program:
That program is almost reloadable as is. In fact, it is reloadable if you don’t care about reseting the state back to zero on every reload. While still valuable this is not the type of reloading I am trying for, I want the state of the system to survive reload.
If we reload the above program counter
is going to get redefined on
each reload which resets the state of the system and will continually
create new atoms which then get bound by add-watch
. Not the end of the
world, but also not the desired behavior.
This is easy to solve by only defining counter
once. You can do this
by changing the first line in the above program to this:
Now when the code is reloaded it won’t be redefining and reseting the state of the system on reload. The burden of making the above program reloadable is extremely small.
Now that the burden of writing reloadable code has shifted, the cost
benefit of doing interactive programming has shifted along with it. If
you tell me that I can experience live behavior changes in the browser
as I type and all I have to do is defonce
the reference to my
program state I’d call that a clear win.
I feel like the time for interactive programming is now. Give it a try, you won’t regret it.
Question for the reader
Is reloadable code inherently better code?
Links
- lein-figwheel
- Play the flappy bird game
- Flappy bird demo code
- React
- Local State is Poison
- The awesome Om framwork
- The Functional Final Frontier
- Light Table