Tuesday, August 29, 2023

TDDbE: Make It

 We can't mark our test for $5 + $5 done until we've removed all of the duplication.

Huh.  Because I have really felt like we've marked earlier tests as done before the duplication is removed.

We don't have code duplication, but we do have data duplication....

My experience is that people often miss this duplication - not necessarily in the long term, but certainly in the short term.  Data duplication gives you "permission" to do a lot of the refactoring early (after first test), rather than deferring it until later.

In this case, why 10? because there are two 5s -- great, so "let's make the code say that".

Instead... ugh, Beck's example really seems to be going off of the rails here.  Sums with augends and addends?  who ordered that?

In passing, I do think it is important to notice that the details of the implementation are bleeding into the tests.  These are programmer tests - they are there to measure the interactions of the internal elements in our module.  We aren't restricted to only testing via the "published" API.

Wrote a test to force the creation of an object we expected to need later.

This has been a peeve for a long time - a lot of the mythology of test driven development, especially early on, centered the fact that the design arrives organically from the needs of the tests.  At the same time, practitioners were constantly guessing at designs ("I'm going to need a class that does/represents mumble") and then creating a bunch of scaffolding around their guess, rather than attacking the problem that they actually have in front of them right now.

I don't think there's anything wrong, necessarily, with having a mental model of how the code should read in the end, and creating a sequence of tests to get there.  I do think, though, that if that's what we are doing we really ought to be upfront about it.

 

Monday, August 28, 2023

TDDbE: Addition, Finally

Beck introduces the idea of rewriting the TODO list as both a warmup exercise, and as permission to clean up the little items first rather than copying them to the new list.

I'm not sure how to write the story of the whole addition, so we'll start with a simpler example

Again, the lesson of shifting to smaller steps as a counter measure to uncertainty; accompanied by my usual interjection that baby-footin' is optional, not mandatory.  Have the skill to work at multiple cadences and shift between them, then use the cadence that is appropriate at the time.

I hope you will see through this how TDD gives you control over the size of the steps.

Vindication!

TDD can't guarantee that we will have flashes of insight at the right moment.  However, confidence-giving tests and carefully factored code give us preparation for insight, and preparation for applying that insight when it comes.

That said, I think that testSimpleAddition really goes sideways.  I think there are two flaws here: first, that the metaphors aren't very good.  Second, the experimenting with the metaphor is something that should emerge during refactoring, not during the red task.

What we should be doing is taking the metaphor we understand (adding dollars to dollars), and making that work, then refactoring the underlying implementation to find the working metaphor (encoding into the design our improved understanding of the proper way to think), then lifting the new metaphor into the published API and finally (assuming it makes sense) sunsetting the dollars to dollars metaphor.

In other words:

for each desired change, make the change easy (warning: this may be hard), then make the easy change -- Kent Beck, 2012

This is not a fair fight: I'm writing 10+ years after Beck shared this approach, whereas the work I'm criticizing was written ten years before.  If he waited to write the book until he understood everything thoroughly, the book would not exist for me to critique.

Part of the point of this review exercise is to rediscover where we were, in the expectation that we will find past practices that should be improved.


Thursday, August 24, 2023

TDDbE: The Root of All Evil

A quick lesson on how to get rid of a pair of classes that shouldn't have been introduced in the first place.

One thing stands out here: he doesn't do a lot of work to verify that the tests he wants to get rid of are redundant.  Think, zap, done.  And here, that's the right thing (toy problem, not too much to keep in your head, and of course it happens the tests are actually unnecessary).

Of course, if we are deleting tests that are passing, there's no problem in the sense that the production code is still right.  The potential difficulty would be if we continue to assume that some part of the code is covered by tests when in fact it is not, and then start working on that code expecting to be afforded the same protections we had when the test was in place, and start making mistakes.

Sunday, August 20, 2023

TDDbE: Interesting Times

 Whoa! Code without a test?  Can you do that?

This is a strange little digression, on two points.  

First, the error messages for the equality tests are something that should have been observed when the equality tests were created during RED.  That would have been the obvious time to notice the messages and make improvements to them.  Perhaps addressing the issue then would have made the earlier chapter more confusing.

Second, the change to the output message doesn't actually clarify the problem - Kent calls attention to this in the text, of course, but I'm amused that the extra work thrown in at this point made the failure harder to recognize, rather than easier.

Kent decides to back out the change and start over: here, he calls it the conservative approach.  Fifteen years later, he'll introduce test && commit || revert -- a way of committing to the conservative approach.

With the tests you can decide whether an experiment would answer the question faster.  Sometimes you should just ask the computer.

 I like the experiment language quite a bit.

 I'm beginning to feel that the main lesson up to this point is something along the lines of: be flexible until you know what you are doing.

Friday, August 18, 2023

TDDbE: Times We're Livin' In

The answer in my practice is that I will entertain a brief interruption, but only a brief one, and I will never interrupt an interruption.

 That's a useful constraint right there.

This is the kind of tuning you will  be doing constantly with TDD.  Are the teeny-tiny steps feeling restrictive?  Take bigger steps.  Are you feeling a little unsure?  Take smaller steps.  TDD is a steering process -- a little this way, a little that way, There is no right step size, now and forever.

Yet another definition of TDD.  Heh.

As usual, I'm not particularly fond of the currency test; again, it lacks connection to the business needs.  Expressed another way, there's no assurance that the test, as written, is a good example for future clients because we aren't actually looking at the needs of the client.  We're just sort of assuming that we're going to end up with micro-methods eventually anyway, so we might as well proceed to them without passing go.


Sunday, August 13, 2023

TDDbE: Makin' Objects

The two subclasses of Money aren't doing enough work to justify their existence, so we would like to eliminate them.

Minor complaint: that's a pretty clear conclusion to reach as soon as you start thinking about them.  Again, my charitable interpretation is that we are witnessing a demonstration of how to climb out of a hole that you probably shouldn't have dug in the first place.

And that's perhaps concerning, in so far as we could have had a lot more coupling to the "wrong" interface if we hadn't discovered the improvement as early as we did.

The first step is interesting - replacing the direct invocation of the object constructors with factory methods (aka "named constructors").  That's a good idea often enough that I wouldn't have minded terribly if the "perfect interface" we imagined in chapter one had used them.

Kevlin Henney once observed that if your program is really object oriented, then the only place you would see the name of a concrete class is at the point that the constructor is invoked - everything else would be interfaces or (rarely) abstract classes.

 


Friday, August 11, 2023

TDDbE: Apples and Oranges

We would like to use a criterion that makes sense in the domain of finance, not in the domain of Java's objects. But we don't currently have anything like a currency, and this doesn't seem to be sufficient reason to introduce one.

Working outside in, we'd probably have one.  After all, the multi-currency report shown in Chapter 1 includes ISO 4217 currency codes.  

Many kinds of values will want to have both an amount and unit, and currency code is the logical expression of unit in this domain.

The thought occurs to me: are we floundering about because we don't actually know what we are doing (or are pretending that we don't know what we are doing?)