Yes, and if the initial design is bad enough then refactoring becomes equivilant to reimplementing.
Agreed, though this still doesn't ring as much of an alarm with me. *shrug* The XP guys call it a "spike refactoring".
When I was at Evans & Sutherland, we were developing a graphics driver for an amazing video chip. The typical video card back then was 32MB and you could get 64MB if you were willing to pay $400 for your video card. The card we were developing had a bottom-end price point of $2500 and came with 256MB ram, though you could get a $6500 version with a full gigabyte.
Anyway. The chip was in the fab when we discovered a major flaw in its design. If you did 3D rendering to a texture, then did a 2D blit to the texture, you ended up with undefined results because the 3D operations were piped but 2D operations were instantaneous. If you rendered a cube and blitted it to the screen, you got garbage: the blit was over and done long before the 3D operation came out of the pipe.
But the chip was in the fab, and fabbing chips of that complexity was a 3-month process back then (this was in late 2001). It would cost about US$1M to turn the chip, and we'd instantly lose 1-2 months from our ship date. We couldn't change the hardware. We had to fix it in the driver. The task: figure out how to synchronize 3D and 2D without sacrificing 2D speed unnecessarily. It took a week of yelling and shouting in the conference room, and several whiteboards were completely filled with calculations to determine the speed impact to various operations. We ended up with a sync mechanism that had to be implemented everywhere in the driver, top to bottom. I figure maybe 1% of the codebase was changed, but that 1% was in every single file.
It took 6 engineers a week to implement, and the remaining 46 engineers on the team another 2 weeks to get adjusted to using it. But in the end, the project never really stopped moving forward.
I remember those weeks as being a bear to slog through, but it wasn't a total nightmare. That's the experience I think of when you mention "a complete reimplementation", and its why I don't flinch (much) when I insist on doing things simply at first: I've counted the cost, I've paid
the cost, and my experience tells me that paying it again is cheaper than muddling things up front.
EDIT: It's quite clear that not only are we not on the same planet wrt to what we do, we're not even in the same solar system so different attitudes towards this are understandable.
You know, I get that a lot.
I don't know how far apart we are, really, though. I've never done operating systems, but I've done device drivers, video games, vibration control, realtime networking, and the odd bit of motherhuge dataset processing. I got to the opinion I hold today because of those industries, not in spite of them. If my perceptions are vastly different from your own, chalk it up to weirdness on my part.
Well, that all comes down to how you define optimization. If you call anything other than the simplest possible implementation "optimization", then you're going to paint yourself into a lot of corners.
You're exactly right! And, in fact, what I'm advocating to the younger programmers out there is that they should paint themselves into these very corners. See earlier comment about counting the cost. To borrow an XP phrase, "when you painted yourself into a corner, you've located the precise spot to place a door."
And how is picking fast algorithms not an optimization? ... but I do worry about complexity.
I think we're on the same page, here. I'll use a faster algorithm if it's easy to implement and doesn't massively impact the complexity of the application. Otherwise, I'll use the simplest, easiest to read algorithm that comes to mind.
eg, if you know you'll have to make at least X many transactions per second and each one takes at least Y bits, and X*Y is several times Z the network bandwidth, then there's just no possibility that it can be done without a cache. We don't have to profile it to know that.
Here we're definitely on the same page. This is what I meant by O(data/s) being a significant fraction of O(processor/s). Or in your case, O(bandwidth/s). If a quick bit of back-of-the-envelope math tells you that you have a design constraint to worry about, then go ahead and worry about it. Ignoring it is willfully stupid.
I think we agree. If it's not free there has to be a damned good reason to do it, like "We can say for sure it's impossible without this.". If there's two similarly hard ways of doing it and experience tells you one will be significantly faster without your having to mull it over, it's okay. The rhetoric is a necessary evil so people who don't have the experience to do this well won't try until they learn where the exceptions are through experience.
Yes. This is exactly what I was on about. I recently read some code of another programmer. It was heinously complex, using parallel data structures and the clients of his module had to know how the internals worked in order to keep the data synchronized. When I asked him why (in the hell!
) he did it that way, he said, "Well, it needs to be fast. If I just use a queue it'll be too slow."
Poor guy thought he'd win a cookie; instead I went four sigma past tantrum. I had already done a quick bit of envelope math and determined that his code needed to handle sustained throughput of 100 messages per second, with rare bursts of up to 1000 messages per second. He could have been writing them to disk and reading them back in that amount of time.
My only regret is that, after burning him at the stake, I didn't make his next-of-kin rip out his code and implement a queue.