My name is Toni and I’m a programmer
I wrote my first choose-your-own-adventure game when I was eight years old. I had learned to instruct my trusty C64 to wait for input, process the input, print output, rinse and repeat. My first university classes were basically the same, although the process was much slower because my Java code had to be compiled in each iteration. However, we soon ditched any notion of quick prototyping and moved on to Real Programming, which evidently involved lots of modelling, diagrams, classes, objects, and instances. Now, having used Clojure for a year at work, I’m back to being that kid who enjoyed programming. I write functions that take data as input, do stuff with that data, and output data. That’s it. I can try out stuff in the REPL, look what I got out of it, and try something else. I see the data. I can touch the data. I get immediate feedback. It’s how I have always loved to work.
Reading Clojure code
I will give a few code examples in Clojure. They are brief (Clojure code always is), but you should know the basic syntax. If you already do, come play with us. If you don’t, you could go back and forth to the Clojure cheatsheet, or even take a crash course in Clojure. However, I can tell you the basics in no time. You already know how functions work, right? If so, the following illustration summarizes Clojure syntax for the reader more accustomed to imperative languages:
Now that you know how to read Clojure, let’s get started.
Stuck in the ‘50s
It used to be so that we cared where computers store their data. It made a lot of difference whether the OS loaded your stuff at 0xA5A79 or 0x77F4C (especially if you got this for Christmas). It made even more difference how and when and what memory was accessed or — gasp — manipulated. Nowadays, most of us don’t think about the day-to-day issues of memory management. “How many bytes does it take to store my integer?” is no longer the right question. “Why should I care?” is a more relevant one. The following code snippets illustrate the difference between describing implementation details and the meaning of data.
Even this simple example shows that data is much more than byte counts. Nonetheless, our de-facto programming languages are still standing on the shoulders of Fortran and C, rooted close to hardware. We are more concerned about the “how” — the exact sequence of operations a computer must perform — than the “whats” and “whys” of programming. Our focus on the lower levels of computing is in direct contrast to the needs of our customers, for whom declarative will always be greater than imperative. They want to predict when a stone crusher needs maintenance, or guide a customer to book travel that fits their needs and preferences. Beyond meeting the criteria of security and reliability, they don’t (and shouldn’t) really care about the implementation from a business perspective. They need results, not operations, dammit!
A tale of two camps
Maybe we could live without a construct for chaining functions like this, or use objects and method chaining (shudder!). However, such deficiencies stack up and encourage a certain style of programming, i.e., not a functional style. For example, the lack of proper function chaining makes lambda lifting quite unattractive.
The hermetic encapsulation
The empty promise
Here’s a brief summary of React: Components take input as “props” and output beautiful HTML UIs. When props change, the component re-renders — reactively, you might say. So, when I tried a new visual component library for React, I expected to throw data at the library, and get it rendered. What I got instead, was an empty promise. The library wanted me to use a promise to signal when my data is ready to be rendered. This was not a good fit, since I was using Redux for my state management and redux-sagafor handling all my side-effects (i.e., things that are not pure; in this case, interact with the unclean outside world). I was forced to write some ugly code that resolved an empty promise (yuck!) after executing the side effects. Not a big deal, you say? Well, it’s difficult to look the other way, once you’ve seen the light. I’m now used to just managing the data of my app, and getting beautiful reactive UIs by default. The following code example from my re-frame frontend app shows how I update a list of items in response to a :shuffle event:
When my handler changes the in-memory database (a good metaphor for any frontend project, by the way), the views are automatically updated. The changes propagate all the way to the underlying React components, which handle the re-rendering efficiently. No need to explicitly request a re-render, or other ominous trickery.