---
date: "2023-11-29"
keywords: ["Hoplon", "ClojureScript"]
title: "10 Years of Hoplon"
id: "urn:uuid:5fd52e3e-8ebc-11ee-b4e3-04ed33d3e45b"
abstract: |
It's been 10 years since the Hoplon ClojureScript libraries were announced publicly on the Clojure Google Group. This is a retrospective.
---
December 18th 2023 will mark a full 10 years since Micha Niskin and I [publicly announced Hoplon](https://groups.google.com/g/clojure/c/gRFyzvRfPa8/m/YIjGA63N_XkJ), a Clojure and ClojureScript framework for building Single-Page Applications (SPAs).
I am pleased to report that while I've been almost totally uninvolved with Hoplon since 2017, the project is very much alive, and remains thoroughly defensible as a means to build SPAs in ClojureScript in 2023.
I thought I would take the opportunity this month to write two short posts about Hoplon. This, the first, is a quick update and design retrospective. In the next, I'll try to capture some of the exciting things happening between Hoplon and [Scittle](https://babashka.org/scittle/) thanks to [Michiel Borkent](https://www.michielborkent.nl/) and [Marcelo Nomoto](https://github.com/mynomoto).
## Hoplon Quickstart in 2023
Hoplon has changed some since we first released it. The biggest change is that it's no longer coupled in any way to the [Boot](https://boot-clj.github.io/) build tool. These days, Hoplon projects can be [quickly scaffolded](https://github.com/hoplon/hoplon#quickstart) and built with the excellent [shadow-cljs](https://github.com/thheller/shadow-cljs).
If you want to understand Hoplon quickly, I recommend [Daniel Neal](https://twitter.com/DanielNeal2)'s [Reactive web apps with Hoplon and DataScript](https://skillsmatter.com/skillscasts/5380-reactive-web-apps-with-hoplon-and-datascript#video). This was the first public presentation of Hoplon's capabilities, and remains my personal favo**u**rite. Despite being given back in 2014, and aside from a few details, the talk remains a viable introduction to the ideas and mechanics of Hoplon.
If you're thirsty for more, and curious in particular about how exactly Hoplon relates to React, I can recommend [Micha Niskin's Hoplon and Javelin, WebDev Alternate Reality](https://www.youtube.com/watch?v=UoZyyo2Bwr8) from 2015.
OK, now on to the retrospective part.
## Two Decent Ideas
Before I get into what Hoplon got right, I must say that not everything about Hoplon is still relevant or has otherwise held up. Requiring use of a new build tool and promoting an XML syntax for ClojureScript are two ideas Hoplon has since set free.
That said, I think we knocked these two things completely out of the park:
1. Strict ("push") propagation of reactive values in Javelin (instead of lazy aka pull).
2. ClojureScript functions for HTML (HLisp).
## Push Propagation
The author of any FRP-spreadsheet-"reactive"-ish thing is confronted with a big decision up front: should updates to the dependency graph be processed immediately after new data is introduced, on write? Or, should the necessary computation happen on demand, when some value of the graph is read?
The first kind of value propagation is variously called "strict" or "push", whereas the second kind is often called "lazy" or "pull". Each way offers a different set of tradeoffs.
Push attributes:
- Mostly static dependency graph
- No conditional dependencies
- Any side-effects occur on write
Pull attributes:
- Dynamic dependency graph
- Conditional dependencies are free
- Any side-effects occur on read
- Multiple writes on the same call stack are implicitly transactional
Back in 2013, "pull" was the preferred approach in the JavaScript ecosystem. Both Meteor.js and Knockout used pull, and were highly influential.
## HLisp
## Dormant but not forgotten: Boot
Hoplon required a build tool because we thought that XML syntax like JSX for ClojureScript was good to have, and even the best default.
Of course, our XML syntax for ClojureScript wasn't JSX exactly, as we conceived of our "hlisp" syntax independently. However, we saw in XML syntax the ability to represent Hoplon programs using a syntax that cooperated with other web development tools, and that was hypothetically friendlier to designers.
Ultimately, our effort to promote a new syntax served only to raise red flags with the Lisp faithful, while simultaneously not especially wowing the designers we worked with, as sizeable ClojureScript knowledge was still requisite to working with the XML.
Thus, the build tool requirement was probably a net fail that dissuaded many potential early adopters.
Post-separation, with Boot 2.0, Boot took on a life of its own independently of Hoplon, but now lacks a maintainer and has gone dormant.
## Talking to the Server
In our early Hoplon apps we struggled
In my opinion, two particular design decisions held up remarkably well:
1. Strict (not lazy) reactive value propagation
FRP/spreadsheet/"reactive" library authors must choose between either strict or lazy propagation semantics. Strict propagation means that any computation needed to produce derivative values is performed when new values are written. Lazy propagation means that computation is performed "on demand", when an attempt is made to read values. A little work is still usually performed on write, such as marking root values "live".
The vast majority of reactive libraries intended for use with UIs are lazy. I think this is for two reasons:
a. Lazy systems are more tolerant of dynamic dependency graphs. Computation is never performed for subgraphs the values of which are never demanded by the consuming system. Since the consuming system is usually a UI framework with knowledge of what is and isn't visible to the user, lazy systems
2. Code (not data) for HTML
The first decision, to separate data representation from DOM/UI concerns,
I thought it would be fun to reflect a little on Hoplon's beginnings and history, and also to share some enthusiasm for the future of Hoplon and ClojureScript.
# Setting the Stage: ClojureScript
ClojureScript was [released in 2011](https://clojure.org/news/2011/07/22/introducing-clojurescript) at a meeting of the NYC Clojure group. I was fortunate to be in attendance, and also to have had the opportunity to work a little on and with ClojureScript before it was publicly released. I remember the atmosphere was electric, both in-person and on-line.
Rich's choice to integrate tightly with Google Closure and its advanced compiler was bold, and from the perspective of anyone doing JavaScript professionally at the time, came from completely out of left field. Momentum in the JavaScript community at the time was all around [CoffeeScript](https://coffeescript.org/) and [Backbone](https://backbonejs.org/). React wouldn't be released until almost two years later, in May 2013, or really make waves until [Pete Hunt's talk about it]( https://www.youtube.com/watch?v=x7cQ3mrcKaY) shortly thereafter.
# The DOM Problem
While ClojureScript paved over JavaScript's most egregious footguns and simultaneously imported Clojure's most powerful tools to the browser ecosystem, it didn't promote or imply a new way to deal with the DOM.
Every large stateful JavaScript program needs to "maintain" the DOM as its used, in order to ensure that the interface is in a state compatible with the wider state of the program. When ClojureScript appeared, there were approximately two popular approaches to this: jQuery and MVC.
- jQuery was generally used to implement an immediate-mode approach, where all or part of the DOM were cleared and re-painted as JavaScript state changed.
- MVC (typified by Backbone, but there were many others) promoted declarative descriptions of connected data objects, and changes to the the graph of data objects were synchronized in some managed way to the DOM.
These approaches mapped roughly to the two main approaches of UI implementation:
1. [Immediate-mode](https://en.wikipedia.org/wiki/Immediate_mode_GUI), where the entire UI is blown away and repainted speculatively on every domain data change.
1. [Retained-mode](https://en.wikipedia.org/wiki/Retained_mode), where graphics objects (DOM objects) are long lived and updated surgically as the domain data beneath them changes.
The tradeoffs were something like these:
- jQuery worked great for small apps, but the immediate-mode paradigm would break down as app data became large and re-painting became noticeably slow.
- MVC generally worked better for apps with a lot of data. However, MVC imposed a more rigid application data structure, among other constraints.
There were other cool things that didn't fit in these categories, like [Knockout](https://knockoutjs.com/) and [Meteor](https://www.meteor.com/), but they weren't as popular.
React came later and showed the immediate-mode way could scale, with the idea of a Virtual DOM, but not before [Conrad Barski](http://www.lisperati.com/) showed the same thing — in ClojureScript! in 2012! — with his [Webfui](https://www.youtube.com/watch?v=HeI5-D7SQe8).
## Enter Hoplon
From 2011-2012, while I was still writing ClojureScript and CoffeeScript with boring approaches to DOM manipulation, Micha Niskin was working on what would eventually become Hoplon.
He was working at a startup called The Fresh Diet and needed a way to separate the business logic of a menu item selection app from the way it looked. Other than MVC, there weren't many ideas floating around for representing domain data separately from its presentation, and that worked in the web.
Eventually I joined Micha at The Fresh Diet and helped him refine the ideas into the first version of Hoplon, which consisted of at least these parts:
- [Boot](Boot), the build tool
- [Castra](https://github.com/hoplon/castra), the server-side RPC library
- [cljson](https://github.com/tailrecursion/cljson), the RPC wire format
- [Javelin](https://github.com/hoplon/javelin), the client-side reactive data library
- HLisp, the DOM abstraction
**Boot** came about because Micha and I were dissatisfied with other ClojureScript build approaches of the time, and also because we thought an HTML syntax frontend to ClojureScript was valuable for designer buy-in. While this pre-saged [JSX](https://en.wikipedia.org/wiki/JSX_(JavaScript)), we ultimately dropped the special syntax for lack of interest, including our own.
**Castra** was a Ring middleware that exposed Clojure vars to the client with a metadata-based authentication layer.
**cljson** came about because we found it unacceptablly slow to read large chunks of EDN in the browser. Rich solved this better, and comprehensively, a little later with [Transit](https://cognitect.com/blog/2014/7/22/transit).
**Javelin** is a way to stitch together graphs of Clojure data through functions, and introduced the _cell_ abstraction. Contrary to most such things then and now, Javelin is completely DOM-agnostic.
**HLisp** was the DOM integration piece, and did the work of mapping cell values to DOM objects. Unlike React, the DOM objects here are retained, and so HLisp features no vdom.
## Rocking Hoplon
Hoplon's release was met with some enthusiasm, but also a lot of skepticism. Imposing a new build tool, Boot, was a lot to ask of prospective users. Our promotion of an alternative XML-like syntax, while optional, also didn't exactly endear us to the Lisp faithful.
The first, and my favorite, public presentation of Hoplon's capabilities was [given by Daniel Neal](https://skillsmatter.com/skillscasts/5380-reactive-web-apps-with-hoplon-and-datascript#video) in 2014.
A little later, in 2015, Micha Niskin gave a talk called [Web Dev Alternate Reality](https://www.youtube.com/watch?v=UoZyyo2Bwr8) that compares Hoplon's DOM approach to that of React's virtual DOM.
## The Adzerk Years
Micha and I both ended up at Adzerk (now Kevel) where we used Hoplon and ClojureScript extensively. In particular, we (honestly, mostly Micha) built the next generation of a large ad management interface.
## The Quiet Years
I left Adzerk in 2017 and stopped using either Hoplon or ClojureScript professionally at that time. Third-party ClojureScript tooling had improved significantly, and we dropped the HLisp XML syntax, obviating the case for Boot or its necessity in using Hoplon. Despite that change, I feel that many folks continued to steer clear of Hoplon, remembering only that it had its own weird build tool. I don't blame them.
Boot, in particular version 2.0, enjoyed a degree of popularity outside of Hoplon, but as a piece of JVM software with OS and filesystem sensitivity, required significant upkeep. With Micha occupied with other things at Adzerk, and me out of the loop entirely, Boot development eventually slowed to a halt, and the project is now dormant.
Nonetheless, many intrepid souls kept trying and using Hoplon, filtering into the [#hoplon Slack channel](https://app.slack.com/client/T03RZGPFR/C08BDAPRA).
## The Renaissance
I am happy to report that 10 years later, Hoplon is *very much alive!* In particular, Javelin and Hoplon, the reactive and DOM parts, now both run entirely in the browser via scittle, a browser-based ClojureScript interpreter.
It's never been easier to use Hoplon, regardless of your build tool.
The front-end APIs of Hoplon, Javelin cells and HLisp operators, are stable, and