Getting an array of "characters" in Clojure

I’m continuing to noodle around in Clojure and needed to split a string into its component characters. If you know your string will be plain-old-ASCII, you can do:

(clojure.string/split "hello" #"")
;; ["h" "e" "l" "l" "o"]

But this gets funny if you want to split up a string that has emoji in it:

(def ghosties "👻👻👻")
(clojure.string/split ghosties #"")
;; ["?" "?" "?" "?" "?" "?"]

This is because emoji are represented by two bytes under the hood, called a surrogate pair. When you split up a string using the empty regex, it spits it on each byte not on each character. This is a problem in Javascript as well.

To solve this problem in Clojure, we need to reach into the Java APIs for manipulating strings and characters:

;; For a given integer codepoint, return the string representation of it
(defn codepoint-to-str [cpt]
  (-> (StringBuilder.)
      (.appendCodePoint cpt)

;; For a given string, split it into codepoints and generate a string
;; for each individual code point.
(defn to-string-array [s]
      (iterator-seq (.iterator (.codePoints s)))))

(to-string-array ghosties)
;; ("👻" "👻" "👻")

Twelve days of Christmas

A fun software challenge has been floating around my social network this holiday season: given a list of gifts, print out the lyrics to The Twelve Days of Christmas. I’ve been itching to write Clojure again lately, and so I decided to use this as an opportunity to get my head back in that world a bit. I wrote the code using a REPL, because that’s a big part of my enjoyment of Clojure.

There are some interesting bits of the challenge that I wanted to solve in a clever way. First, the song uses both cardinal numbers (one, two, three) and ordinal numbers (first, second, third). The simplest way to implement this is to just list out the first twelve cardinals and first twelve ordinals, but I thought it would be fun to use Clojure’s dynamism to pull in a dependency from the Leiningen REPL.

To do that, I first needed to add the lein-exec plugin to my ~/.lein/profiles.clj, which gives access to Leiningen’s pomegranate library.

{:user {:plugins [[lein-exec "0.3.4"]]}}

This gives me access to deps, a function that lets me pull dependencies down from Maven Central. There’s a package by IBM called icu4j which has features for printing cardinal and ordinal numbers:

(use '[leiningen.exec :only (deps)])
(deps '[[ "65.1"]])
(import 'java.util.Locale '

;; set up fns for formatting numbers
(def rbnf (RuleBasedNumberFormat. Locale/ENGLISH RuleBasedNumberFormat/SPELLOUT))
(defn cardinal [n] (.format rbnf n "%spellout-cardinal"))
(defn ordinal [n] (.format rbnf (long n) "%spellout-ordinal"))

I now have cardinal and ordinal functions, which can be called with a number to get the cardinal/ordinal string of that number.

Next, I need to render a list of gifts using cardinal numbers—four calling birds, three French hens, etc—and decided to use Clojure’s dispatch-on-arity and recursion to print out all the gifts passed to it. A multimethod may be more appropriate here, using the length of the passed vector rather than using arity like this. Nevertheless:

(defn gift-lines
  ([gift] (str "  a " gift)) ;; fn for one gift (used on the first day)
  ([gift-1 gift-2]           ;; fn for two gifts (2nd day and later)
    (str "  " (cardinal 2) " " gift-1 "\n  and a " gift-2))
  ([gift-1 gift-2 & gifts]   ;; fn for many gifts (3rd day and later)
    (str "  "
      (cardinal (+ 2 (count gifts))) " " gift-1 "\n"
      (apply gift-lines gift-2 gifts))))

Now, a function that renders a whole verse, which is just adding a prefix of “On the [ordinal] day of Christmas…” to the previous function, then rendering the list of gifts in reverse.

(defn verse [gifts] ;; generate a verse (day) of the song
    "On the " (ordinal (count gifts)) " day of Christmas, my true love gave to me\n"
    (apply gift-lines (reverse gifts))))

And lastly, a function that prints out the whole song, which is a loop that consumes progressively more and more of the list of gifts until it runs out. I could call this function with any number or any list of gifts, and it should absorb the difference gracefully.

(defn song [gifts] ;; print out all verses of the song for the list of gifts
  (doseq [day (range 1 (inc (count gifts)))]
    (println (verse (take day gifts)))
    (println "")))

Calling the song function:

(song [
  "partridge in a pear tree"
  "turtle doves"
  "French hens"
  "calling birds"
  "gold rings" 
  "geese a-laying" 
  "swans a-swimming"
  "maids a-milking"
  "ladies dancing"
  "lords a-leaping"
  "pipers piping"
  "drummers drumming"])


On the first day of Christmas, my true love gave to me
  a partridge in a pear tree
On the second day of Christmas, my true love gave to me
  two turtle doves
  and a partridge in a pear tree
On the twelfth day of Christmas, my true love gave to me
  twelve drummers drumming
  eleven pipers piping
  ten lords a-leaping
  nine ladies dancing
  eight maids a-milking
  seven swans a-swimming
  six geese a-laying
  five gold rings
  four calling birds
  three French hens
  two turtle doves
  and a partridge in a pear tree

A fun little challenge, and a fun thing to do with a Clojure REPL.

He sat in his suit, candy-striped, and poured the bag of beans onto the table.

“There’s a flavour here, the red one, that you’ll really like, and another, the blue one, that you’ll really hate. There are two that are good, one bad and four you’ll be indifferent to. You have to eat them all, and usually in handfuls, not one flavour at a time. That’s your life.”

“And after I Commence there are more red ones and fewer blue ones?”

“Oh no. There are just fewer bland ones, and you never get to the bottom of the bag.”

— from the musical HE SAID HE COULD

Using context in redux-saga

This post originally appeared on the Faraday Blog

At work, we use redux-saga in our client-side webapp because it offers a robust and testable set of tools for managing complex and asynchronous effects within Redux apps. I recently upgraded our version of redux-saga from an embarrassingly old version to the latest, in part to take advantage of a new (but largely undocumented) feature: context.

The problem

I want to be able to write sagas without having to implicitly import any statically-declared singletons. The reason for that is simple: if I’m testing the saga that creates new users, I don’t want to drag along the API layer or the router instance.

There are also a few modules in the codebase that only work in a browser and will fail loudly when I try to run them in mocha. If one of these browser-only modules ends up in an import chain, suddenly my tests start failing for bad reasons. At worst, I have to rethink my testing strategy to include a mock browser environment. I’m lazy and hate testing, and I think mocks are a gross awful code smell that should be avoided at all costs.

The solution

One of redux-saga’s greatest features is that I can test a saga’s behavior without actually executing that behavior, or even really knowing much about the details of how that behavior alters the world. It it should be possible to apply that to dependencies as well. And it is possible in redux-saga 0.15.0 and later using context.

Right now, there are very limited docs for context, but acts as shared value across all sagas that can be read with the getContext effect and written to by the setContext effect. It can also be set when the saga middleware is created by passing a context object as configuration.


Let’s say we’re writing an app that fetches game inventory data from the server using some kind of authentication. We don’t want tokens and authentication to bleed into all our sagas, so we wrap it up in a nice singleton API service:

class ApiService {
  getInventory = () => {
    return fetch('/api/inventory', {
      headers: {
        Authorization: `Bearer ${this.token}`
    }).then(res => res.json())

const api = new ApiService()
api.token = localStorage.token

export default api

Without context, our saga would probably statically import the API singleton:

import { call } from 'redux-saga/effects'
import api from './api' 

export function * fetchInventorySaga () {
  const inventory = yield call(api.getInventory)
  // Do something with the inventory data...

All is well until we try to test it in nodejs/mocha:

import { fetchInventorySaga } from '../src/sagas/inventorySaga.js
// ReferenceError: localStorage is not defined

There is no localStorage in the nodejs global context. We can either pull in a testing harness to change how import api from './api' is resolved, attempt to run the tests in a browser, or roll our own late-binding mechanism so that you don’t need to import API and can pass the API instance in at runtime.

We need to solve the same problem for fetch, because that’s also absent in nodejs.

Or, we could use context. Our saga changes only a little bit:

import { call, getContext } from 'redux-saga/effects'
// No more API import:
// import api from './api' 

export function * fetchInventorySaga () {
  // Get the api value out of the shared context:
  const api = yield getContext('api')

  const inventory = yield call(api.getInventory)
  // Do something with the inventory data...

We can now test the getContext effect just like we would any other redux-saga effect, and we can insert a mock value into fetchInventorySaga at test-time if we need to.

Setting up context in the main application is very straightforward. When you’re creating your saga middleware:

import createSagaMiddleware from 'redux-saga'
import api from './api'

const saga = createSagaMiddleware({
  context: {
    api // our singleton API value

Being able to late-bind singleton values like this has been enormously helpful writing robust tests in a complex codebase. I’ll be steadily migrating the application code to use getContext more frequently, now that I have it as an option.

Human interfaces

Most of my job is building interfaces for humans to interact with a complex data model. A lot of the time, that’s laying out buttons inside a window, showing the right number or text at the right time, or simplifying a firehose of data down to a nice visualization.

User interfaces aren’t just buttons and boxes, though. A user interface is a way to make a complicated thing simpler to manipulate. The way an idea is described also a user interface for thinking about it.

The more incidental complexity it takes to describe an idea, the more difficult it is to manipulate the idea in your head. Here’s a fairly simple problem expressed by a great Persian mathematician al-Khwārizmī from the tenth century:1

What is the square which when taken with ten of its roots will give a sum of thirty nine? Now the roots in the problem before us are ten. Therefore take five, which multiplied by itself gives twenty five, and amount you add to thirty nine to give sixty four. Having taken the square root of this which is eight, subtract from this half the roots, five leaving three. The number three represents one root of this square, which itself, of course, is nine. Nine therefore gives the square.

The above passage is extremely difficult to understand. A senior in high school might now represent this problem and its solution as:

x^2 + 10x = 39
x^2 - 3x + 13x - 39 = 0
(x-3) * (x+13) = 0
x = {3,-13}

(al-Khwārizmī missed the second solution of -13)

There are advantages to both “interfaces” of this math problem: The natural language version requires no special knowledge of any special notation. A person with no knowledge of mathematics, but a knowledge of language, could work their way through this problem with a dictionary.

The compact mathematical notation has significantly more advantages. Once you get past the learning curve of the concise notation, it becomes much easier to symbolically manipulate the problem. Not only is it easier to solve, it’s easy to apply the same solution to many possible problems.

It’s also possible to build higher-order concepts on top of a concise notation. Calculus is a natural byproduct of concise mathematical notation; it was discovered concurrently by both Liebniz and Newton about 15 after the vocabulary of mathematic notation had settled.1

The right abstraction/interface can produce higher-order insights. Fabricating the right kind of interfaces is critical to further innovations. This can be at the expense of easy learnability, which is a problem I don’t know how to solve (or if it even needs to be solved).

  1. This example is lifted from Bret Victor's lecture, Media for Thinking the Unthinkable. It's an excellent talk on the nature of problem solving and building new affordances for our weak monkey brains.
  2. By "settled," I mean that the full set of symbols =, +, −, ÷, ×, as well as notations for exponents, roots, grouping, and so forth. The division symbol was the last to be introduced in 1659, according to this awesome table I found on Wikipedia. These operations existed for centuries before their symbols were commonly used. I don't think it's not a great leap to assume that innovations in notation drove the discovery of calculus, and not the other way around.

The contours of belief

A big problem with conveying a statement of belief is that the actual outline of that belief is fractal in nature. For several months I’ve been working on a piece that tries to describe why I think agile software development is bad for everyone involved in it. But that’s not completely accurate–really, I think the agile manifesto is good, but the practices that have grown up around it are poisonous to a business that adopts it. And even then, some agile practices are valuable, and it’s the constellation of ideas that make up scrum that are so toxic.

As I try to get at the details of my position, clearly explaining it becomes much more difficult. If we imagine a constellation of opinions as a physical territory, it falls victim to the coastline paradox. The alternative is to run roughshod over the contours of what I actually think in service of a useful approximation.

But run roughshod I will. I’ve become paralyzed by nuance, and it’s not helping this particular project.

Using Figwheel with Docker

One of the things I’ve been using a lot lately is Docker. I don’t pretend to be an expert, or even be very enthusiastic about it, but there’s a lot of interesting tooling being built up around it. docker-compose lets you put together large-ish systems using a configuration file, and deploy those configuration files to remote clusters. Working within Docker also means that your development environment closely resembles production, which is a boon.

The other thing I’ve been playing with in my spare time is Figwheel. The ability to live-code user interfaces without losing application state is incredible, and being able to force the application into particular states makes it really easy to test unusual edge cases.

Using Docker and Figwheel together is a bit fiddly, as I have discovered, so I’ve written down the magic incantations to save others (and my future self) the time it takes to figure it out.

It should be easy to retrofit these changes onto an existing project, but I’m going to start with a fresh project here, becasue I think it will illustrate the changes that need to happen more clearly:

lein new figwheel dockerwheel

Now that we have a new project called dockerwheel, we need a Dockerfile. This will be our recipe for plugging into the Docker infrastructure:

FROM clojure

ADD . /clj

# 3449 is default http and websocket port that figwheel uses to communicate
# 7888 is the default nrepl port

RUN lein deps
RUN lein cljsbuild once
CMD lein figwheel
# This command will start figwheel and open a repl socket
# This would need to change for a live environment -- you wouldn't want
# the figwheel socket open in production, but I'll leave that bit as an
# exercise for the reader.

There are also some changes that need to be made to the project.clj configs to get the hostnames/IPs to line up for the Dokcer environment:

;; project.clj
:cljsbuild {
  :builds [{:id "dev"
            :source-paths ["src"]
            :figwheel { :on-jsload "dockerwheel.core/on-js-reload"
                        :websocket-host ""} ;; <--
                        ;; This IP address needs to be the IP to your docker
                        ;; container, otherwise the websocket will attempt to
                        ;; connect to localhost:3449

;; AND:                        
:figwheel {:css-dirs ["resources/public/css"] ;; leave this bit alone
           :nrepl-host  ""
           ;; nrepl only accepts connections from certain IP addresses
           ;; as a secuity measure. Setting this to "" lets incoming
           ;; REPL requests access it from any IP address.
           :nrepl-port  7888
           ;; Nrepl doesn't start if you don't give it a port in the configs
           :repl        false }
           ;; Finally, don't start a REPL when the container is started,
           ;; instead, we want to allow remote connections

Now you can build and start the container:

docker build -f Dockerfile -t dockerwheel .
# this builds the container, it can take a while to pull all the dependencies
docker run -p 3449:3449 -p 7888:7888 -v `pwd`:/clj -it --rm \
  --name dockerwheel dockerwheel
# start the container and wire up the relevant ports

Now you can go to your container’s IP (in this example at port 3449 and see the starter figwheel app. If you want to connect a REPL, hit that same IP at port 7888.


I’ve been meaning to write another blog post for a while now, but life has conspired against me in some of the most exciting and brutal ways possible.

About a month after I posted the last link on Angular 2.0, I gave notice to my former employer. In January, I started at Faraday, a data-driven marketing startup that uses machine learning to help companies locate and contact likely customers. It’s a really exciting place to work; smart people, cool technology, moving fast and a lot of autonomy. Somewhere, I have a draft looking back at the four years I worked for Dealer, and the months I’ve worked for Faraday; it never got published, and probably doesn’t apply anymore.

On Feburary 2nd, my stepfather died suddenly of a heart attack. He was never a father figure to me, but he was a good friend and, in many ways, the kind of person I aspire to be. His death was devastating, to me and my mother. Much of my free time in the last few months has been helping my mother through this crisis.

In the middle of February, my grandfather–my mother’s father–died. He was nearly 100, and his death was somewhat anticipated. Nevertheless, it’s difficult to work through many deaths in the family so close together.

In the beginning of May, the whole Faraday team got together for a week and to get our product ready for a public launch. Hundreds of person-hours were spent that week finishing all the bits that had been put off for months; we polished the parts of the app that weren’t working well, we redesigned the login and signup flow, relaunched the website, built an automated tour of the app, rebuilt parts of our campaign-construction process, and rethought all the indexes in our giant geospatial database.

On May 11, we soft-launched our webapp. Anyone can sign up for an account and explore a nation of demographic data. I encourage you to do so at

In a couple days, I hope to finish a technical blog post about using Figwheel with Docker.

Clojure for the Javascript programmer

What follows is the first entry in what I imagine will be a short series about Clojure, all from the perspective of a someone who writes a lot of Javascript at his day job. This is intended to be a simplified introduction to Clojure. It will become a short presentation to interested engineers where I work. I’ve deliberately simplified and omitted some detail that would be covered by a more-comprehensive resource.

I’ve become a bit infamous among my peers for evangelizing Clojure and the unfamiliar concepts it makes use of. I’m especially interested in ideas that can be ported to more-familiar languages because I believe they make it easier to think about complex software. I believe the easiest way to learn those concepts is to become at least passingly familiar with Clojure.

Clojure can be an intimidating beast from a distance, but up-close it’s not nearly as terrifying. A recent comment by a coworker is summarized by, “Clojure seems really powerful, but when I look at that code I’m totally lost.” I believe this sentiment is rooted in Clojure’s unfamiliar syntax, but the language described by that syntax isn’t very much different from Javascript. Brenden Eich based a lot of Javascript on Smalltalk, which was itself inspired by Lisp. Clojure is a Lisp dialect, so the two languages are distant cousins of one another; while the syntaxes of each language might be wildly different, many of the underlying ideas are the same.

A quick language primer

There are two rules for translating between Javascript and Clojure. The first rule is that parenthesis begin to the left of the function name:

capitalize("hello world")  // => "Hello World"
(capitalize "hello world") ;; => "Hello World"

You can see that the function named capitalize is enclosed by parenthesis, rather than followed by them.

The second rule is that everything is a functional expression. Even mathematical operators are defined as functions, and are enclosed by parenthesis:

2 * 4         // => 8
(* 4 2)       ;; => 8

2 * 4 + 1     // => 9
(+ (* 2 4) 1) ;; => 9

This looks awkward at first, but has the advantage of never being ambiguous about operator ordering.

Clojure has a bunch of built-in literals to describe different types of data, almost all of them should be familiar from Javascript:

  • true, false, nil - The values true, false, and nothing are pretty simple
  • 1000, 1.25 - Numbers look the way you’d expect 1
  • "Hello world" - So do strings
  • :nietzsche - This is a new one. This is called a keyword, and it’s a placeholder value that always means itself. It’s similar to the Symbol type in Ruby, or a Java Enum value. It provides fast equality checking and has a few other uses throughout the language.
  • [ :oranges, :bananas, :pineapples ] - This is a vector of keywords. A vector is basically an array.
  • { :name "Rich Hickey", :employer "Cognitect" } - This is a map. Note that the keys here are keywords, which aren’t strings. Maps in Clojure are like Java-style maps, in that the keys can be of any type.
  • #{ :oranges, :bananas } - This is a set. It’s like a vector, but has only unique items.
  • (fibonacci 5)

The last peculiar thing about Clojure is that it doesn’t reserve very many characters for syntax purposes. The following are all valid names in Clojure: number?, transact!, assoc-in, clj->json, *app-state*, >!.

Why learn Clojure?

“Clojure feels like a general-purpose language beamed back from the near future.” This is how the book Programming Clojure describes the language. Clojure has a constellation of features that will help you build better programs:

The most striking feature to newcomers to the language is how expressive it is. A Clojure program can easily be half as long as the equivalent in other languages, and often even smaller than that. Once you’re comfortable with the standard library, it will be hard to go back to more-verbose languages. Here are two snippets in Javascript that check if an array contains only numbers:

// Naive Javascript:
function areAllNumbers(collection) {
    for(var i = 0; i < collection.length; i++) {
        if(typeof collection[i] !== 'number') {
            return false;
    return true;

// Or, using Javascript's collection methods:
collection.every(function(item) { return typeof item === 'number'; });

The following examples are the same algorithms in Clojure; Even if you’re unfamiliar with the language, it should be possible to see the “bones” of what’s going on:

;; Naive Clojure:
(defn all-numbers? [coll]    
    (empty? coll) true
    (number? (first coll)) (recur (rest coll))
    :else false))

;; And using the Clojure collections library:
(every? number? collection)

Javascript stands out as a very expressive language, and yet the Clojure samples remain significantly smaller. This disparity is only magnified as programs become more complex.

There is an important distinction between conciseness and terseness. Minification or creative “code golf” can make the source code smaller, but at the cost of understandability. This is what I mean by terse. Conciseness is about being able to express an idea intelligibly in a small space, such that it can be composed easily into higher-level concepts.

The next obvious feature is that it’s a functional language, which can be a tough thing to get used to. Much of Javascript is calling functions attached to objects to produce a new state. In Clojure, you call functions against values to produce a new value. If you want to append to an array in Javascript, you use the concat method with the value you want to add, in Clojure you call the conj (short for “conjoin”) with the collection and the value you want to add.2

[1, 2, 3].concat(4); // => [1, 2, 3, 4]
(conj [1, 2, 3] 4)   ;; => [1, 2, 3, 4]

This is also a good time to bring up the excellent standard library Clojure has. Rich Hickey, the author of Clojure, is allergic to re-implementing the same functions for different data types, and the standard library reflects this.

The Clojure standard library is large, but can be used across many data types. The biggest beneficiaries of this approach are collections. Every collection in the language can use the functions that operate on sequences (including strings and maps). The values of the collections are intelligibly coerced into a shared representation that can be easily acted upon:

(first [ 1 2 3 ])         ;; => [ 1 ]
(first { :foo 1 :bar 2 }) ;; => [ :foo 1 ]
(first "Hello")           ;; => \H
(first #{ :red :green })  ;; => :red

I believe most-important feature of Clojure to understand is immutability. In Javascript, strings are immutable—there’s nothing you can do to a string that won’t create a new string as a result. If you call .toUpperCase() on a string, it will return a new copy of that string with all the letters in upper-case, rather than modifying the string in place. In Clojure, all data behaves in this way; If you want to add an item to a vector, you call conj, which will return a new vector with the item added.

Why is this important? There are a few reasons: It means that the functions you write will usually be pure (have no side effects), which will make them easier to test and reason about. It makes sharing data throughout your program extremely safe, because distant parts of your application can’t alter the states of each other accidentally.

For example, there’s a bug in the following code:

var phoneNumbersPromise = getPhoneNumbers('george');

phoneNumbersPromise.then(function(phoneNumbers) {
    phoneNumbers.forEach(function(it) {
        it.type = normalizeNumberType(it);

phoneNumbersPromise.then(function(phoneNumbers) {
    var hasHomeNumber = phoneNumbers.some(function(n) {
        return n.type === 'HOME'
    if(hasHomeNumber) renderHomePhoneNumber(phoneNumbers);

The behavior of one promise block depends on the behavior of the other. It doesn’t matter what normalizeNumberType does, it affects the value of the phone number in a way that the second resolver will succeed or fail depending on execution order. Because we’re dealing with asynchronous code, execution order may be non-deterministic. These two resolvers might be separated by tens of thousands of lines of code, or may have been added at different moments during development.

If the value returned by the phone number promise were immutable, this bug could not exist.

In addition to the above major features, you get a bunch of pretty awesome minor ones:

  • Live coding
  • Managed CSP
  • Homoiconic code
  • Macros
  • ClojureScript
  • Easy testability
  • JVM / Javascript interop
  • Value destructuring
  • Ad-hoc Polymorphism
  • Lazy and Infinite Sequences

I believe there is value in learning new languages with unfamiliar ideas. Every programming language that’s made it to production has been a successful attempt at solving a problem in software. The ideas encoded in these languages are often portable to other languages, or can be an introduction into new ways of thinking about a particular set of problems. I believe that the concepts embedded in Clojure are incredibly useful, and they will make you a better programmer in whatever language you choose to write in.

If you’re looking to get started in Clojure, I highly recommend the book Programming Clojure by Stuart Halloway. From there, you can either try out some practical Clojure with the Basic Om Tutorial, which covers building React-style UIs in ClojureScript, or you can try out the challenges on CodeWars, which has a large-and-growing collection of Clojure challenges.

  1. Clojure numbers also support a rational form. So if you divide 2 by 3, you'll get a rational value of ⅔ rather than the less-accurate 0.66̅. ClojureScript does not have rational numbers and use the Javascript numbers instead.
  2. The common function to use in Javascript would actually be push, but push and conj aren't strictly equivalent. push alters the array in place and returns the value you pushed into it. concat combines the values you give it into a new array and returns that value. As a style note, I tend to avoid push unless it makes my code significantly more complicated.

What’s next?

A few days ago, the development team behind YUI announced that development on the project would be halted. I didn’t think I had anything to say about it—I assumed that I would feel some sadness for a few weeks or months until I moved onto whatever is next. But it’s been a week, and I think I’m itching for something to say.

I’ve also been looking for a reason to start blogging again, and this is a good a reason as any. In the wake of the “death” of YUI, what now? What’s good out there? What are the bad ideas? I wonder if there’s anything I can contribute to the conversation.

The world of JS has changed a lot in the last five years. The old-and-busted IE world is fading and the future looks like a bright forest of evergreen browsers. Node.js came out of left field; it now completely dominates the frontend build-tooling world and has a growing place as the frontend of the backend. There are now enough popular compile-to-JS languages that whole communities have sprouted up around each. It’s now possible to compile a C++ game engine to something that can run on the browser. The modern web is a weird place, I hope to make a little bit of sense out of it in the process.

I suspect that I’ll be writing about three different topics in the coming months:

  1. Exploring how to build large applications using new frontend technologies.
  2. Demonstrations of interesting new or “fringe” programming constructs
  3. Looking at the behavior and implications of language features

Before I start looking forward, I want to begin by looking back.

A retrospective on YUI

I’ve been building applications in YUI for my entire professional career. YUI2 was the first library I picked for ajax, animations, and widgets. I tracked the early development of YUI3 with great interest. Learning YUI3 threw me into entrprise-quality javascript with composable primitives, great documentation, comprehensive testing, and readable source code.

YUI was never a very sexy tool to work with. For most of the last 5 years, it was owned by Yahoo, which despite its great in-house talent, doesn’t project an aura of developer credibility, especially over the last few years. The YUI branding was boring and didn’t clearly advertise what made it special. The value of the framework was also hard to articulate to fellow UI developers; In 2010 extensibility, composibility, and maintainability took a back seat to simple APIs and fast DOM mutation. For almost everyone, the features of the library appeared monolithic and over-engineered. I believe history has validated YUI’s ideas, though—in 2014, most of the ideas first pioneered by YUI exist in current client-side frameworks.

To its fans, YUI felt like being in a near-future world where browser inconsistencies were gone, the event API was robust and sane, modules could be isolated and tested, and building applications with complicated state wasn’t a nightmare of DOM smashing. If a component didn’t do exactly what you wanted it to, almost anything could be extended and modified. Compared to black-box jQuery plugins that were its contemporary, YUI is a revelation in composability.

The community was similarly execellent. I used to monitor the message board, then the mailing list, and still spend much of my day lurking on IRC. I feel strongly that the quality of a community can be measured by the responses to open-ended design questions (“What’s the best way of doing x?”). There was always a constructive discussion about the most-maintainable way to achive a certain goal, even if it wasn’t in the “YUI happy path”. Asking a question about a new feature like promises or application routing was met with helpful examples, usually by the designers of those modules.

Unlike many modern JS frameworks, YUI isn’t “opinionated”1 about application structure or design. It makes a few recommendations, but the components were loosely-coupled and could be used in many arrangements. Prior to the announcement, there was discussion of breaking the framework up into ES6 modules that could be used outside the YUI context with limited dependencies. This would have been a significant-but-worthwhile project.

There’s still a lot of code that I’ll be working with that sits on top of YUI, but has been marked for refactoring to Angular2 since late last year. Eventually, the dependency will be removed entirely, and I’ll have few enough reasons to hit up the documentation. Still, I wouldn’t be the developer I am today without the experience I’ve had with YUI; the great ideas embedded in it will inform my decisions about writing software for a long time.

  1. "Opinionated" feels like a spin-word for a much uglier reality—an opinionated system is tightly-coupled or very complex, and usually both. It's telling that systems that could reasonably be called opinionated, but also have well-justified reasons for their decisions, do not claim that adjective. On the other hand, systems that make design decisions without clearly-stated rationales are eager to use it.
  2. I assume I'll be writing a lot about Angular in the coming months. I'm sure know too little about it, and I'm sure I dislike it too much.