Lessons from making software about using software
Here's a great question that gets passed around on social media every so often: "What is obvious to everyone in your profession but unknown outside of it?" Programmers can answer a closely related question: "How does making software change how you use software?" Here's a partial answer:
- I read all error messages as: "Something is wrong. Doing something different might help, or maybe there is nothing to be done." Error handling is very, very hard (the incomparable Dan Luu has written about this here and here).1 If I read your error messages as accurate and meaningful, you have earned a lot of trust with me.
- There are many features I don't trust. It's hard to say exactly which ones, because this relies on complicated intuitions about (e.g.) which ones are hardest to get right or most likely to be rushed into production. But I am keenly aware that just because it's in production, that doesn't mean it works. And it definitely doesn't mean that it does what the banner headline or the name of the feature makes you think it does.
- I am a lot quicker to "turn it off and on again" (force-quit the program, restart the device, or whatever) than almost all non-programmers. Software gets into bad states. The program often doesn't know what bad state it's in (see above). Such is life. Destroy the bad state and start over.2
- I value speed and low latency, and am much more likely to use software or features that are fast. Yes, all evidence suggests that almost all users strongly prefer speed and responsiveness, but I see myself actually choosing and rejecting software on this basis much more often than my non-programmer associates.3
These might make me sound grouchy, but I'm pretty sure that, all told, I'm happier with software and take more joy in it than non-programmers, not just in making it but in using it.2 What might appear to be cynicism is just realism, and realism that comes from a place of love.
If you want get the flavor of the problem: it's common to have a section of code that checks for errors and determines what result or message to pass to some other layer of code. These blocks might assume, explicitly or implicitly, that if an error is not X or Y, it must be Z. Or they might assume that any 4xx error means that an input was malformed. These assumptions might be wrong in the first place, and they're often "brittle" (in the sense that even changes in the codebase, even small or distant ones, might falsify them).↩
If I rely on software and/or have some hope of developing a mental model of it that explains the error and will help me later, I'll spend more time with a bad state. But most of my software interactions are not like that; usually I just want to, e.g., get the kiosk to print the piece of paper I want it to print.↩
Speed isn't the only characteristic like this. I suspect that this difference in behavior is a matter of (i) having a rich conceptual scheme in which to describe to myself what I do and don't like about some piece of software, (ii) believing that the software could actually be better than it is, and (iii) having trained myself to keep being dissatisfied with suboptimal software indefinitely (an important professional disposition!). But that's another post.↩