Hacker News new | ask | show | jobs
by Huggernaut 1547 days ago
Can you talk a little bit more about tactic vs strategic development?

What do you find ridiculous about doing the simplest thing to make a test go green first?

2 comments

Not OP, but I find TDD ridiculous as well.

Thinking strategically is understanding the trade-offs of your code, and coming up with good abstractions, that take these chosen trade-offs into account. You want to express the business problem in a language that is close to the domain, and then write a translation (and sometimes the translator) to the language closer to the metal. Coming up with the correct language how to express it (the language can be as simple as recognizing that your problem is a general one on which you can apply a known algorithm) is precisely the strategic thinking.

Applied top-down, it also means exhaustively understanding states of the application and major data structures (for example, database schema) and designing the functions around that. It can also be applied bottom-up, by building reusable tools and building blocks, which are independent on the global state, and then connecting them as simply as possible (this is also sometimes called hexagonal design). Both top-down and bottom-up have pros and cons.

I am much in favor (instead of too much unit testing or TDD) of building better abstractions that make humans less prone to errors (these can even be DSLs), building assertions into your code that warn you something is amiss (and can also be used in property tests), and always testing against something (i.e. the test code doesn't use the same assumptions as the program it is supposed to test, which is a big issue I have with unit testing). The best parts of the code are the ones that you don't have to test - if the compiler (or your abstraction) can guarantee you an assumption about your code, then you don't need to worry about it being wrong in the first place.

And in particular, the problem with "x+y in C++ can launch nuclear missiles" is not syntax, it is a weak type system (ideally you would use something like Haskell that controls the side effects). Again, using checks in a stronger language is a strategic, not a tactical decision.

I share their opinion. I understand "Do the simplest thing" to mean "ignore any additional insights you may have".

If I know that a class will need to be accessed from multiple threads, I am not allowed to use locks, concurrent data structures or lock-free patterns until I add the first test that checks for multiple thread access. When that happens, I need to throw away almost all of the previous implementation. The same happens for any special data structure or algorithm that I know in advance will be necessary to solve the high-level problem, but it takes tens of tests to reach a point where the "simplest solution" no longer works. As an exercise, consider implementing a Union-Find data structure while constraining yourself to never writing a line of code that is not the simplest thing to solve the current test.

My experience has been that it's better in those cases to construct a unit testing roadmap so that:

- you incrementally build the correct solution - you throw away as little code as possible - throughout the process, you minimize the amount of code not covered by a test

> If I know that a class will need to be accessed from multiple threads, I am not allowed to use locks, concurrent data structures or lock-free patterns until I add the first test that checks for multiple thread access. When that happens, I need to throw away almost all of the previous implementation. The same happens for any special data structure or algorithm that I know in advance will be necessary to solve the high-level problem, but it takes tens of tests to reach a point where the "simplest solution" no longer works. As an exercise, consider implementing a Union-Find data structure while constraining yourself to never writing a line of code that is not the simplest thing to solve the current test.

Who's imposing that constraint on you? Why? Can't you negotiate your way out of that?

TDD. That's the point of TDD and that's what people are arguing against. If you relax this constraint, you get something different.
I share the same sentiment. TDD is one of those things that are really nice on paper for trivial toy code like Cat extends Animal, but quickly becomes impractical and falls apart against real world problems.