The Cost of Abstraction
Technology evolves by building better abstractions. But in the last 15 yrs, have these abstractions come at the cost of, ironically, computational thinking?
Back in 2006, Jeannette M. Wing wrote an article for CACM, called Computational Thinking. It's an extremely readable article, written for technical and non-technical audience alike, and I'll strongly encourage you to go through it. An important line from the article that I'd like to highlight (with a very slight paraphrasing):
"Computational thinking means more than being able to program a computer. It requires thinking at multiple levels of abstraction." - Jeannette M. Wing
Jeannette was not alone in recognising this. Richard Hamming in his fantastic book The Art of Doing Science and Engineering (an absolute must-read for any engineer, scientist, or any thinking person) makes similar arguments about the style of thinking.
Both Jeannette and Hamming go on to emphasise the importance of Foundations and the Method of thinking, and how it's pervasive to problem solving in general. Specifically, these techniques affect every area of science & engineering. Jeannette talks about putting Computational Thinking alongside Arithmetic in terms of applicability. Similarly, Hamming talks about "the underlying homogeneity of knowledge".
Why am I talking about all of this? Because over the past 15 yrs, there's been a large number of software engineers (in India at least) who are stuck at the level of abstractions they used to get into the industry. This statement might sound offensive & elitist to some, but I'm at a loss to phrase it differently. In this post, I'll explore what I believe to be the most major contributors to this phenomena, why I feel the cost is beginning to show up now, and possible paths to get out of it.
A bit of history
In the past 2 decades, there have been 4 defining inflection points for how we build and use technology, ranked below in the order of what I perceive to be their contribution:
Modern Smartphones: The launch of iPhone in 2007 (and Android in 2008), was a defining moment in consumer adoption of technology1. Every person wanted one, and the pervasiveness of an always-on computer in the hands of every consumer meant that every single company out there had to be on the Internet. The launch of App Store in 2008 created a completely new economy, and created an extremely high demand for people who could code.
Javascript: JS was launched in 1995, but it's only 2009 onwards2 (thanks to Node.js, AngularJS, React et al.) that JS (standardised to ES) became a proper programming language, in the sense that one could create end to end useful apps with just JS/ES alone.
Open source software: Github's launch in 2008 was a great accelerator of the OSS movement3. Github's focus on collaborative work showed up in the number of PRs raised within 2 yrs of its launch. Git doesn't have the concept of a PR, it was the name of Github's workflow, and its simplicity allowed people to collaborate without necessarily understanding git. Progress in OSS greatly reduced the number of things that would have to be written in-house.
Cheap Compute Cloud: AWS was launched in 2006, which had some effect in terms of speed of infrastructure movement that companies could have, and trading off capex in favour of opex. But it was really its PaaS offerings over the next many years that had a far more long-lasting effect - developers could focus on just the business logic and orchestrate across API calls to the PaaS services.
One item I've not included above is easy supply of capital, often referred to as the ZIRP phenomenon. A lot has been written about it, and I don't disagree with any of it, but explaining everything via ZIRP is silly. Smartphones success (and thus, the app economy) would've happened without it. JS & OSS are reasonably economy insensitive. Cloud had more to do with Amazon creating a new business model out of existing resources. So yeah, while acknowledging its role, I'll be ignoring it for the purpose of this essay4.
Programming becomes accessible
Notice how all of the above happened really close to each other, really building up 2009+ onwards. It was a perfect storm:
- The app economy created a huge demand for developers, driving up the cost of devs (also making the space attractive).
- Cheap (arguably) fractional compute allowed one to be significantly wasteful with resources. Cost of compute resources would often be deemed lower than cost of development (high demand).
- Javascript frameworks & OSS allowed easy programming and lego-like assembly of a product. Speed of iteration became a more important metric.
It's not like accessibility5 of tech was a new concept. The demand for simpler languages had been brewing for a while. Java had already become mainstream in enterprise software development, thanks to abstracting away memory management. Dynamically typed languages traded off performance & costs in favour of expressibility (cheap compute meant it was increasingly more tolerable).
People wanted to be solving their problem, instead of figuring out how to get their computers to behave. There was a burning need for better abstractions and a lot of the development I mentioned above, fulfilled it. These abstractions made it much easier to create value for customers.
Accessibility without computational thinking
Now that we've discussed how programming became very accessible thanks to much better abstractions, let me highlight how programming/design can happen without computational thinking. Let me give 3 examples:
An engineer is building software for a logistics company. Everything is getting scanned, no need for manual entry in a register, returns are being logged, traceability exists for every human touchpoint, everything is in the system™. "How does the latency vary with the throughput?". Usual answer - "Uhm, what?". Because there's no such notion - the system was built to digitise the existing process, instead of modelling the process to be computationally tractable. "Don't worry, I'll have our analytics team get back to you with an answer".
A stock broker is facing high request rates. "We've now put Redis in front of read-only requests, and every write invalidates the key". "Ok, what happens if your writeback queue is getting slow, or just fails". "We've never seen it fail". Remember that this is a stock broker we're talking about. Unbounded delay in write-backs effectively translates to unbounded risk exposure for its traders. FWIW, my issue isn't as much with the choice (one can argue about ROI of efforts), but with the complete lack of rigour behind the thinking. This is also an example of taking a scaling recipe from low risk domains, and applying it blindly to high risk ones, instead of thinking afresh about the method of modeling such systems.
An engineering team is doing capacity planning for their systems. "Our load tests show that we can handle our current peak of 1k simultaneous users with a total of 100 cores of compute capacity, so let's order 150 cores so that we have a 50% buffer". Do you see the issue here?
Maybe you're thinking I'm exaggerating. I'm definitely not. Each of these is a real life example spread across many companies, and the full list is much longer. Or perhaps you've had better experiences, in which case I'm happy for you. FWIW, I'm not advocating an unjustified amount of rigour for every single decision. I'm talking about fixing a broader culture of lack of rigour, that might be based in intellectual laziness to some degree, but is likely also influenced by an influx of people who've been trained to use computational tools, but not in computational thinking. And easy abstractions allow for significant tolerance.
Abstractions - good or bad?
I should state upfront that I firmly believe abstractions to be a good thing. It's a crucial tool in our ability to zoom out and think in terms of better, more appropriate, primitives. Similarly, the ability to zoom-in, and looking at how things work behind the scenes, is crucial to being able to see the homogeneity of knowledge that Hamming mentions. In the past, I've talked about the foundational layers being a sort of basis set to generate the rest of the knowledge domain. Engineers naturally need to be able to operate at multiple levels of abstractions!
The problem isn't with abstractions. The problem is with choosing to be stuck at one layer of abstraction because it's good enough, and never trying to go beyond. The significant improvement in quality of OSS meant that new engineers didn't have to fiddle around with the internals of things to make them work, so the need to explore lower levels of abstraction got removed. Simultaneously, availability of someone to tell them what to build, eliminated the need for a higher layer of abstraction too.
Easy money (driven by the huge demand for software engineers) meant it was possible to do this without risk. Value was still being added, so why go the extra mile? It's my belief that the median engineer in this era outsourced their thinking6 - some times to whoever gave them the requirements, and at other times to the OSS community.
Engineering degenerated into shallow programming. If you could just tell a computer what to do, you could get a job.
If you find this statement elitist, I ask you this:
- On the higher layer abstractions - what percentage of engineers around you have taken non-trivial decisions (i.e. having higher order effects) in the past few years? For those that have, what has been the value of those decisions in terms of outcomes?
- On the lower layer abstractions - When you open a job req, the average person who applies, what can you say about the depth of understanding that they possess? Forget that, the laptops (or git for that matter) that most engineers use on a daily basis, how many can explain precisely how that works? Note that I'm not asking them know every term or number, I'm talking concepts.
The incessant bashing of college education
In parallel, an interesting debate had been getting fuelled on social media, whether colleges are even necessary. Like most such debates, part of it was based in reality, i.e. quality of college education was not up to the mark. But a large part of it was purely capitalising on this truth to incessantly bash the notion of college. The idea that you can do a 3 month course to prepare yourself for the industry, was in vogue.
One could argue that there were hardly any students who truly dropped out of college due to this discourse. While true, it still influenced a whole generation of engineers to completely disregard the foundational concepts ("I'll get my degree, but don't value the subjects") that are so crucial in shaping the mathematical and systems thinking of budding engineers. I remember tweeting this at the time, after having seen a disturing trend amongst undergrads based on advice doled out on Twitter or Youtube.
To be clear, I'm no fan of the education system we have in India, but colleges do provide a forcing function to understand the foundations better - something that the industry hardly provides the space for. I believe the approach that undergrads need to take is to go beyond the knowledge that your college provides, not replacing it with a 3-month upskilling course. Skills go up and down, foundations remain forever.
"Education is what, when, and why to do things, Training is how to do it. Either one without the other is not of much use." - Hamming
A change of scene?
As the era of shallow programming (being sufficient to generate value) comes to a close, expectedly there's a flux in which all kinds of people get caught up. What's certain is that engineers who've invested enough time in developing their core foundations & systems thinking skills, will find themselves out of this flux much sooner. Those who've either been deprived of good education on foundations & computational thinking, or were provided so but have forgotten how to practice it, it's a good time to start now.
I see a new set of opportunities shaping up nicely - a reinvention of sorts. Programming languages are being reimagined7 creating better abstractions, the shape of computing hardware is changing, and the progress in AI should ideally allow us even more time to invest in thinking than writing, along with opening up newer economic opportunities. Engineers who are well versed with foundations are breaking some of the previous abstractions (every abstraction has a half-life), and reinventing technologies for the new era8.
Our ability to think at different levels of abstractions, is precisely what defines the breadth and depth of what we can study and build upon. I hope we can make this thinking at least as accessible than the tools.
- 1: Programmable mobile phones had existed prior to it - smartphones like Blackberry or even the Sony Ericsson that I had. But nothing like iPhone/Android. The predecessors were clunky, designed for & marketed to the business user, apps were pathetic Java applets, and there was no App Store.
- 2: JS did start showing up meaningfully on the browser frontend in early 2000s (AJAX et al.), i.e. much before 2009, but even then, it was a far cry from being considered a full-stack programming language. It was always an add-on to some other stack.
- 3: Not that sites like Sourceforge didn't exist, but at the time of its launch, Github was the only site designed around Git, the awesome then-3yr-old distributed version control system built by Linus Torvalds. Sourceforge added Git support in 2009, but its reputation prior to Github wasn't stellar either for a variety of reasons.
- 4: There's perhaps a more important reason. Capital supply goes up & down all the time. If my hypothesis (of abstractions as the primary contributor) is correct, the implications on education and how we think about being an engineer, stand independently of capital market swings.
- 5: Needless to say, by accessible tech, I'm talking about ease of getting into programming, and not accessibility meant for disabilities.
- 6: An argument could be made about the number of frameworks that engineers often end up having to learn. While it's true that every year in the past 15 yrs, there's been rise of something new - a few real, and a whole bunch of ephemeral buzzwords, we shouldn't conflate knowing how to use something with understanding it. More often than not, engineers would rely on a PaaS offering of such tech, or recipes when hosting in-house, than actually trying to understand it.
- 7: Rust 1.0 was released just in 2015. Zig's
comptime
has been making waves. - 8: My favourite example here is TigerBeetleDB, whose decisions of deterministic-by-design, rethinking the primitive to be debit/credit instead of SQL, and many other choices has allowed them to provide two orders of magnitude of difference in performance, while simultaneously improving safety.