Amir, On 2/17/13 12:52 PM, Amir Kolsky wrote: Great job analyzing this, Ron (seriously).
Thing is, none of it had anything to do with TDD... Look again. Now our question here is how to TDD all this. I would do at least this much thinking with pencil and paper, which takes less time than it took to write this. To TDD the patch of code above, I've got a problem, which is that it calls time(). I can't really TDD well that way, because time is always weird. Just as we do with a random number, we need to abstract time out, so that our test can look like this:
deltaTime = 1.0/30.0 assertEquals(15, distanceMoved(deltaTime))
That's what I was talking about when I said, It sounds like a typical problem of not abstracting the external source of timing. You should be able to calculate into the future without being tied to the system clock. Abstracting external systems, even ones as ubiquitous as the system clock, is essential in TDD. - George -----Original Message----- From: testdrivendevelopment@... [mailto:testdrivendevelopment@...] On Behalf Of Ron Jeffries Sent: Sunday, February 17, 2013 3:40 AM To: testdrivendevelopment@... Subject: Re: [TDD] How do you write tests if you aren't sure what the result should be?
Hi Avi .
On Feb 17, 2013, at 1:03 AM, Avi Kessner <akessner@...> wrote:
My comparison was supposed to be regarding the culmative calculation, not the per tick calculation.
Ill have to look up when velocity is multiplied vs when it's added. I was supposing that dt is some kind of a time value. I imagined that it meant "delta time" or "change in time since last time". Its dimensions must surely be "seconds" or some other time value. I don't know whether you have set
I was supposing that x is some kind of position value. I imagined that its dimensions were "meters" or "pixels", or some other distance value.
The expression was x += dt. Dimensionally, pixels += seconds, or meters += seconds. Can't really be right.
Now what we often do when we animate a penguin -- I mean who doesn't animate a penguin every now and again -- is reason as follows:
I suppose I'll get about 30 frames a second; I suppose I'd like him to move across the screen in about 2 seconds; The way gravity works is you go constant speed in X but up and down in Y; I plan to get 30 frames a second; So I'll need 60 frames to move him The part of the screen he'll move across is about 900 pixels; He has to move 900/60 . uh . 15 pixels every second in the x direction; . and so on
Then, having done the math, when we calculate the penguin's x in our draw() code, called, we guess, every 1/30 second, we can just write:
x += 15
Then the new iPad comes out and our draw() function is called 60 times a second and poor Pengi zips across so fast that it's no fun. So we reason:
OK, well, he's moving 15 per tick. But now on the new iPad I get 60 ticks and he should move about half that. I should generalize this. Hm, well, I want him to go 900 pixels in 2 seconds. That's 450 pixels per second. Um, maybe if I just read out the actual time since last time I can use that. So I'll save time in timeThen and read time now and difference them. the time() function is a float, seconds since long time ago.
And we write
draw() timeNow = time() dt = timeNow - timeThen x += 450*dt timeThen = timeNow end
Now our draw() function is independent of frame rate. But wait! what is that 450*dt??? It seems we just added time to distance and that's supposed to be wrong. It's ok. look at the dimensional analysis of that statement:
pixels += (pixels/second)*second
the seconds cancel and we're adding pixels to pixels if x was in meters, it'd be meters += (meters/second)*second, so that would be OK too.
Now our question here is how to TDD all this. I would do at least this much thinking with pencil and paper, which takes less time than it took to write this. To TDD the patch of code above, I've got a problem, which is that it calls time(). I can't really TDD well that way, because time is always weird. Just as we do with a random number, we need to abstract time out, so that our test can look like this:
deltaTime = 1.0/30.0 assertEquals(15, distanceMoved(deltaTime))
This requires us to write
distanceMoved(float dt) return 450*dt end
which means our draw function needs to be
draw() timeNow = time() dt = timeNow-timeThen x += distanceMoved(dt) timeThen = timeNow end
Now how might we TDD that whole patch. Honestly unless I was demonstrating my great TDD powers, I'm not sure I would, but your mission is to demonstrate great TDD powers. It's darned hard to do in retrospect, when the code is so easy, but we have to learn to think backwards, so let's pretend that we are thinking that the draw has to look like that but that we were being really retentive about TDD, and didn't type it in yet. So we reason, knowing full well what we want:
OK, we have a way to compute distanceMoved as a function of a delta-time. Now we need a way to measure delta time. So, um, let's have a delta-time function that we call in our draw. Its test is, um .
beginTime = 1.5 initDeltaTime(beginTime) endTime = 2 assertEquals(0.5, deltaTime(endTime)) endTime = 3.5 assertEquals(1.5, deltaTime(endTime))
Hmm, how can we write delta time? Well .
lastTime = 0.0 initDeltaTime(float aTime) lastTime = aTime end
float deltaTime(float aTime) dt = aTime-lastTime lastTime = atime return dt end
Now the draw() that we have in our head looks like x += distanceMoved(deltaTime(time()) y += godWhatWillWeDoAboutY(time()) sprite("penguin", x, y)
and both the distanceMoved function and the deltaTime function have been fully TDD'd. Now we do the y function. Because we've read that article that you posted, we realize that we want a velocity that isn't constant 450/second, but is instead a function of gravity. And we know that we want to do that average velocity trick -- after we understand it, which we might not at the beginning.
We proceed similarly. Your mission, if you care to, is to follow my reasoning above, then try to reason similarly as you calculate Y. I don't know yet what I'd do, because I'm stopping here for now. Unless I decide to animate a penguin in Codea .
Hang in there!
Ron Jeffries www.XProgramming.com It's true hard work never killed anybody, but I figure, why take the chance? -- Ronald Reagan
------------------------------------
Yahoo! Groups Links
------------------------------------
Yahoo! Groups Links
-- ---------------------------------------------------------------------- * George Dinwiddie * Software Development Consultant and Coach ----------------------------------------------------------------------
|