Tests are a technique to manage programmer anxiety about code. When I feel anxious about some aspect of my code I write a test case.
Does programming language affect level of anxiety? Definitely. Does programmer skill affect level of anxiety? Absolutely.
Writing tests becomes more important when you're part of a team. Your choices affect not just your anxiety but that of your teammates. That's why it's reasonable to be more dogmatic about TDD in a team.
A lot of 'getting better at TDD' is just getting better at listening to yourself. When I started programming the little anxieties would pile up until I'd painted myself into a corner. With experience I pay more attention to the little anxieties.
After some time doing TDD I feel less anxious just knowing that I can write a test if I want. The benefit of the tests as an artifact is secondary to me; what they primarily do is keep me from getting stressed and giving up to go play poker.
And I don't have to worry about side effects from writing tests.
You're taking me too literally when I say I want to manage anxiety. If medication is a solution, so is not hacking at all, or just remaining inexperienced and non-introspective about my coding. Anxiety usually has good reason, and it requires improving the _codebase_. But my metric for how the codebase is doing is my own perception as I live and breathe it.
I have a love-hate relationship with anxiety. I need to listen to my perceptions, because that's key to where the code comes from. But those perceptions also have the ability to demotivate me away from the code. It seems like an obvious connection to me ever since my experience with burnout. Learning about the non-linearities in my motivational structure makes me a better programmer.
Has Kent Beck influenced me? Definitely. Listening to myself works for me. I don't see how thinking more about how I operate and how I learn my skills can do more harm than good. Paraphrasing Sun Tzu, "Know yourself". http://en.wikiquote.org/wiki/Sun_Tzu
Basically, the value of unit-testing everything drops considerably when you move from OO to writing mostly side-effect free code and testing expressions in a REPL. That doesn't mean that unit tests become worthless; it means there are more cases where they aren't worth doing because their cost exceeds their benefit. One area where the benefit does still exceed the cost, in my opinion, is when you're working with complex algorithms. But that's a far cry from test-everything.
The weakness of the test-everything school is that they don't take into account the cost of writing and maintaining tests. They act as if the benefit is non-trivial and the cost is trivial, which is why they think something's wrong with people who don't agree with them. But the cost isn't trivial.
The other half of this article, that Clojure code requires less testing, is also interesting. I've noticed the same thing myself. Once the author had specified the problem, I thought of the solution in my head "he's going to map over the epochs, rounding them to dates, and then call merge-with". Scroll down, yep, almost exactly what I had in mind.
I don't normally do that in other languages. I attribute a large part of that to the map/filter/reduce paradigm. Functional languages tend to have a much more expressive vocabulary than C/C++/Java. Rather than writing a for loop to filter an array, you just write (filter ...). The language is almost declarative, in that you specify what you want to happen, rather than how.
Tests are an important part of developing these days. They should count in pg's assertion that program shortness == power. Needing to write fewer tests to be sure of a program's correctness is an important attribute.
I would say that MAP/FILTER/REDUCE are relatively trivial applications of Functional Programming. Add to that lack of side effects, then it gets really simple. What would one want to test with these simple examples. But how about more complex code, like an XML parser in a functional language. No tests? I doubt that.
If your writing little functions in a REPL you get to see the results of that code immediately, in a sense, that is test-driven -- the verification aspect is present. What isn't present is the test-first aspect that ensures your code is easily testable, which is valuable. And you don't have the test code to keep in a suite to run whenever to check for harmful synergies.
You could probably write a REPL with the appropriate commands that would build rudimentary test code from lines you executed that did what you wanted them to.
You could probably write a REPL with the appropriate commands that would build rudimentary test code from lines you executed that did what you wanted them to.
I did exactly this, in a previous job where we were required to unit-test a lot more than I liked. I always mess around with stuff in the REPL a lot anyway, and it was dead simple to write an Emacs command to turn my REPL sessions into unit tests.
That's the best idea I've seen in a long time. Give an expr, get a value, and if you like it, type something meaning "add a test that evals that expr and expects the value I just saw". The only risk is convincing yourself that what you got looks right when it's actually not.
doctest comes with Python. You paste from REPL sessions into doccomments, and use a little utility function to automatically find/run them.
It's not as useful as you'd think -- the only way to structure the tests is by the class or function the comment is on, and you have to go out of your way to avoid default __repr__ returns of the form "<object foo at 0xADDRESS>", as the expected response handling is ANAL.
Yes, but I often use Lisp expressions as quasi documentation when learning someone else's code. How does this function work? Let's call it from the REPL. Maybe that's too complicated? Let's copy some inner bit of it to the REPL and play with that. Ok, I see how that works, now let's try calling the whole thing.
This 'play with some inner bit until you understand it' technique is interesting in a couple of ways. It means you're bringing the code to life piece by piece; and it means you're reading it inside-out. Both of those things were revelations to me.
As an aside, this gets harder to do to the degree that the code is written in an OO-style (even in Common Lisp) because you typically have to create other objects before you can bring code to life, which is usually not obvious how to do and bogs the process down.
Right, this becomes problematic with OO code. It also is problematic with large libraries when you're trying to figure out where to start. I.e. what are the three functions I need to call to run this search engine library.
I do the same but I usually end up writing the tests in order to understand their code. "Is this input allowed to be null? Hmmm... write a test with it null. Ouch! let's add foo may not be null to the documentation ..."
Does programming language affect level of anxiety? Definitely. Does programmer skill affect level of anxiety? Absolutely.
Writing tests becomes more important when you're part of a team. Your choices affect not just your anxiety but that of your teammates. That's why it's reasonable to be more dogmatic about TDD in a team.
A lot of 'getting better at TDD' is just getting better at listening to yourself. When I started programming the little anxieties would pile up until I'd painted myself into a corner. With experience I pay more attention to the little anxieties.
After some time doing TDD I feel less anxious just knowing that I can write a test if I want. The benefit of the tests as an artifact is secondary to me; what they primarily do is keep me from getting stressed and giving up to go play poker.