TITLE: StrangeLoop: Rich Hickey on Channels and Program Design
AUTHOR: Eugene Wallingford
DATE: October 04, 2013 3:12 PM
DESC:
-----
BODY:
[My notes on StrangeLoop 2013:
Table of Contents]
Rich Hickey spoke at one of the previous StrangeLoops I attended,
but this was my first time to attend one of his talks in person.
I took the shaky photo seen at the right as proof. I must say,
he gives a good talk.
The title slide read "Clojure core.async Channels", but
Hickey made a disclaimer upfront: this talk would be about what
channels are and why Clojure has them, not the details of how
they are implemented. Given that there were
plenty of good compiler talks
elsewhere at the conference, this was a welcome change of pace.
It was also a valuable one, because many more people will
benefit from what Hickey taught about program design than would
have benefited from staring at screens full of Clojure macros.
The issues here are important ones, and ones that few programmers
understand very well.
The fundamental problem is this: Reactive programs need to be
machines, but functions make bad machines. Even sequences of
functions.
The typical solution to this problem these days is to decompose
the system logic into a set of response handlers. Alas, this
leads to callback hell, a modern form of spaghetti code. Why?
Even though the logic has been decomposed into pieces, it is
still "of a piece", essentially a single logical entity. When
this whole is implemented across multiple handlers, we can't see
it as a unit, or talk about it easily. We need to, though,
because we need to design the state machine that it comprises.
Clojure's solution to the problem, in the form of
core.async, is the channel. This is an implementation
of Tony Hoare's
communicating sequential process.
One of the reasons that Hickey likes this approach is that it
lets a program work equally well in fully threaded apps and in
apps with macro-generated inversion of control.
Hickey then gave some examples of code using channels and
talked a bit about the implications of the implementation for
system design. For instance, the language provides handy
put! and take! operators for integrating
channels with code at the edge of non-core.async
systems. I don't have much experience with Clojure, so I'll
have to study a few examples in detail to really appreciate
this.
For me, the most powerful part of the talk was an extended
discussion of communication styles in program. Hickey focused
on the trade-offs between direct communication via shared
state and indirect communication via channels. He highlighted
six or seven key distinctions between the two and how these
affect the way a system works. I can't do this part of the
talk justice, so I suggest you watch the video of the talk. I
plan to watch it again myself.
I had always heard that Hickey was eminently quotable, and he
did not disappoint. Here are three lines that made me smile:
- "Friends don't let friends put logic in handlers."
- "Promises and futures are the one-night stands" of
asynchronous architecture.
- "Unbounded buffers are a recipe for a bad program. 'I
don't want to think about this bug yet, so I'll leave
the buffer unbounded.'"
That last one captures the indefatigable optimism -- and
self-delusion -- that characterizes so many programmers. We
can fix that problem later. Or not.
In the end, this talk demonstrates how a good engineer
approaches a problem. Clojure and its culture reside firmly
in the functional programming camp. However, Hickey recognizes
that, for the problem at hand, a sequence of functional calls
is not the best solution. So he designs a solution that allows
programmers to do FP where it fits best and to do something else
where FP doesn't. That's a pragmatic way to approach problems.
Still, this solution is consistent with Clojure's overall design
philosophy. The channel is a first-class object in the language.
It converts a sequence of functional calls into data,
whereas callbacks implement the sequence in code. As
code, we see the sequence only at run-time. As data, we see it
in our program and can use it in all the ways we can use any data.
This consistent focus on making things into data is an attractive
part of the Clojure language and the ecosystem that has been
cultivated around it.
-----