This is still the header! Main site

Simplicity as a Feature

2021/12/03

... and here is a quick summary.

This is post no. 49 for Kev Quirk's #100DaysToOffload challenge. The point is to write many things, not to write good ones. Please adjust quality expectations accordingly :)

If you mention the word "engineering", one of the things that come to mind is that it's all about tradeoffs.

You're building an airplane. How fast can it go? How much weight can it lift? What's the fuel consumption?

There are no uniformly good answers. If you add an efficient jet engine (like on an airliner), you can't quite go as fast as a fighter jet, but you'll use a lot less fuel. Similarly, airliners can turn slower and are less resistant to being shot at. Military cargo jets can land at a lot more places than airliners and can transport entire actual trucks. They're also a lot more expensive.

Crucially, you can't make a 737 as fast as an F-35 by adding parts to it. A 737 with a whole lot of engines is... still a pretty bad fighter plane. In fact, you're working really hard at removing parts or processes from your planes, as much as you can, so that you can save weight, fuel, and manufacturing cost. It's an actual physical object that you're building; extra parts are not free, in many senses.

Enter software engineering.

Software is that marvelous thing that doesn't have any weight, it's extremely cheap to copy, and adding extra lines of code doesn't affect your aerodynamics, either. There is no need to solve the same problem over and over... to go with an analogy: if you once build an "airplane wing", you can just reuse the same wing on any of your products!

(Yes, it's a stupid analogy. It feels wrong for a reason though.)

In the overwhelming majority of cases, you solve problems by adding code. Because it's weightless and there is no Actual Physics around, adding those extra wings doesn't hurt functionality elsewhere... meanwhile, everyone is happy that new features are now present.

As a consequence, starting new projects quickly becomes pointless when old ones already exist, especially if they are open source. We already have Linux as an operating system; any other attempt at this is a waste of resources. We should just all work on the one system we already have put all the work into!

Well okay, but... is this really so?

... at this point we come to the part where we slowly realize that... the previous section made significantly less sense than the amount it should have.

Even with our slightly broken analogy of "airplanes": adding large amounts of wings definitely doesn't make sense. However... actual software isn't significantly better than that.

Namely, you can add features like "supports protocol X" and "has button to do Y" by adding more code. However... not all possible features are like that.

Take, for example, "it's easy to add new functionality". Which probably includes understanding what's going on; our existing code base needs to be simple and well-organized to make this happen. Even so, larger projects need a lot more work to change (... which one would you add a new UI element to, a Visual Basic "hello world" app or Firefox?)

Meanwhile, if "easy modifiability" roughly corresponds to "turning speed"... "fuel consumption" is roughly analogous to performance. Which is... yet another area where all the abstractions break down: we might be doing the very same thing, but if your Electron app is using 10x the RAM and CPU as my native implementation... "fuel" might be cheap, but it's not exactly free.

There are more, more subtle features related to these. Are APIs the right shape to do X? Perhaps doing it is really ugly on e.g. Linux, but is trivial on, say, Plan 9 (e.g. users mounting file systems). Yes, you might be able to plaster this over in abstraction layers, but not everyone is going to use the abstractions, and you'll still see bugs bubbling up from the lower layers. It's still there. You can't pretend those lower layers don't exist with 100% accuracy.

(VMs come the closest; look at cycle-accurate console emulators though to see how much more performance it takes to make emulation really feel like the original.)

Conclusions?

We can basically just negate those of that "fake" section above.

Namely... since you can't add simplicity later... it's actually worthwhile having multiple projects with almost the same design goals, except implemented slightly differently. Each of them might fit into a different niche of requirements, without trying to pretend it's one of the other ones.

For example, we do need not only Linux but the BSDs, Haiku and TempleOS, too!

... comments welcome, either in email or on the (eventual) Mastodon post on Fosstodon.