Correlation And Causation
“The quality of a software product cannot exceed the quality of its requirements.” – Phaneendra Nath Vellanky
“The quality of a software product cannot exceed the quality of its requirements.” – Phaneendra Nath Vellanky
The past couple of days I wrote about the dangers of providing too much functionality. In a fit of cognitive dissonance I now want to contradict myself and demand dangerous power when it suits my needs.
I’ve been working the past week to get a particularly gnarly application running in a set of docker containers. There are over a dozen services, plus a Rabbit queue and a database. Many of the services do not handle database connection failures in a robust way. During my testing I wanted a simple way to ensure they waited a bit before trying to connect, as the database container needs a minute or so to seed itself and get ready for connections.
Unfortunately,docker-compose
does not have any form of manual startup delay feature. This is by design, as the Docker team (rightly) argues that having services intolerant to connection failure is a bad thing. However, it’s frustrating to not have the power to do the wrong thing in the short term.
Then again, it turns out it wasn’t too tough to augment my compose file with a depends_on
clause that includes a health check, which is a more reliable solution anyways.
Giving a user too much flexibility can be a dangerous thing. Better to do the hard work of separating actual requirements from “desirements” (as an old government customer of mine used to say).
Yesterday’s lesson: the Perl HTML::Tidy
library doesn’t handle certain UTF-8 encoded characters properly. In particular, it truncates a non-breaking space (code c2 a0
) into a bare control byte (c2
), which at best gives a mangled character, and at worst an invalid encoding sequence. Pass that result to another utility, and you can expect failure.
The above incident was particularly difficult to debug because the app in question does not keep edit history. I was reminded how valuable it can be to track changes over time, not just in source code, but about the data on which an application operates as well. Made me think that git
might not be a half-bad back-end storage mechanism in many situations. Anyone have experience with that?
It happens to every developer at some point. You spend a bunch of time trying to determine the source of an urgent bug, only to find out the problem was caused by action or inaction of the user. It’s easy in that moment to be frustrated, but may I suggest a more circumspect path? It behooves a thoughtful developer in these moments to consider if the source of the user error was caused by poor design. Perhaps the button wasn’t in an obvious place, or the side effects of the command were not obvious, or the name of the feature didn’t describe the outcome. In many (even most) cases, user error is preventable with good design.
Yes it’s difficult, and perhaps impossible in some situations. But it is the high calling of the software engineer to design products in a way that a user almost subconsciously knows how to operate without error. Viewing design with this attitude saves a lot of frustration.
It might seem this is a counter argument to Not Even Mostly, but actually they go hand in hand. A user must be carefully listened to and considered, but sometimes they must also be guided into the features they really need, versus what they say they want. Do that hard work up front, and you’re more likely to have a system that minimizes the potential for mistakes.
Also, go read The Design Of Everyday Things.
The Internet is a funny place. Yesterday was the first weekday in some time that I didn’t write a post, yet I had the most page views in a single day since I created this thing. Apparently someone (or some-bot) in Canada decided to read every single post I’ve ever written. A roughly similar thing happened a few weeks ago, when a post I spent quite a bit of time on got only a handful of views, while the filler I wrote the next day got three times as much traffic. I’m not complaining, just observing that it can be difficult to predict how consumers will respond to a product.
I think there’s a lesson there for aspiring software developers (and really creators of all types). Don’t get too hung up on numbers or popularity. Don’t think less of yourself just because your app didn’t blow up like Facebook or Instagram (those guys will tell you that was luck as much as it was hard work). Simply do the best work you can.
When I decided to revive this blog, I wanted to post daily for two reasons. I figured it would draw more traffic to have more content, but more importantly, my writing muscles had atrophied and needed regular exercise. Ultimately this whole thing is for my own enrichment, but if it helps others, great.
Customers are a finicky bunch (they’re human, just like everyone else). That means they’re not always right, and any business practice that assumes they are is likely to fail in the long run.
Don’t hear me wrong, I’m not saying that software engineers shouldn’t listen to customers. Nor am I saying businesses shouldn’t careful consider their customers’ demands and in certain situations give in. I’m really speaking more to an attitude of continual acquiescence. That’s not helpful for a customer who may not have the skill to evaluate what he wants, and it’s not healthy for a developer when they see their professional opinions thrown to the wayside.
If a relationship isn’t a two-way street, it’s probably not worth having.
Last night I wrote my first Cordova Plugin (a little tool that allows an app to determine the local IP address on a Windows 10 device). I was proud of my success given limited documentation and a poor development environment (just a Surface 3 and command line tools).
What made me particularly excited, though, was that I could give my update back to the open source community via Github. Every developer on Earth has benefited greatly from the availability of high quality and easily modifiable free software, myself not the least. I enjoy every opportunity to give back in some small way, and I encourage all developers to do the same.
If nothing else, it makes your résumé significantly more attractive.
Does anyone else have a hard time finishing a project? I suspect it’s a common theme among developers. At the beginning, a project is fresh and new, and it’s fun setting up new tools, cleaning the slate, and getting that first prototype up and running. But as time goes on and the needed features pile up, excitement wanes. Your clean initial bits of code have been cluttered by refactoring and redesign as requirements evolved and unexpected complexities emerged. What was once new is now routine when you’re adding feature 42 of 50, and by the time a task is 90% done, you’re tired of looking at it and desperate for something different.
You’re not alone in this feeling; it’s a well documented phenomenon across a variety of creative disciplines. But fight that tendency, my friends, and push through, because a finished imperfect project is better than a perfect unfinished one.
My theory is that the inability to finish is a combination of the 80/20 rule, unavoidable code rot, and the Creator’s Curse. Naming these issues is the first step to mitigating them, so don’t be afraid to call them out when you see them, both on your team and especially in your own work.
I know personally it was a barrier to getting this blog going again, and it’s a problem I still fight. Am I totally happy with this post? No, not really (writing it while trying to listen in on a teleconference doesn’t help). But I’m clicking publish anyways.
I was busy today doing actual work. It happens. See you Monday!
Developers may like to write software, but that doesn’t mean we want to fix your computer (or even know how to fix it, for that matter). Nevertheless, we’re often asked, and sometimes try. A former co-worker of mine used to complain about his neighbor’s constant IT requests. “Toaster Lady” he called her, because she’d say “I want my computer to ‘just work’. Like a toaster.”
There’s a lot for those of us in the software industry to unpack in a statement like that. In particular, I was reminded this weekend that getting software applications to the point where they “just work” can be incredibly difficult.
Part of this relates to the phenomenon of simplicity that I’ve written about before. It takes effort to design interfaces that are both simple and functional for a broad range of users. And there’s a temptation to put aesthetics before all else. Resist it (and read Don Norman’s seminal work on the subject).
Implementation of a simple design is not simple. In fact, it’s often tougher to build code that does simple things well, because nothing is simple with computers. Beneath the Google search box lies an unimaginable stack of data, algorithms, networks, and hardware, all of which works together in concert to find that perfect cat video. It takes an army of people to keep it all running (because everything is always breaking all the time). Not to mention the even larger army of people who designed the individual elements, who could only do so because of the work of even more people whose research and ingenuity gave rise to computing machines in the first place. Simple search? Ha, there’s no such thing.
And the work required continues to grow exponentially into testing. All possible permutations of use cases must be tested to flush out potential problems. Have two buttons? Well, that’s four tests. Add a third, now you’re up to eight tests. Oh, and even that isn’t covering that one weird case where if you press the same button fifty times in a row and then hit button three the software crashes. Now expand that to a box with arbitrary text input? The possibilities are staggering (but not endless; there’s a big gulf between large and infinite, but that’s a post for another day).
Consider all of this next time your technology fails you, and be thankful that it ever works at all.