TDD is horrible while learning a new language
peterevjan.com
peterevjan.com
I'm running into this exact thing right now on a new project that uses some tooling I haven't used before, and I'm doing an awful lot of yak-shaving. Some of it I would have done anyway just writing code with the new tools, but writing effective tests really does require a certain base comfort with the tools.
Your productivity is down, but that's expected, you're learning a new language.
Consider someone who wishes to learn how to drive a car and also how a car works under the hood. Learning how to steer and learning the complete function of the steering apparatus at the same time is not as effective (for me at least) as learning how to drive in one session with the mechanism either not explained or vastly simplified. At another time, I can learn about steering mechanisms and hear all about power steering and differential gears and what-not.
in the example given, don't mock out the file system, just use it. hard-code your paths. you can go back and fix that later - what you're doing now is getting basic tests sketched out so that you can learn.
so you're confusing "learning a language" with "writing a complete, portable system". of course you can't do the latter while doing the former - you need to make compromises. but ignoring tests is throwing the baby out with the bathwater. perfect is being the enemy of good.
[and i am not just bullshitting here - last week i was learning go and this is exactly what i did. the go getting started docs are very clear about how to run tests, and having tests to check i was understanding really helped.]
When learning, I often find it's most helpful to just plunge in, then when something isn't working, go back and write tests to try and hone in on the problem. Then more tests to make sure my solution works for edge cases. I find this is helpful even when I'm not learning a new language, and just when I'm trying to do something new enough that I can't see the outline in my head when I start.
It's odd how sometimes TDD helps you break down complexity into manageable chunks, and sometimes it front loads complexity, and forces you to solve problems you aren't capable of handling quite yet. Whenever TDD is making me bang my head, I tend to skip it for the moment and come back to it when it's helpful again.
If i know it before the implementation, I write the test first. Most of the time, I start programming and write tests for everything that gets nailed down. If I am in completely new ground, I start playing and do not test beyond "run and see".
I get the argument of tests as interface specification, but I just don't buy it. Some people may not like to model outside of code, aka UML or variants, but any reasonably complicated system needs a high-level concept drawn up before you can safely start pushing through individual components.
I love TDD for known problem/known solution scenarios, but I've found it to be a pretty bad time sink for unknown solution combinations. YMMV, and I think everyone finds their own comfort zone with TDD after some experimentation. The big lessons for me were that [x] testing is a net time saver versus the spray and pray code like hell strategy (yes, this makes sense before you realize you're not a programming messiah after all!) and that taking the perspective of a code consumer helps you write more fluent APIs.
But its totally fine to learn new languages and try out new stuff without it. TDD only needs to be enforced on code going into production.
However TDD (when done pragmatically) is actually a great way to dive into a language. The thought process of mocking the file system is actually _where_ you learn about the language/libraries/frameworks. You have to understand those APIs a little bit before you can properly mock them.
... like how do I run the tests? I run into this a lot when I code as well. But I have to remind myself that I don't need a runner from a framework in order to do TDD. Don't even need a framework.
There is nothing about TDD that says you have to use any unit testing library. It's a process. And if understood properly and used pragmatically can be an excellent way to learn a new language.
1. (If Applicable) How do I compile the code? What is the shortcut?
2. How to I get something to display on the screen/website?
3. How do I build unit tests in this language?
4. How do I run the unit tests?
5. Are there any tools like AutoTest available?
6. What are the preferred source control tools?
7. What frameworks are there? Are any of them by far the leader?
This can be expanded as far as you want to take it, but I think this approach would make things a little easier to swallow. By focusing on one question at a time, I believe someone would be less likely to bite off more than they could chew before they were ready for it.
Once you feel comfortable and want to write something a bit more stable, bring in unit tests if you feel the need. I find tests great for establishing how I want the API to be since the test is API-in-use and quickly shows flaws in ease-of-use. But, if you're just learning you don't need that extra layer on top of all the other things you're trying to learn.
True, but isn't that helpful? There are loads of people who don't know that TDD may be the wrong tool for the "learning a new language" job. Now they know that if they're banging their head against the wall, it may not be them.
I have found that when learning a new language that if I have someone's unit tests it makes it easier. BUT, I have a few languages of exp such as C/C++, COBOL, assembly, Pascal, Forth, Java, Groovy, Python, etc.
In most cases, TDD is not to be used with beginners unless its used as pair programming. In fact if you read back when TDD was established that was one of the use cases for paired-programming..
You're SUPPOSED to write the test ahead of the code which it tests.
As a now-classic example, observe a TDD master struggling with Sudoku: http://xprogramming.com/articles/oksudoku/
You're not doing TDD if you're writing tests afterwords, you're just writing unit tests. I'm not trying to dissuade you from that but just pointing out you're using the wrong term if you're not doing that.
I'm not a TDD proponent for most types of work that aren't heavily interfaced based, webservices to iPhone apps, I TDD them, but the actual app internals? Only on certain parts.
BDD encourages higher-level, whole-system tests alongside low-level unit tests, so the conditions for changing a behavioural spec should (hopefully!) happen less often, but I still don't see why you would avoid changing a test if it was wrong or no longer relevant.