Skip to content

Instantly share code, notes, and snippets.

@codification
Last active May 28, 2017 22:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codification/387e73bec19f2f17fa46c1c7b0680684 to your computer and use it in GitHub Desktop.
Save codification/387e73bec19f2f17fa46c1c7b0680684 to your computer and use it in GitHub Desktop.
(Sometimes) Conflicting aspects of TDD
So.
First there was this, from @jbrains:
https://twitter.com/jbrains/status/868129015986618368
> There is more to #tdd than just writing the test first and looking
> for mistakes in the runtime behavior of the system.
Then there was this response from @gdinwiddie:
https://twitter.com/gdinwiddie/status/868279210963587073
> Yeah, but that's a good first step toward learning TDD.
I greatly admire and respect both JB and George and agree with both
points. (As JB pointed out later - "And, not but"). I also do not feel
that writing the first test and looking for mistakes necessarily
stands in opposition to doing and learning other aspects of TDD - I
think it is integral in learning and mastering TDD.
However, I have at times felt, both for myself while programming alone
and also in the context of being a coach or mentor, that the focus on
getting that first test in and the kind of compromises that may need
to be made in order to get a first test to run in some legacy systems
can distract from and consume time for more nuanced discussions of
design and how to go about vetting your code for functionality and
correctness. It has also confused workshop attendees I have enjoyed
mentoring because at one point (showing successful TDD or design) I am
very meticulous about coding and testing while at another time
(getting the first test to work) I may seem to throw caution to
the wind and just pen a lot of ugliness for "later" (refactoring)
in order to make any progress at all. Getting that first test to
run and test something that seems meaningful to developers at a
customer site can be a very technical, hairy and infuriating
process that in no way resembles what I envision as what TDD "is"
or feels like. At the same time I think exercises like this are
very important. Firstly, because to see all the ugliness and hard
work that is required just to get one test in may point out the
hard truth that it is unnecessarily complicated. Secondly, going
through all those hairy runtime dependencies often results in
surprises regarding how the system is configured, bootstrapped,
runs etc.
So, in this case this one "aspect" of TDD - getting a test in and
running - conflicts with the learning and appreciating the goal or end
state of working in a TDD-like fashion. Getting the test in and
running is fraught with frustration and can be very time consuming
with little benefit and is in no way reminiscent of the positive
feeling of ease, security, confidence, swiftness and even fun that
working in a positive flow with TDD can be. I think I have lost more
than one participant in workshops on legacy code or TDD this way by
not knowing how to balance between getting hands dirty and showing the
desired end state. Especially - connecting the two and showing a path
from one to the other.
I feel that there should be some interesting and good thing to learn
from this. There is perhaps something to this very dynamic that could
even make it a far better learning opportunity - something that I have
overlooked or misinterpreted. A similar type of dynamic - I think -
can be found in balancing the two aspects of refactoring (refining)
and writing more tests (incremental progress) - but there I can often
feel a lot more confident balancing. Perhaps because those two are so
central and repeated so much they become routine. That first test is
almost never routine work.
@codification
Copy link
Author

Oh, and this was my tweet that caused me to write this: https://twitter.com/villesv/status/868425054530482177

@jbrains
Copy link

jbrains commented May 28, 2017

Curious. I don't know anything about the context in which you had this experience, so I can only guess at what might have happened. I experience something similar from time to time, and it usually means that I've made too many designs up front about my design or that I'm in the processing of trying to think 10 steps ahead instead of simply getting something running and working. In this kind of situation, I feel like I would benefit from either just writing some code or writing a "worse" (bigger, usually) test. I interpret this feeling as trying to do TDD in my head instead of in my editor.

Nothing I do in this situation "is wrong". It just "is". I can take bigger steps and wait for that to cause pain, then hope that it causes mild pain that I can easily recover from. I can take smaller steps and feel like I'm writing tests for their own sake, confident that this helps me avoid pain, since I "know" that 1000 steady steps probably takes me farther more quickly than 20 big steps forward and 5 bigger steps back. Not everyone will like my choices. I have been in workshops where people have complained about my small steps and wanted me to get the point. I have been in workshops where people have complained about my big steps and accused me of not actually doing TDD, but just jumping to a solution. People are different.

We can perhaps go back to test-first programming and the Ratchet Effect: when I have a test running, it helps me avoid falling too far down when I make a mistake. That might make people feel better. On the other hand, I've always felt uncomfortable with the idea that it's hard to demonstrate avoiding pain, because we've avoiding the pain. How do we show that we've avoided more pain than we've caused? I don't know. I can only tell people what I think has happened and invite them to try it and decide for themselves. "One day, you'll realize that you've gone 118 days without a crisis. Or not. I don't know. This isn't science."

With legacy systems in particular, progress is unpredictable. That's why we call it "legacy". Release the outcome. We can never know whether we're investing wisely in rescuing legacy code, except by looking back and measuring what happened. This makes it "legacy" and that's why we should try not to write more legacy code for ourselves.

When I feel frustrated getting the first test running, I interpret it as a sign that I don't know what I'm supposed to do. Fred Brooks said that deciding what we should be building is the most difficult part of what we do, so I find it quite reasonable to except the most frustration while figuring out the first few tests in any new part of the system. This is why we are paid well. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment