"Computer Science is not a science... It is also not really very much about computers" - Hal Abelson, 1986
I first came across Structure and Interpretation of Computer Programs ("SICP") around the year 2000. At that time I was a software engineer at a large investment bank. I was working on building multi-threaded real-time risk systems in C++. SICP and Scheme blew my mind. This was a language that could create and return functions!
I have recently come across a copy of the Instructor's Manual for SICP, bookmarked with a London Underground ticket dated June 2000, marking commentary on Church Numerals. I first came across Church Numerals in a lecture at university. They were presented as a mathematical curiosity. To my mind they were an example of pointless mathematical abstraction(1)! And yet here was a computer language which had so much power you could implement Church Numerals.
But Lisp seemed hopelessly impractical(2). At our investment bank, we had to get every ounce of performance from our hardware. And just how were we going to build a Windows GUI in MIT Scheme?
More forward to 2006-2008 and I got badly burnt on a project. It was another realtime risk system, this time implemented in Java 5. It was painful. The complexity of the system and the OO encapsulation meant we could not reason about the concurrency of the system. We could ensure that shared data was protected, but we could not be certain there would be no deadlocks. And deadlocks there were! In production! They got ironed out eventually, but it is not an experience I would like to repeat.
Then there were "stop the world" garbage collections ("GC"), which would mean that our system would stop for 5-10mins at a time at random. Again, in production! These too were eventually tuned out.
There had to be a better way. The solution was not a better UAT environment that allowed the ironing out and tuning before the code reached production. The solution had to be a different way of constructing applications. A way in which there was a guarantee of no deadlocks. A way in which there was a guarantee of a maximum GC time.
Move forward to 2014, and the landscape had changed. I began to explore Elixir and Clojure. Both languages "solved"(3) the problem of concurrency. Clojure has many different (4) approaches whereas Elixir offers just the one, actors.
Elixir's runtime, the BEAM, solves the "stop the world" GC issue (5) as well. Clojure does not itself solve GC problems like Elixir. But structuring a Clojure application as a series of services communicating via a messaging service (such as Apache Storm or RabbitMQ) helps to keep GC under control.
And of course Clojure is a Lisp. And more than that, it is a Lisp built around immutable data structures, allowing the approach to program design described in the first two chapters of SICP on large scale projects (6).
I then saw a SICP in Clojure study group starting. I joined at once! This was an opportunity to study SICP and learn Clojure. And even better, I learnt that there were jobs for Clojure programmers! Lisp, this powerful, but obscure language I first discovered 15 years ago is now the present.
At one point I had hoped to read the whole of SICP and do every exercise! But
time is finite and there are so many other interesting topics in Maths, Computer Science and AI.
But when I have the time, I read another section of SICP or work another exercise. Maybe I will be finished in another 20 years. I am certain that SICP will still be relevant to software engineering.
My SICP code in Clojure is available here
1 I have learnt since my time at university that Lorenzo Church was looking at defining computability and wanted to add integers to a language (lambda calculus) that only supported function definition and application. With this context they move from being "pointless" to beautiful!
2 I was wrong again. Paul Graham was happily building a multi-million pound internet startup, ViaWeb, in Common Lisp at this point.
3 Well concurrency still remains challenging. But in Clojure and Elixir concurrency is under control in a way that isn't in any reasonably sized Java 5 apps.
4 For most applications just persistent data structures and atoms get you there. More complicated apps can use Software Transactional Memory or CoreIO. There are also non-blocking Java concurrency data structures such as the ConcurrentHashMap.
5 BEAM supports hundreds of lightweight processes. Each process has its own garbage collector. So the maximum GC for any one process is limited. In fact BEAM was designed to run telephone switches.
6 In 1986, writing an immutable LISP program for a large scale problem was infeasible. Hence SICP starts to talk about how to manage mutable data from Chapter 3. However, advances in computing power and in computer science now make this possible
Comments