I just finished the nastiest debugging experience of my career–nearly 3 weeks on a single bug. After days and days of staring at code, swearing at core dumps, tailing logs, connecting to gdbserver via a multi-hop ssh tunnel from inside a secure environment, and general programmer misery, I felt like doing cartwheels when I finally figured it out, tweaked a few lines of code, and observed stability again.
Hindsight teaches me this lesson: undocumented, unhandled constraints waste enormous amounts of time and energy. If you’re interested in writing good code, you must know your limits, and you must communicate them. This especially matters when the constraints are obscure or surprising.
image credit: ericdege (Flickr)
My bug seemed simple enough at first blush: Continue reading
One of the codebases that I work on is theoretically C++, but if you peer under the hood, it looks more like 1990-vintage C. It’s 500 KLOC of almost purely procedural code, with lots of structs and few true objects. More dusty and brittle than I’d like.
I am not a C++ bigot; I first began to do serious, professional coding in C, not long after this codebase got its start. I understand the C-isms pretty well. And although I think Linus got carried away in his rant about the ugliness of C++, I can appreciate the ways that lean C sometimes makes its descendant look ugly and inefficient. (Though C++11 and 14 are making this less true…)
This means that I don’t consider the C-like style of this particular codebase a fatal flaw, in and of itself.
However, since my early coding adventures I’ve been converted to the advantages of OOP for complex projects and large teams, and I’ve also accumulated a lot of battlescars around multithreading. Our codebase needs OOP to solve some encapsulation antipatterns, and it needs RAII and C++11-style mutexing in the worst way. Its old, single-threaded mindset makes far too many things far too slow and error-prone.
A few months ago, we decided to make an investment to solve these problems.
To do it right, I had the team add a story to our scrum backlog about making the codebase const-correct. And therein lies a tale worth recounting…
It’s the season for coughs and sniffles, and last week I took my turn. I went to bed one night with a stuffy nose, and it got me thinking about software.
What’s the connection between sniffles and software, you ask?
Let’s talk redundancy. It’s a familiar technique in software design, but I believe we compartmentalize it too much under the special topic of “high availability”–as if only when that’s an explicit requirement do we need to pay any attention.
Redundancy can be a big deal. Image credit: ydant (Flickr)
Redundancy in nature
Mother Nature’s use of redundancy is so pervasive that we may not even realize it’s at work. We could learn a thing or two from how she weaves it–seamlessly, consistently, tenaciously–into the tapestry of life.
Redundancy had everything to do with the fact that I didn’t asphyxiate as I slept with a cold. People have more than one sinus, so sleeping with a few of them plugged up isn’t life-threatening. If nose breathing isn’t an option, we can always open our mouths. We have two lungs, not one–and each consists of huge numbers of alveoli that does part of the work of exchanging oxygen and carbon dioxide. Continue reading
photo credit: nandadevieast (Flickr)
Before the industrial age, “features” were noteworthy aspects of a face or a geography: a patch of color, abundant wrinkles, a scar… The human brain is stunningly good at identifying and comparing such features–perhaps because that ability has been central to our nurture as children, our bonding into family units, and our survival as a species.
When we want to say what a face looks like, we describe its features. They are an entrée into experience with it.
At the dawn of the computer age, the advertising and publishing industries were already talking about how products–or aspects of them–could be “featured” in media. Highlighted characteristics were called “features”, and this metaphor transferred seamlessly into digital language. Software product managers now traffic in “features” and “feature sets.”
We use the term so comfortably that we sometimes forget what it has to teach us.
Project management 101 teaches that, when managing outcomes, you cannot alter scope, schedule, or cost (resources) without affecting at least one of the other dimensions. This interrelationship is known colloquially as the “Iron Triangle.” Sometimes we put “quality” in the middle to show how it is unavoidably shaped by choices on the other constraints:
Image credit: John M. Kennedy T (Wikimedia Commons)
Lots of Dilbert cartoons derive their humor from the unwillingness of the Pointy Haired Boss (PHB) to acknowledge this relationship. These cartoons are funny because they are so eerily similar to conversations we’ve all had, where someone wants us to deliver ultra-high quality, on a limited budget, in an aggressive timeframe, with a boatload of features.
It ain’t gonna happen, folks. We engineers are clever, but we’re not magicians. Triangles don’t work that way.
You’ve learned some good principles when you can articulate this geometry lesson.
But there’s more.
Truth 1: Scope is a trickster
Many well meaning managers and executives understand this trilemma, and they distance themselves from Dilbert’s PHB by acknowledging that something has to give. “I pick scope,” they’ll say. “We absolutely must have the product before the summer doldrums, and we only have X dollars to spend, but I’m willing to sacrifice a few features.”
This can give product management heartburn–feature sets sometimes hang together in ways that make slicing and dicing dangerous. An airplane that’s good at takeoffs but that can’t land is unlikely to be a commercial success. Good product managers will point this out, and they’ll be right.