The Bootstrapping Mindset
From OO to Clojure Workshop!
Watch my free workshop to help you learn Clojure faster and shift your paradigm to functional.
Summary: One of the great things about very robust and powerful abstractions is that they can give you tremendous leverage. The leverage can be so great that you can build something much greater than the sum of its parts. However, I worry that the web is an end to this kind of abstraction. I'd like to explore why that is and what we can do about it.
I'm on a campaign to find a solution to the web:
Folks, I'm repeating this every month until I see some progress: Has anyone solved CSS yet?
--- Eric Normand (@ericnormand) January 26, 2017
One of the great things about very robust and powerful abstractions is that they can give you tremendous leverage. The leverage can be so great that you can build something much greater than the sum of its parts. However, I worry that the web is an end to this kind of abstraction. I'd like to explore why that is and what we can do about it.
In the 19th Century, Charles Sanders Peirce, the father of Pragmatism and Semiotics, was struggling with some very deep questions in the philosophy of mind. Two of those questions were: How can a flawed/limited mind make itself smarter? And how can a spoken language be developed that refers to abstract concepts when the language doesn't have words for it yet??
Peirce's answer to both of these questions was that we can bootstrap. For example, if we have basic literacy, we can read books just beyond our current level and pick up new vocabulary and concepts. We use those new vocabulary to read more books, ad infinitum. Similarly, given enough concrete icons and indices (which are easily learned), we can define abstract concepts with them and assign arbitrary symbols. Thus we can invent new words, explain them to others, and use them to speak abstractly.
We start with a limited set of capabilities and, building with those, construct an expanded set of capabilities. I call this the Bootstrapping Mindset. One of the reasons I like Lisp is that it is a manifestation of the Bootstrapping Mindset. It's not unique to Lisp, but that's where I first saw its application in programming.
To summarize the last linked article briefly, Lisp starts with a few primitives easily defined in machine code. You construct an interpreter using those primitives. And now you have an executable lambda calculus. The leverage from that process is amazing.
Let me put it another way. Let's say you could write some algorithm in 10,000 lines of machine code. Great! You could also write a small Lisp implementation in 1,000 lines of machine code. Then you can write your algorithm in 10 lines of Lisp. Given a big enough project, you should build your own tools. Investment in tools will pay for itself many times over.
You also see this phenomenon in FORTH (build a small set of words and a way to define new words) and Smalltalk (build a small set of message interpreters and a way to define new interpreters).
In all of these examples, we have a "vocabulary" that is expanded by using the vocabulary itself. A great example and explanation is Growing a Language. Guy Steele explores the idea of how we can make a language that is not limited by our current understanding. The future potential of the language is limitless.
To my mind, Turing Machines are bootstrapping engines. Once you've got Turing-completeness, you can interpret any language. The differentiator is expressivity. Which bootstrapping steps get you to where your problem is trivial?
In all of these examples, we find a huge leap in expressiveness. We want to build something powerful enough and robust enough to very rarely (if ever) deal with the lower levels. I can write Clojure code all day and never think about the JVM bytecode, let alone the machine code that is actually running. When was the last time you debugged your code's NAND gates?
Here are my two requirements for bootstrapping. I call them:
- Leverage: Quantum leap in expressivity.
- Robustness: Rarely deal with the lower level.
If you don't have these two things, it might be very useful, but it's not bootstrapping.
I saw the greatest minds of my generation waste their time trying to vertically center divs.
--- Eric Normand (@ericnormand) December 12, 2014
So here's my original concern: can we bootstrap on top of the web? I believe we desperately need it. We are spending billions of dollars each year on the silliest problems of our own invention. And I'm tired of the tedium of working at such a low level. Yes, the web is a great economic force for good in the world, but the amount of crap work it generates is staggering.
Let me give an example of the "crap work" I'm talking about. We have at our disposal very powerful graphic design tools like Adobe Illustrator and Sketch. We can draw freely and make things as beautiful as humans can. Even if we limit our work to only what is possible on the web, we then manually compile that design into angle brackets. It is a specialized skill, with conferences, books, trade magazines, and training, to be able to turn a design into something that your browser can use. I respect the people who do it, because it's very hard. But I cannot respect the need for people to waste their time learning the magic incantations that make your design work in browsers. The fact that we do not see a great tool that outputs HTML + CSS directly is a bad sign.
Let me dig into this even more, because I don't want to give the wrong impression. Making stuff work in browsers is important. But actually getting it to work is way more work than discovering how it should work, which is the actual work of design. We can't focus on what's important: turning pixels into an expression of our humanity. Why not? Because we can't get it to render correctly. We're talking about unimportant minutiae like the best way to select an element in CSS. Should you add a new class? Or use nested selectors? There is no good answer because they all suck, and so we fight over it and call it "philosophy". Or we wait for committees to add yet more stuff to the standards which still doesn't solve the problem.
Let me put it another way: people have written custom layout engines in fewer lines of code than your average PHP page. We lob wrapper divs and CSS rules in our fight against the browser.
Now that I'm totally bummed out and have sufficiently defined the problem and what I'm looking for, I think it would be useful to likeminded searchers if I go over what I've found in my search.
These projects are great, they're just not what I'm looking for.
Flexbox is great, but it's not the last thing I need to finally stop writing CSS because I have abstracted over it. Instead, it just makes living with CSS more comfortable.
Yes, what a fitting name! Bootstrap promises something: use their HTML and the CSS just works. I'll also throw in all of the similar frameworks under this heading since the analysis is the same.
It's not quite the total solution I'm looking for. It's a bit like giving someone a tent to solve their home mortgage problem. You're still dealing with HTML, URLs, and all the rest. For quick web projects, I still turn to it, though.
I remember when I first saw that [build a blog in 15 minutes video](https://www.youtube.com/watch?v=Gz j723LkRJY). Wow! I was so excited. Back then, 15 minutes was unheard of.
But 10 years later, I overhear what Rails programmers complain about: how to write their templates, how to write their CSS, how to set up their routes, etc. In other words, they're using powerful tools to make the web more comfortable. They have not escaped it. Throw in some other well-known frameworks here, including Pedestal, Luminus, and Yada.
Several people have responded to my search with tweets about Garden, a library for generating CSS with Clojure. While it does give you the ability to use powerful logic to output CSS (high leverage), I don't see it giving you any ability to bootstrap out of CSS (low robustness). For example, could you give me a general solution to centering a div using Garden? You're still dealing with the difficult semantics of CSS.
Hopeful partial solutions
Hoplon is a ClojureScript web framework. It does several interesting things.
- It makes DOM elements into functions so they can be used in code like regular functions.
- It makes your elements reactive to changes like spreadsheets.
- It makes your client-server communication look like function calls.
It turns out that these three features together help a lot. And it gives a good foundation to build on. Let's see where this project goes.
I'm keeping my eye on this project. The premise is simple: if you just
wrap all of your divs in two more divs (which you're probably doing a
lot of anyway with
inner divs), you can
made automatically with a few more lines of code. It turns out that this
is fewer divs than you would write if you did it by hand! I don't quite
understand it yet but it's kind of exciting. I'm proud that this comes
right out of the ClojureScript community.
Solve layout with a Cassowary constraint solver. It's a custom layout engine that is more expressive than CSS for layout. And it's got a declarative language for building the constraints. It definitely has the Bootstrap Mindset. You're still living in HTML + CSS, but it acts much more like you think it should.
I am awestruck by this project. It produced Practical Typography, a beautiful online book. The pages look like hand-tuned HTML by a seasoned professional web designer. The author wrote his own authoring format using Racket (a Lisp) that outputs to HTML + CSS. It definitely has the Bootstrap Mindset. It highlights the value of writing your own tools and that maybe the problem is that we haven't peeled back enough layers of the stack.
I mention React here for its philosophy and its potential. It managed to
find a high-leverage abstraction to bootstrap out of error-prone DOM
manipulations. That was a serious pain point of the web. And the same
abstraction is being used on "native" platforms like phones and
desktops. With React on the web, you're still living in HTML and CSS
land, but it's way better than setting
innerHTML by hand.
This is just a talk at Clojure/conj in 2015. He's talking about the stack he's using, but there's an important bootstrap embedded in it. He's bootstrapping on the web as a communication protocol. He defines a single endpoint that accepts POSTs and a Server Sent Events endpoint. The POST endpoint is for sending commands (capturing the intent of the user) and the Server Sent Events endpoint is for updates from the server. That's it. No more fiddling around with URLs and "routes". This is a true bootstrap. High-leverage and high-robustness.
Conclusions, a glimmer of hope, and a plea
Bootstrapping is a beautiful phenomenon. We can transcend our current limitations using nothing but our currently limited abilities. It is a wonderful expression of our humanity. However, are we investing our web apps with humanity? Or are we toiling away in the bracket mines, fixing our CSS, choosing how to name our wrapper divs, and solving problems, yet again, that we created?
The purpose of bootstrapping is to solve that problem once and for all, so that we can focus on what's important. We can take a long walk, or we can "fill [our creations] with ideas, and emotions, and humor, and warmth." (quoted from Reversing the Tide of Declining Expectations, Matthew Butterick, TYPO Berlin 2012.) We need to do that more than ever, for the world and for ourselves.
We live in an interesting time. I've been waiting for a long time to see how Clojure (or any Lisp, really) is going to transcend the web. It has so many great tools! And the community understands the Bootstrapping Mindset. Yet I haven't seen the bootstrapping happen. Can we make it happen? Can we peel back the layers and build an engine for expressing our humanity? What kind of expressivity do we want? Our imagination is the only limitation.
If you're interested in the Bootstrapping Mindset, the big ideas in Computer Science, or Lisp, you should check out the PurelyFunctional.tv Newsletter. It's a weekly romp through the history, present, and future of Lisp and functional programming.