The Steve Wozniak Guide to Building Better Software
Software development insights from the man who started the personal computing revolution
Looking for a job at a company trying to save the world? Check out GoodJobs. It’s a job board I built with hand-picked engineering positions at companies trying to fix problems like climate-change and food insecurity.
There are a few icons in the history of personal computing that programmers like to idolize, and the grandfather of the all is Steve Wozniak. The sales and marketing people have Jobs, the programmers have Woz. For good reason, too — Steve Wozniak accomplished some amazing things, including designing and building the Apple II from scratch, both hardware and software. While you might be thinking “That happened in 1977, in a garage, in California. How does it apply to me, today, in 2019, in my chair, on the internet?”, my goal for this article is to distill some of Steve’s genius and apply it to modern software development.
My primary lens into the brain of Steve Wozniak is chapter 3 of the fantastic collection-of-interviews-in-book-form, Founders at Work (affiliate link (full text of Ch3 here)). Some additional resources are linked at the bottom of this article, and Steve is also apparently very active on Twitter via Foursquare Swarm (not necessarily the greatest morsels of programming insights there, but what can you do?).
Design with as few parts as possible
The idea that constraints can improve creativity for teams doing R&D has made its rounds in technical circles over the years, and is pretty well known at this point. Lots of evidence points to the benefits, but even so many software projects lack any sort of meaningful constraints to inspire out-of-the-box thinking. For web apps in particular the expanding capabilities and ubiquity of browsers, coupled with ever more powerful personal computers, means that Wirth’s law is very much alive and doing quite well.
While it may be somewhat of an artificial constraint considering the capabilities of modern computers, building simple software using as few pieces as possible is a useful tactic that we can adopt from Woz’s design philosophy. Taken from Founder’s at Work:
Wozniak: “Even back in high school I knew I could design computers with half as many chips as the companies were selling them with. I taught myself, but I had taught myself in a way that forced me to learn all sorts of trickiness. Because you try to make valuable what you’re good at. I was good at making things with very few parts by using all sorts of tricks — almost the equivalent of mathematics — so I valued products that were made with very few parts.
That helped in two ways. When you are a startup or an individual on your own, you don’t have very much money, so the fewer parts you have to buy, the better. When you design with very few parts, everything is so clean and orderly you can understand it more deeply in your head, and that causes you to have fewer bugs. You live and sleep with every little detail of the product.”
While reducing the number of ‘parts’ in a software project won’t directly save you on manufacturing or shipping costs, the latter part of Steve’s quote rings true. In any system, especially software, the less complexity you have in a system makes it easier to understand how everything works together. This transparency leads to an understanding of how changes in one area will affect another related area. In a simple system, these relationships are clear and able to fit in one tidy mental model. In a more complex system, we have to combat our own inability to hold all of the pieces together with measures like documentation and unit testing. While these processes benefit a project of any size, they are more necessary in larger projects.
While Steve Wozniak probably has a greater capacity for understanding systems than your average developer, the theme here holds: simplicity leads to clarity, which in turn leads to fewer bugs.
Take opportunities to reimplement existing working systems.
While Steve Wozniak was in high school he lacked the resources necessary to work on actual computer hardware (this was way before computers were affordable for regular people), but still had a keen interest in hardware design. He read through manuals for computers which contained the specifications for their chips, and redesigned them so they had the same inputs, outputs and general functionality, but with different layouts.
Livingston: “You were designing all of these different types of computers during high school at home, for fun?”
Wozniak: “Yes, because I could never build one. Not only that, but I would design one and design it over and over and over — each one of the computers — because new chips would come out. I would take the new chips and redesign some computer I’d done before because I’d come up with a clever idea about how I could save two more chips. ‘I’ll do it in 42 chips instead of 44 chips.’ ”
While it may seem like bad business advice (why rebuild things that already work?) there are are actually a number of benefits from rebuilding systems that you already understand. For one, there are a number of unknown unknowns that inevitably crop up during the code construction phase of software development, issues that were invisible to the design process and only come to light when you go and try to code the thing. These unknown unknowns by definition become known considerations when you’re reimplementing a working piece of software. This allows the programmer to account for them in more elegant ways than whatever solution was implemented on the first run.
Another benefit of reimplementing working systems is that on the second time around, you are more of an expert in building that type of software. Reimplementing a working piece of software means, by definition, that you have more experience with the necessary tools, processes, and thinking that lead to a correct implementation. This means that instead of just worrying about meeting the specification, you are able to hoist your thinking about the problem to the next level up; a sort of meta-problem-solving, if you will. This mind-space can lead to insights that aren’t possibly when you’re primarily concerned with the nuts and bolts of getting an implementation to work.
Avoid unnecessary abstractions
This last point is one that I find very compelling, so much so that I’ve written about it before in another article. Basically, any tool or abstraction in software engineering limits your ability to problem solve based on the smallest element of that abstraction. In other words, abstractions give you lots of power, but its easy to run into pitfalls that you can’t reason around because they exist below the level of abstraction that you’re working on.
This point is echoed by Wozniak, talking about programming his Basic interpreter in machine language:
“So this was not at all a normal project where you have tools. I had no tools; my approach in life was to just use my own knowledge. I know what’s going on better if I’m not going through a tool.”
While somewhat simply put, the theme here is clear: it’s easier to reason about the entire system if you don’t offload any of its complexity into a tool that you don’t fully understand. This is a point that is especially powerful in the age of proliferation of web based technologies and ever-heavier web applications.
To wrap things up, I’ll end it with this quote which I think goes far beyond software development:
“Always seek excellence: make your product better than the average person would.”
Thanks for reading.
If you’re interested learning more about Steve Wozniak’s genius, take a look at his Floating Point Routines for the 6502 or the document, System Description: The Apple II. For another look at the early days at Apple, check out this interview (video).