With the holidays coming on, many of us are heading up to the attic to retrieve the boxes of decorations that have been waiting all year to be called into service again. In my family we put up and decorate a Christmas tree each year, but I suspect Hanukah and Kwanza, etc. have their festive ornaments too, and probably electric lights are involved.
One thing I’ll do this year, as I do every year, is to lay out the strings of lights on my coffee table and plug them all in, to see if any of them fails to illuminate.
My parents did this too, but they had a different kind of light set than I do… the lights in those days used a screw-in connection, like a typical light bulb, and were wired in simple series. Because of this, if one light burned out the entire string would go dark, and you’d have to check each bulb to find the bad one. Luckily this did not happen that often and we used the same strings for years on end.
Modern strings, the ones I have, are usually different. They have a simple push-in connection for each bulb, and the design includes a bypass mechanism in the sockets such that even if one bulb goes out the rest of the string will stay lit, making the bad bulb obvious. Good idea, because the bulbs are smaller and there are many more of them (my strings have 150 lights per string; my father’s had maybe 15).
So, with this modern design the entire string should never go out. In theory.
I’m often reminded of a quote Al likes to use in class, alternately attributed to Yogi Berra or Jan L. A. van de Snepscheut: “In theory, there is no difference between theory and practice. But, in practice, there is.” I almost always have a light string or two that is dead.
Why? There are a number of possibilities. These modern strings are also made much more cheaply than the ones my parents owned. Sometimes, because of the simple push-in connection and the soft plastic of the socket, a bulb gets in only partway, or twisted slightly. Sometimes the cheap little bent-back wires sticking out of the bulb, which are supposed to make the connection, will break or bend the wrong way. The wiring between the sockets is also lower quality and can develop breaks. The pass-through mechanisms in the sockets are also cheaply made and can fail. The plug at the end of the cord, cheap plastic again, can fail, or the fuse inside it could be blown.
What do I do with such a string? The same thing I suspect you do; I throw it away. Finding the problem would take too much of my time to be worth it, especially given how low-cost a new string will be anyway. I might check the fuse, but beyond that, I toss it. Wouldn’t you like to do that with some of the legacy systems you deal with?
So, this is part one of my analogy: even a “better” design idea will not produce greater value if quality is allowed to suffer. You can code an Abstract Factory as a single class with a set of methods that each have a switch-case statement, all based on a control variable, but the fact that you “used a pattern” does not mean your code is good quality (or vice-versa). This can really matter when you have to debug, enhance, or otherwise maintain it. In other words, pretty much always.
But let’s take this farther. Each of these failure possibilities is a lesson.
Each socket is dependent on the wiring that leads to it, and away from it, and upon the proper behavior of each socket those wires connect to, and to the sockets they are connected to, and so on. This coupling means that a failure of anything in any socket can affect other sockets, causing them to fail. And, all sockets are coupled to the plug, and the fuse inside the plug, and the electrical system in your house, etc…
Each socket has a number of reasons to fail because each one actually does multiple things. It supplies energy to the bulb, ensures the bulb is properly positioned in the socket to receive it, and it passes energy through to the next socket. This lack of cohesion in the sockets means it is hard for us to know which of these aspects is failing when the string goes dark.
Finally, worst of all, every socket is a repeat of every other socket. This redundancy of design means that it is impossible to know which one of them is failing, since they are all candidates for all the same failures. What if two or more of them are failing? It will not be enough to swap out each bulb in turn… because if many of them have badly bent wires or many are twisted in their sockets… what a nightmare.
What if I had a device that I could plug my string of lights into which, with a simple press of a button, would test every individual aspect of my string and tell me exactly what was wrong, immediately? That would be wonderful! I’d never throw a string away again. This is very much like an automated suite of unit tests.
But, we’ll probably never have such a device. The manifold coupling, weak cohesion, and multiple redundancies would make it too hard to achieve. That’s why legacy code almost never has tests. The lack of quality usually makes them too difficult to implement.
We can follow this analogy yet farther.
Let’s say I discard and replace any bad strings and so now all my strings light properly. Now I put them all on the tree, and then add ornaments, garland, tinsel, popcorn strings, etc… Beautiful!
On Christmas Eve, just as my friends and extended family are about to arrive for our celebration, one string in the middle of the tree goes out. Big dark spot, right in front. It looks terrible and will spoil things.
Now throwing it away and replacing it is not an option; it has become too entangled with everything else on the tree. That laborious socket-by-socket, wire-by-wire, arduous inspection of the string (which was not worth it to me before) is now my only option. It will actually be made more difficult (and much more unpleasant) because the string is in place on the tree. It’ll be several hours of pine needles in my eyes and broken ornaments before I solve this problem, if I ever do. Everyone’s due in four hours, the deadline approaches, Andrea wants to know when I’ll have it working, and when I’ll be available to help with the hors d’oeuvres…
Our software, and its quality, does not affect us alone, because increasingly software is being created from other software; we create services which may well end up in the center of a system or systems that we did not anticipate. We depend upon the good work of other developers, and they depend on us.
Quality is worth it, if we want to be able to create software with persistent value, rather than systems we simply re-write and throw away on a regular basis. As software becomes more important in the world, and as there is more and more of it to enhance and maintain, focus on quality becomes increasingly important.
Good quality software is understandable, testable, and can be changed to meet the ever-changing needs of business and individuals. It is a Timeless Way of Building, so to speak. J
Now, if you’ll excuse me, I need to get the ladder and climb into the attic…
-Scott Bain, Christmas 2008-