Sebastian Bensusan

Abstracting Engineering Away

Once in a while, an essay of the form "Programmers, let's be like engineers!" appears in my screen. Sometimes it's the opposite: "Programmers, stop pretending you are engineers". I studied engineering and I now program most of the day so I naturally read them. One side focuses on the differences between the fields and declares them too big to be overcome. The other side focuses on the similarities and thus decides that the noble title of Engineer is worth the trouble, all it takes is discipline.1 I think they miss the underlying issue: programmers and engineers deal with different levels of uncertainty. Some characteristics of software, abstraction and reuse, force programming into a semi-perpetual state of uncertainty, which explains the observed behaviors and offers some insight into the field's future.

By uncertainty I mean: if programmers/engineers want to solve a problem, how well do they know what they are doing and how will they do it?

For example, researchers know very little about what they are doing, and even less about how they'll do it. They first need to figure out what are the right questions, and only then how to answer them. Many of science's big ideas started with innocent questions that turned out to have tremendous implications, what do I see if I travel alongside a beam of light and look at it?2 In that sense, researches deal with high levels of uncertainty.

Unlike researchers, engineers have a better understanding of what they need to accomplish, for example: build a nuclear reactor to power a small city. There is room for creativity on how to do it: should it be a boiling water reactor or a pressurized water reactor? Even when choosing methods, they face very well understood constraints and trade-offs and can look back for previous solutions. Clearly, that doesn't necessarily make building a reactor an easy task. Significant expertise, skill, and effort are needed to implement solutions, even known ones.

Finally, there are technicians who implement known solutions for known problems with little variation. An electrician can predictably estimate the type of panel and size of fuses for a house and install them; he has done it before and will do it again. When the problem is well understood and the solution is repeatable, there is low uncertainty and less room for creativity.

The three categories, researches, engineers, and technicians, offer a continuum of technical activities with varying degrees of uncertainty. Where does programming fall in the scale?

Most non-technical people assume it neatly falls alongside engineering. Thus, they expect the software industry to work like any other engineering industry which leads to all sorts of confusion, most notably with regards to scheduling and failure rates.3 Society's expectations naturally correlate with uncertainty: research is not held to deadlines and failure is accepted, engineering projects are scheduled with some leeway but expected to succeed, and technical tasks are usually integrated into larger processes as predictable steps.

While there is a subset of engineering that resembles programming and a subset of programming that resembles engineering4, programming is higher in the uncertainty scale.

Let's continue our very serious example: building a nuclear plant. The engineer team will clearly take advantage of the set of knowledge and best practices accumulated by previous engineers. Their job is now to see how does his current plant differ from previous ones and adapt the known methods. But what happens if there are no previous plants?

The team that designed and built the first nuclear energy plant faced a set of unexplored requirements and constraints5. They probably had to do much more testing and prototyping than current nuclear engineers. They also probably felt like they didn't know what they were doing, because in fact, they didn't. Did they "act like engineers" or like "sloppy programmers"? They must have acted like serious engineers, it was a nuclear plant after all. Let's ask them:

These Borax-I experiments were expected to provide proof as to whether or not a water reactor could operate in a stable boiling mode

That sounds like a prototype for the reactor. Interesting, how did they go about it? What about safety?

It began as a crude reactor experiment, conducted in open air without benefit of any building structure or containment.

Ouch. Even nuclear engineers skip SSL on the first prototype. Clearly, engineers have to experiment at some point. With that in mind, the following quote makes sense:

The loose arrangement allowed for decisions and problems to be resolved quickly, sometimes with whatever materials were conveniently available.

And this final quote sounds like it was taken from a programming conference talk:

There was insufficient time available to make the needed modifications. We compensated for the problem by implementing some very innovative tricks.

But engineers don't use tricks! That is how we perceive engineering now, but only because yesterday's tricks are today's best practices. One might argue that engineering is a collection of tricks that are known to work. An obvious conclusion follows: you can't act like an engineer when the problem is new and you don't understand it.

So why is it that all programming feels like the experience of the first nuclear engineers? Abstraction and reuse. Unlike any other technology, software is free to distribute and lends itself extremely well to abstraction. When the software industry solves a problem, it solves it for every project. For example, when was the last time you implemented your own HTTP server? Apache solved that in 1995 and for many purposes that is all that you need. On the other hand, the nuclear plant's foundation needs to be poured every time, even though the Romans had a great recipe for concrete. The accumulation of well understood, repetitive problems makes each engineering project less innovative and more predictable than its programming counterpart.

Programmers face higher uncertainty even after they think they've solved the problem: the maintenance phase. While maintaining a nuclear plant means following an established procedure, maintaining software means changing it to do new things. That doesn't sound like maintenance to me. It is only called maintenance because it happens after the implementation. A more appropriate name would be "continuous redesign". Software is perceived as "easy to change" and thus is expected to adapt to new circumstances. Even inside one project software needs to reinvent itself.6

