TDD is a very useful tool.
Done well, it offers assurance that your code does what it is
supposed to do, provides a set of baked in regression tests, allows
you to refactor code without worrying that you will break something
in the process and acts as a sort of living design document.
It is not, however, a
silver bullet. If done poorly, it can cause code to become rigid.
This generally happens when people test the implementation details
rather than the behavior. In a language like Python, where there are
no truly private methods, it can be even easier to test
implementation rather than behavior if you aren't cautious. I'll also
say that it can be really difficult to effectively test Android code
because TDD isn't a first class citizen in that ecosystem.
In my opinion, the
possible downsides of TDD are generally far outweighed by the bonuses
– especially since the downsides are usually able to be mitigated
by exercising some self-discipline.
That's not to say that
every piece of code you ever write has to be done with TDD. There are
some small, usually one-liner style programs, that I write which I
don't test drive. If I'm going to be using something once and
tossing it, provided that there isn't really a danger of permanent
damage if the code doesn't do what I want the first time, I may
decide that it isn't worth the effort to set up a testing harness.
Now that we've got my
opinions on the topic out of the way, I have to say that I don't get
the hate that some developers have for TDD. I can understand a
non-technical manager not understanding how writing tests (more code)
isn't a drawback, but people who write software for a living are
another story.
If I had to guess, I'd say
it was probably some combination of fear of the unknown, a previous
bad experience (whether because of lackluster tools, lack of
guidance, or inexperience), or posturing on the part of the developer
(after all, we are often not known for a lack of ego).
There are occasionally
reasons to not test something (few and far between), but as a general
rule, having the tests will only help you now as well as helping
future you when you have to dig back into the code in 6 months. Not
wanting all of the tools that could help you is just crazy.
This whole post was
inspired by a tweet that a friend of mine
re-tweeted (and its associated tweets), so let's take a little time to critique the conversation.
Shocked by the number of jobs proposed to me whose ads list "TDD" as a requirement. Are we really still doing this?
— Bodil Stokke (@bodil) August 30, 2015
Yes. Because it works. I've already
covered that above, so I'm not going to repeat myself.
TDD works really well for a lot of people, and that's great. Others have different ways of thinking about programming. Don't exclude them!
— Bodil Stokke (@bodil) August 30, 2015
If you are working in a shop that
doesn't do test driving (I'd be tempted to ask why not, but just for
the sake of argument), then yes, a person who doesn't do TDD will be
fine. If you are in a shop that does TDD and the person is willing
and able to learn TDD, then consider helping them get up to speed. If
they refuse, then they're probably not a good fit for your
team/company. Sorry, but that's the way it is.
If your team all does TDD, but one
person refuses to do so, you lose a lot of the benefits. The baked in
set of regression tests is no longer complete. The living
documentation is no longer complete. Refactoring becomes trickier.
Bugs can become harder to track down. These are problems.
@makmanalp @jasonpbecker Yes, I think this is a matter of individual neurology. My architectures definitely get _less_ simple with TDD.
— Bodil Stokke (@bodil) August 30, 2015
Then you're probably doing TDD wrong.
In all likelihood, you are testing implementation instead of behavior.
This is actually a pretty common mistake for people who aren't used
to TDD and it takes some experience to get over. Heck, even people
who have been doing it for a while can slip up sometimes. None of us
are perfect. That doesn't change the fact that you're probably using
the tool wrong.
@makmanalp @jasonpbecker If I'm TDDing with unit tests, it helps me a lot. If I'm TDDing with integration tests, I lose the big picture.
— Bodil Stokke (@bodil) August 30, 2015
You don't TDD with Integration Tests,
or at least not only with integration tests. You use Unit Tests to
test functions (given input, check output for example). Integration
Tests are used to test a series of Units (kind of like checking to
see that a bunch of legos you put together actually build a wall).
@jasonpbecker TDD literally gets in the way of my thinking properly about my code in some cases.
— Bodil Stokke (@bodil) August 30, 2015
Then you're looking at it wrong. Each
unit test should be a condition that your function should fulfil. You
only test the criteria that your code is supposed to fulfill. That's
not to say that you can't spike out something you're not sure of
(especially if you're working with a new language), but before that
code actually makes it into your codebase, it needs to be under test,
and that test needs to fail first.
@jasonpbecker In my case, striving to always do TDD would have a negative impact on the quality of my code.
— Bodil Stokke (@bodil) August 30, 2015
I can sort of get behind this for one
very simple reason – some things are just ridiculously difficult
(if not damned near impossible) to test. These cases don't come up
often, but they do occasionally come up. Other than that, test your
code. For everyone's sake.
@MaggieL "You must know what TDD is" is still a bad requirement. And no, "we do TDD here and so will you" is something I get a lot.
— Bodil Stokke (@bodil) August 30, 2015
I disagree. If the entire team (or
company) does TDD, then yes,
it is a valid requirement for the job. If you refuse to use TDD, then
you don't have a place on the team for reasons that I've already
outlined. In fact, I'm glad more places are making it a requirement
(provided that their people write good tests).
The
sad thing is that I hear these sorts of arguments a lot. Thankfully,
however, I seem to be hearing them less lately. I honestly welcome
constructive criticism of practices because it helps people grow. You
need to be prepared to have others respond to that criticism though.
Just
complaining about a methodology you don't like without valid reasons
doesn't help anyone (and that's exactly what that last tweet was).
Current
mood: Calm
Current
music: INXS – The Stairs
No comments:
Post a Comment