Writing stupid code is actually really difficult.
For me, it takes a little bit of iterating before I know just the right place to insert stupid.
Writing stupid code is actually really difficult.
For me, it takes a little bit of iterating before I know just the right place to insert stupid.
(Often attributed to Mark Twain, but similar sentiments were expressed by many before him.)
Kinda goes: 1) Make a bad solution exploring the problem 2) Explore a good idea for how to solve the now-understood problem 3) Mature the good idea through usage.
It's really an issue of not being sure at first what needs to be flexible & data-driven vs handled in code. If make everything data driven, then it becomes this horrible mess where your input is basically a program and your actual code ends up being a terrible interpreter.
I tend to just build things bottom-up, and start with a small bit of functionality, then when I have enough small bits, I bolt them together and decide what I need to abstract at that point, do refactoring on the smaller bits and provide data to them from the caller. Then repeat that continuously until I have all of the functionality I need.
It might be different for other people, but I need to have working code before I can it abstract.
To provide a more concrete example, say I have a function that performs a transformation on a piece data. From what I currently know about the data, I can parse it using a regex. So I code up the function that accepts data, it runs the regex and provides the transformed result. Great.
Now as I'm continuing my work, I notice that some other data requires a similar, but not exactly the same transformation. It can be done with a slightly different regex. So rather than duplicating functionality, I modify the transform function above to take a regex as input along with the data. Everything works as expected.
I get further along in the project and I realize another piece of data needs a somewhat similar transformation, but this time it's just slightly too complicated for a stand-alone regex, it needs to be a function.
The "smart code" way to handle this would be to create another transformation function and call that instead. The "dumb code" way of handling this is to generalize the transformation function such that I can pass in some descriptor for the transformation, and have the transform function return the correct result.
That's the crux of the issue. I rarely have enough information at the time of writing to know just how generalized to make a function. If I created this hyper-generalized transformation at the beginning, but never needed anything beyond the original simple regex, I would have wasted a bunch of time creating code that's needlessly confusing.
TDD is perfectly applicable for development, and would help tremendously with the refactoring aspect, but what it doesn't help with is information that you don't yet know about.
The difference is that you only need to support a tiny fraction of possible features / use cases, but your algorithms need to be correct for a wide range of inputs.
For an algo, let's say it operates on a list, I'll start with test f([]) == 0, and implement f to output the constant 0.
And then go from there.
Tests are good, but they need to be universal for any implementation, which means you often cannot tests the internal details that prove you didn't use bogo sort (picking a pathological example to make the point)
When one says "wide range of inputs", as gp did, one is not talking about low-level algorithms; one is talking about a business algorithm. You should be using TDD for this.