When starting a new project, programmers only face problems with novel elements, otherwise they would reuse somebody else's code. When maintaining projects, programmers face unexpected problems, otherwise no maintenance would be needed. These are some of the problems that the industry has already solved:

  • Communicate machine information over a network. (IP/TCP)
  • Communicate human readable documents over a network. (HTTP)
  • Store data that fits in a table. (SQL databases)

These are some of the problems that the industry is actively trying to understand:

  • Build distributed systems that behave as expected.
  • Deploy and manage clusters of servers and applications.
  • Process large amounts of data either in batches or continuously.

Maybe those problems are ill-defined. Distributed systems don't look like something you can abstract over but more like a design space. Accordingly, people dealing with distributed systems increasingly sound like engineers: they refer to trade-offs (consistency vs availability) and recommend best practices ("don't write your own consensus protocol!"). Bigger architectural patterns and structural elements (coordination, messaging, persistence) will emerge and be adopted as basic building blocks. After some time, the interplay between those elements will be more predictable and building distributed systems will feel more like engineering. Data processing is at the same stage. On the other hand, cluster configuration, monitoring, and deployment looks like it can be solved by a set of tools.

Experienced software consultants also tend to behave like engineers. They usually end up specializing in niches like systems integration and after a couple of decades they have seen it all. Any problem domain in which they specialize might be abstracted away by others experts making them less useful. If they specialized in payments infrastructure they would be in trouble if Irishmen ever built a service that abstracts the problem away7. While this is true in some degree for all industries, software specialists are specially vulnerable to abstraction.

There are other programming activities with lower levels of uncertainty.8 Consider your average business "we exist!" website. A web consultant can build it with HTML, PHP scripts, and Wordpress. He has done it a thousand times and knows how to do it. Unlike engineers, they don't have to re implement Wordpress from scratch so the project is not as challenging. They don't even need to behave like engineers because most of the best practices were already encoded in their tools by experts. In that sense, they are more like technicians than engineers, implementing known solutions for known problems.

When programmers solve a problem, abstraction lets them encode best practices and the industry as a whole moves on to the next frontier. In that sense, "let's be engineers!" is a moving target. Once a problem is abstracted away, implementing all future solutions will feel like plumbing and not like engineering. The next problem they face is by definition new so it doesn't feel like engineering either!

Abstraction and reuse are not restricted to software. Electrical engineering has such good standards that it almost feels like no design is needed. I think it stems from the fact that there is only one thing to produce, AC electricity, so components can be easily "connected". Electronics has even more powerful abstractions since theirs compose. Individual components (e.g., transistors) can be composed into more complex components almost indefinitely (computers!). One might even argue that composition explains why digital electronics are more powerful than analog electronics: analog components can't be composed indefinitely because of noise propagation.

Mechanical engineers have a harder time. Pumps, electrical engines, and small combustion engines have been abstracted into off-the-catalog components. Beyond that, things are harder to abstract industry-wide but are still successfully abstracted inside of companies. For example, Volkswagen has only a handful of car engines, which it reuses on dozens of cars models. Civil engineers face the hardest challenges when dealing with reuse but even they've found some abstractions: steel framing for skyscrapers and prebuilt homes transformed "building a structure" into "assembling a structure" which is much quicker.

All those disciplines have distinct places where the quirky engineers tinker with the future and figure things out: workshops. If you still believe that engineers always act like engineers, visit one: you'll either leave thinking that tape is a valid structural material or you'll never trust an engineer again. While the tinkerers remain hidden in workshops, the rest of the field is visibly busy solving the problems they couldn't abstract away: keeping the production line running, pouring concrete into molds, etc. In programming the opposite is true: the tinkerers are the majority, goofing in public and setting the tone for the industry.

Engineering only emerges when a problem has no final answer but actually represents a design space with multiple solutions and trade-offs. Programmers have been around for less than a century and are still abstracting problems away. Let's hope it continues that way, tinkering is much more fun.

1There is a third category of essays which try to distinguish between terms like "programmer", "developer", and "software engineer". While those exist and are relevant, they concern themselves with differences between individuals; I'm interested in the difference between the fields: the accumulated knowledge, accepted behavior, and best practices.

2Those historical anecdotes have their share of myth and having the question is not sufficient to come up with the resulting solution. The important part is the framing of the problem, which is captured by those questions.

3They are tremendously disappointed when they realize that is not the case, which probably explains the tone of some of the "Programming vs Engineering" essays.

4This was so obvious to my brother (an engineering student) that it almost prevented me from publishing the essay. His first instinct was to compare programmers to philosophers because they both "build upon ideas". He clearly doesn't know about CSS.

5For much more on the fascinating story of the BORAX I, the first nuclear reactor, read the account of one of its creators. The quotes are just from the preface.

6Thanks to Martijn Walraven who pointed out continuous change as another factor contributing to higher uncertainty.

7Note that even though a company abstracts the problem away the result is the same: programmers no longer need to implement the checkout step.

8What about higher levels of uncertainty? Programming, being between engineering and research in the uncertainty continuum also gets associated to computer science research, with its own set of interesting consequences. That is the starting point of Hackers and Painters where Paul Graham argues that programming and research should also be kept separate.