Image for post
Image for post

ClojureScript is the Triforce of Power

Bobby @ fiskal.app
Dec 30, 2015 · 6 min read

If you like this article, check out my work to solve personal finance at .


A while ago my 8 year old daughter was getting frustrated trying to alphabetize her spelling list. She’s constantly misplacing of the word and starting all over again. Being an opportunistic father, I told her I’d teach her how to tell the computer to do it for her. We opened up a ClojureScript REPL and she wrote her first line of code (sort [“truth” “simple” “powerful” “learn” “happy”]). If an 8 year old can learn basic ClojureScript so can you.

On Capital One’s Level Money team we just use ClojureScript for our front-end JavaScript single page web app. React handles our view layer () and ClojureScript handles the data layer. Our ClojureScript library is called Triforce. If you want to see how our Javascript interacts with ClojureScript, check out our other post. ClojureScript is amazing at handling asynchronous work, dependency management, optionally does static type checking, event propagation, data manipulation, writes reusable/refactorable code, low memory footprint and is very performant. First up:

Data Fetching

Image for post
Image for post

That’s it. If you want to enable CORS just add a simple Object (called a “map” in ClojureScript).

Image for post
Image for post

Async

Async work in ClojureScript is a joy. There’s no callback hell or wrapping data in Promises. ClojureScript uses GoLang’s CSP for async. It takes normal synchronous looking code and just parks until that line is done executing. The core construct used for parking is a channel. By default a channel has one piece of data on it and the other side has to “park” there’s something on the channel to take. put! will put data on a channel and take! will take it off (>! is synonymous for put! and <! is for take!). The last concept to understand is async work can only happen inside a go block, which tell us that any code in here does not have to be synchronous.

Image for post
Image for post

So in the code above, it parks until it can take! the response the calls the print function to show the response. When we want the response to be set to a variable we just call let and then a variable name. We can rewrite it like this:

Image for post
Image for post

REST calls

Unfortunately we don’t have a shiny GraphQL or Datomic back-end. We have standard REST endpoints which work just fine. The ClojureScript way to do things is to pass data around to other functions. So for each endpoint we do just that. We’re create a simple map that details the minor differences of each endpoint.

Image for post
Image for post

defn creates a function called “get-repos” with required parameters of hostname, auth and request. Then it calls another function called “call-network” with what we need to for this endpoint.

Now we’ll make a few tweaks to make our network call agnostic. This composability is one of the key features that makes ClojureScript so easy to refactor and reuse; Write less code and change that code quickly.

Image for post
Image for post

Static typing in a loosely typed world

So all that should be fairly simple to do but there a lot that is unspoken here. What is request? What is auth? We can’t have those ambiguities on our public interfaces. We’ll add a library from Prismatic called Schema to give us opt-in static typing when it’s really needed. We use static typing on the edge of our namespaces where additional clarity becomes extremely important. It also doubles as validation when the code runs.

Image for post
Image for post

To conclude our network layer, we’ll update our http call to be a little more dynamic. We deconstruct the function parameters with the {:keys } syntax and then merge the default-params with the custom params for the call. Also notice that the last line of any function is the return value.

Image for post
Image for post

Dependencies

Dependency management isn’t a strong suit of most pure functional languages. In this case, ClojureScript has taken the idea of Classes in OO languages to control dependences better. Internally it’s just a closure in a function. This gives the power of encapsulation with the trade-offs classes can have. At the top level, we express what are our dependencies and how they relate. Then we inject them into components to create a system.

Image for post
Image for post

Next we take the components and put them into a system that manages the hierarchy of dependencies.

Image for post
Image for post

Event Propagation

The last core piece we use is localized caching and event proration. This is important to save data locally to be reused and modified along with the network requests. When the data is changed in any way we need to expose an interface to allow other functions to be triggered as a response to a data change.

For this we use atoms (mutable data) and atom-watchers.

Image for post
Image for post

CLJ->JS

To expose all of this to the JavaScript world we use ^:export on a single function and we wrap the core.async and immutable data in a Promise with mutable JSON.

Image for post
Image for post

Small, simple code is more stable and flexible

ClojureScript’s immutable data and focus on small, simple, pure functions make it very easy to compose and understand what the code is doing. We also handle data transforms and other work locally in isolated functions with just standard ClojureScript map/reduce type functions. ClojureScript has a steep learning curve for those with only an object-oriented background. ClojureScript has kept our View layer in sync while only exposing what’s needed. We’re excited for DataScript, OM Next reconciler and Datomic to make things easier and more flexible for our Data layer running in the browser and on Node.

ClojureScript is a fantastic language! To get up and running fast, check out , read the and use the examples when you get stuck.


Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store