The Kolmogorov complexity of COM is, at the very least, hundreds of kilobytes of itchy, fidgety, sensitive, and complicated code. The Kolmogorov complexity of xor'ing two pointers to save 32 bits is on the order of tens or hundreds of bytes. (I'm using the term a bit loosely, obviously, but I think it gets the point across.) I suppose it depends on the limit of "slightly", but in context I think it's clear we're talking about "techniques" that are more than a three line hack in your linked list library. YMMV. (That is, I do see the point you are trying to make.)
Presumably, the duct tape programmer is doing that because it is the difference between making the product go and not making the product go, not because they love bit packing. It's not a technique I'd adopt today, but Zawinski (just to choose one example from his repertoire I've read about) was trying to make machines with, say, 8MB of RAM able to read thousands of email messages. You get a bit nutty under those constraints, or you ship slow crap. There isn't much of a third choice. (Fast and featureless, maybe.)
(I think I can bid lower than 8MB of RAM, too, but I'm a bit fuzzy on netscape timeframes vs. ram timeframes. I think 4.0 was in the 32-64-128MB era, putting 3.0 a ways back, but I'm not sure.)
I see what you're saying, and I agree. It's not comparable to COM.
I think the thing is, articles like this tend to create some idealized programmer that is just a conglomeration of attributes the author likes even if they are mutually exclusive. To me, avoiding complexity and doing bit manipulation are mutually exclusive.
It's like saying you should use left shift (or is it right...?) instead of diving by 2. Ok, it may be faster. Or the compiler may just do the same thing regardless how you type your code. The point is that "/ 2" means divide by 2 to anyone at all familiar with code. Unless you have some really compelling reason to do otherwise, you should use "/ 2".
Using shifts for division (or various other bit manipulation) may be how your idealized programmer shows their classical training, but don't kid yourself into thinking that bit manipulation fits into all your other ideals for programmers.
Joel's idealized programmer also avoids unit tests. Are you serious? How can this possibly be a good idea? No, your customers don't care if you wrote unit tests... in the same way you don't care if your architect does whatever it is architects do to ensure the accuracy of their work. But that's just the point. You don't care (nor should you) about how they ensure accuracy. You care only that they do. So no, your customer doesn't care if you wrote unit tests, but I assure you they care if your software crashes or gives inaccurate information.
Of course, no one ever creates an idealized programmer without creating their opposite. Joel's "ideally" bad programmer multiply inherits from 17 sources. Does any sane programmer really do this? No. Of course not. Why bother mentioning it? It's like saying an idealized pilot is not like those other pilots that intentionally crash their planes. Well... no one intentionally crashes a plane. Don't bring up absurd examples to prove your point. If real life doesn't prove it, then it's not a valid point.
The simple fact is that when I look at my own real-life, deployed-in-production code, I find this: The code I wrote just to get a problem solved in whatever way possible (duct tape) becomes more and more of a liability as the requirements change. With the code that I spent the most time designing (assuming I eventually came up with a good design), the more the requirements change, the more I see the beauty of the design. When a change in requirements can be fixed with a find/replace, it's a job well done. Duct tape code leads to duct tape maintenance. Duct tape maintenance leads to thedailywtf.com.
I have no problem with emphasizing the importance of shipping software. I have a problem with people saying "real programmers use butterflies" when they aren't writing a web comic.
I don't think there's a single "real programmers" article in the universe that is internally consistence (doesn't advocate any mutually exclusive practices). Like I said, it's an ideal, an ideal constructed out of everything the author could find in their mind, whether it fits together or not. This wouldn't be a problem if the author admitted even a slight possibility of exaggeration or lack of internal consistency, but they never do.
Now... I think by now I've probably exaggerated and broken internal consistency enough for one day, so I'll stop here.
Unit tests have sometimes been a great help, especially for regression tests, but they can get in the way, especially if you actually want to ship.
I can see the benefits of getting the 1.0 to market first (if buggy), getting some market share and using that lead time to either iron out the bugs or to rewrite so you don't have to put up with duct tape maintenance.
I've been in a situation where the users started using the prototype because, despite being buggy as hell, it did stuff light years ahead of what they had before. So imo duct tape 1.0 is ok.
I don't see from your argument how unit tests keep you from shipping. You can still choose to ship a product with failing tests. The difference is now you know what (some of) the bugs are.
> With the code that I spent the most time designing (assuming I eventually came up with a good design), the more the requirements change
Your use of "assuming" is interesting. Sometimes it's hard to know if it really was a "good design" until after the requirements change...
"The competent programmer is fully aware of the limited size of his own skull. He therefore approaches his task with full humility, and avoids clever tricks like the plague." - Dijkstra
You're quite right with unit tests, I often wonder why people only seem to state their about regression. Two and a half years into my project I think our tests have only caught one or two relatively tame regressions. I mostly use them to test new components (that would be hellish to QA manually as the system is so big it takes a while to build->deploy->run), large refactoring of components and integration tests (like spamming our transaction service randomly and ensuring it always outputs valid files)
Comments
The Kolmogorov complexity of COM is, at the very least, hundreds of kilobytes of itchy, fidgety, sensitive, and complicated code. The Kolmogorov complexity of xor'ing two pointers to save 32 bits is on the order of tens or hundreds of bytes. (I'm using the term a bit loosely, obviously, but I think it gets the point across.) I suppose it depends on the limit of "slightly", but in context I think it's clear we're talking about "techniques" that are more than a three line hack in your linked list library. YMMV. (That is, I do see the point you are trying to make.)
Presumably, the duct tape programmer is doing that because it is the difference between making the product go and not making the product go, not because they love bit packing. It's not a technique I'd adopt today, but Zawinski (just to choose one example from his repertoire I've read about) was trying to make machines with, say, 8MB of RAM able to read thousands of email messages. You get a bit nutty under those constraints, or you ship slow crap. There isn't much of a third choice. (Fast and featureless, maybe.)
(I think I can bid lower than 8MB of RAM, too, but I'm a bit fuzzy on netscape timeframes vs. ram timeframes. I think 4.0 was in the 32-64-128MB era, putting 3.0 a ways back, but I'm not sure.)
I see what you're saying, and I agree. It's not comparable to COM.
I think the thing is, articles like this tend to create some idealized programmer that is just a conglomeration of attributes the author likes even if they are mutually exclusive. To me, avoiding complexity and doing bit manipulation are mutually exclusive.
It's like saying you should use left shift (or is it right...?) instead of diving by 2. Ok, it may be faster. Or the compiler may just do the same thing regardless how you type your code. The point is that "/ 2" means divide by 2 to anyone at all familiar with code. Unless you have some really compelling reason to do otherwise, you should use "/ 2".
Using shifts for division (or various other bit manipulation) may be how your idealized programmer shows their classical training, but don't kid yourself into thinking that bit manipulation fits into all your other ideals for programmers.
Joel's idealized programmer also avoids unit tests. Are you serious? How can this possibly be a good idea? No, your customers don't care if you wrote unit tests... in the same way you don't care if your architect does whatever it is architects do to ensure the accuracy of their work. But that's just the point. You don't care (nor should you) about how they ensure accuracy. You care only that they do. So no, your customer doesn't care if you wrote unit tests, but I assure you they care if your software crashes or gives inaccurate information.
Of course, no one ever creates an idealized programmer without creating their opposite. Joel's "ideally" bad programmer multiply inherits from 17 sources. Does any sane programmer really do this? No. Of course not. Why bother mentioning it? It's like saying an idealized pilot is not like those other pilots that intentionally crash their planes. Well... no one intentionally crashes a plane. Don't bring up absurd examples to prove your point. If real life doesn't prove it, then it's not a valid point.
The simple fact is that when I look at my own real-life, deployed-in-production code, I find this: The code I wrote just to get a problem solved in whatever way possible (duct tape) becomes more and more of a liability as the requirements change. With the code that I spent the most time designing (assuming I eventually came up with a good design), the more the requirements change, the more I see the beauty of the design. When a change in requirements can be fixed with a find/replace, it's a job well done. Duct tape code leads to duct tape maintenance. Duct tape maintenance leads to thedailywtf.com.
I have no problem with emphasizing the importance of shipping software. I have a problem with people saying "real programmers use butterflies" when they aren't writing a web comic.
I don't think there's a single "real programmers" article in the universe that is internally consistence (doesn't advocate any mutually exclusive practices). Like I said, it's an ideal, an ideal constructed out of everything the author could find in their mind, whether it fits together or not. This wouldn't be a problem if the author admitted even a slight possibility of exaggeration or lack of internal consistency, but they never do.
Now... I think by now I've probably exaggerated and broken internal consistency enough for one day, so I'll stop here.
Unit tests have sometimes been a great help, especially for regression tests, but they can get in the way, especially if you actually want to ship.
I can see the benefits of getting the 1.0 to market first (if buggy), getting some market share and using that lead time to either iron out the bugs or to rewrite so you don't have to put up with duct tape maintenance.
I've been in a situation where the users started using the prototype because, despite being buggy as hell, it did stuff light years ahead of what they had before. So imo duct tape 1.0 is ok.
I don't see from your argument how unit tests keep you from shipping. You can still choose to ship a product with failing tests. The difference is now you know what (some of) the bugs are.
> With the code that I spent the most time designing (assuming I eventually came up with a good design), the more the requirements change
Your use of "assuming" is interesting. Sometimes it's hard to know if it really was a "good design" until after the requirements change...
"The competent programmer is fully aware of the limited size of his own skull. He therefore approaches his task with full humility, and avoids clever tricks like the plague." - Dijkstra
You're quite right with unit tests, I often wonder why people only seem to state their about regression. Two and a half years into my project I think our tests have only caught one or two relatively tame regressions. I mostly use them to test new components (that would be hellish to QA manually as the system is so big it takes a while to build->deploy->run), large refactoring of components and integration tests (like spamming our transaction service randomly and ensuring it always outputs valid files)