Keyboard Shortcuts
ctrl + shift + ? :
Show all keyboard shortcuts
ctrl + g :
Navigate to a group
ctrl + shift + f :
Find
ctrl + / :
Quick actions
esc to dismiss
Likes
Search
[TDD] How do you write tests if you aren't sure what the result should be?
Amir Kolsky
OK, that makes it even simpler.
toggle quoted message
Show quoted text
This is where TDD can tell you whether you've reached your final destination or not. You can calculate the exact point where the penguin should stop "in the real world", and then specify what the allowed error is. At this point you need to refine your algorithm, taking into account things like the current framework, current location, elapsed time, etc. until the test passes. A. -----Original Message-----
From: testdrivendevelopment@... [mailto:testdrivendevelopment@...] On Behalf Of Avi Kessner Sent: Sunday, February 17, 2013 1:03 AM To: testdrivendevelopment@... Subject: RE: [TDD] How do you write tests if you aren't sure what the result should be? 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. On Feb 17, 2013 3:46 AM, "Amir Kolsky" <kolsky@...> wrote: **(perhaps calculationshigher30FPS) and make that a specification for your game. (With 10 FPS it the10asis described here:is can abilityfixed time step but rather the " (perhapsatto render at different framerates. These two things seem completelyodds, and they are - unless we can find a way to decouple the calculationshigher30FPS) and make that a specification for your game. (With 10 FPS it 10asis described here:is can ------------------------------------ Yahoo! Groups Links |
Amir Kolsky
Great job analyzing this, Ron (seriously).
toggle quoted message
Show quoted text
Thing is, none of it had anything to do with TDD... -----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, 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 |
Amir,
On 2/17/13 12:52 PM, Amir Kolsky wrote: Great job analyzing this, Ron (seriously).Look again. That's what I was talking about when I said,Now our question here is how to TDD all this. I would do at least this much It sounds like a typical problem of not abstracting the external sourceAbstracting external systems, even ones as ubiquitous as the system clock, is essential in TDD. - George -- ---------------------------------------------------------------------- * George Dinwiddie * Software Development Consultant and Coach ---------------------------------------------------------------------- |
Amir Kolsky
Sorry for not being clear.
I meant that the derivation of the formulae that you THEN implemented in TDD did not have anything to do with TDD. From: testdrivendevelopment@... [mailto:testdrivendevelopment@...] On Behalf Of Ron Jeffries Sent: Sunday, February 17, 2013 2:41 PM To: testdrivendevelopment@... Subject: Re: [TDD] How do you write tests if you aren't sure what the result should be? Hi Amir, On Feb 17, 2013, at 11:52 AM, "Amir Kolsky" kolsky@... <mailto:kolsky%40actcom.net.il> > wrote: Thing is, none of it had anything to do with TDD...Let me suggest that you read again, and think again ... Ron Jeffries www.XProgramming.com You never know what is enough unless you know what is more than enough. -- William Blake |
So to sumerize,
1. Research the problem to work around unknowable areas. 1a. Become convinced that its possible to know the unknowable in an abstract way. 2. Abstract the things which cause the problem to be unknowable and create mocks for them. 3. Massage the known solution to be broken up into testable units. 4. Profit. Is that correct? On Feb 18, 2013 7:01 AM, "Amir Kolsky" <kolsky@...> wrote: ** [Non-text portions of this message have been removed] |
Hi Amir,
On Feb 17, 2013, at 11:00 PM, "Amir Kolsky" <kolsky@...> wrote: I meant that the derivation of the formulae that you THEN implemented in TDD Of course it didn't have to do with TDD. It has to do with the laws of physics. It has to do with understanding the problem and is possible solutions. It has to do with understanding what happens if frame rate changes. If we don't understand those things, our penguin will never fly right, because there are an infinity of possible calculations for his x position and y position. These are matters for thought. When we do TDD we don't stop thinking. We stop believing everything we think, and we stop imagining that when we write code, it works as we imagine. Ron Jeffries www.XProgramming.com If another does not intend offense, it is wrong for me to seek it; if another does indeed intend offense, it is foolish for me to permit it. -- Kelly Easterley |
This email needs to be posted as an article online so we can easily
toggle quoted message
Show quoted text
reference it when we talk to our clients, coworkers, and friends. On Mon, Feb 18, 2013 at 5:47 AM, Ron Jeffries <ronjeffries@...> wrote:
Hi Amir, --
Tim Ottinger, Sr. Consultant, Industrial Logic ------------------------------------- |
Ron Jeffries wrote on 17.2.2013 13:39:
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.If we happen to have some domain knowledge of game development and common patterns in game design, we might decide to decouple the physics time step from the frame rate [1] and use a fixed time step for the physics, to keep the physics calculations deterministic. For example the game Supreme Commander (2007) does its physics calculations at 10 fps, as said in [2]: "Take a look at the video if you havent already. What frame rate do you think the game is running at? The correct answer is 10 frames per second. Wait, what? It looks far smoother than 10 fps you say! It is and it isnt. The game is actually running at two separate frame rates." To make the visuals update at a smoother pace, the game state is interpolated to match the frame rate. There are various techniques for interpolating/dead reckoning [3][4], but that's a whole nother story. [1] [2] [3] [4] -- Esko Luontola www.orfjackal.net |
Amir Kolsky
One more question regarding the actual calculation.
toggle quoted message
Show quoted text
The question that comes to mind is "what is the trigger that causes the penguin to be rendered on the screen?" Is there some internal timer? External timer? In either case, if we separate the drawing trigger from the actual drawing, then the calculation becomes. Dt = prevTime - now() And X = prevX + incrementX(dt) (based on whichever factors you want to take into account when moving, deceleration, friction, etc.). The frame rate does not play into this calculation at all. What am I missing? -----Original Message-----
From: testdrivendevelopment@... [mailto:testdrivendevelopment@...] On Behalf Of Esko Luontola Sent: Monday, February 18, 2013 12:10 PM To: testdrivendevelopment@... Subject: Re: [TDD] How do you write tests if you aren't sure what the result should be? Ron Jeffries wrote on 17.2.2013 13:39: OK, well, he's moving 15 per tick. But now on the new iPad I get 60 ticksand he should move about half that. I should generalize this.second. Um, maybe if I just read out the actual time since last time I can usethat. So I'll save time in timeThen and read time now and difference them.If we happen to have some domain knowledge of game development and common patterns in game design, we might decide to decouple the physics time step from the frame rate [1] and use a fixed time step for the physics, to keep the physics calculations deterministic. For example the game Supreme Commander (2007) does its physics calculations at 10 fps, as said in [2]: "Take a look at the video if you haven't already. What frame rate do you think the game is running at? The correct answer is 10 frames per second. Wait, what? It looks far smoother than 10 fps you say! It is and it isn't. The game is actually running at two separate frame rates." To make the visuals update at a smoother pace, the game state is interpolated to match the frame rate. There are various techniques for interpolating/dead reckoning [3][4], but that's a whole nother story. [1] [2] of-desyncs/ [3] _.php [4] ogramming/targeting-a-variation-of-dead-reckoning-r1370 -- Esko Luontola www.orfjackal.net ------------------------------------ Yahoo! Groups Links |
Once we have separated the rendering from the time keeper, you are correct.
However, previously we(I?) was using "frame rate" as a simple term to refer to how often the function gets called. (Before it was recognized that rendering and timers can be separated) brought to you by the letters A, V, and I and the number 47 On Mon, Feb 18, 2013 at 10:26 PM, Amir Kolsky <kolsky@...> wrote: ** [Non-text portions of this message have been removed] |
Amir Kolsky
Oh, I completely missed that... Frame rate has a specific meaning vis-¨¤-vis
toggle quoted message
Show quoted text
the number of screen refreshes. -----Original Message-----
From: testdrivendevelopment@... [mailto:testdrivendevelopment@...] On Behalf Of Avi Kessner Sent: Monday, February 18, 2013 12:53 PM To: testdrivendevelopment@... Subject: Re: [TDD] How do you write tests if you aren't sure what the result should be? Once we have separated the rendering from the time keeper, you are correct. However, previously we(I?) was using "frame rate" as a simple term to refer to how often the function gets called. (Before it was recognized that rendering and timers can be separated) brought to you by the letters A, V, and I and the number 47 On Mon, Feb 18, 2013 at 10:26 PM, Amir Kolsky <kolsky@...> wrote: **10 fps, as said in [2]: second. Wait, what? It looks far smoother than 10 fps you say! It is and it isn't. [Non-text portions of this message have been removed] ------------------------------------ Yahoo! Groups Links |
For a pragmatic answer: Write the code. Run it. Observe the result. Validate that the result is "reasonable." [...whatever the heck THAT means!!!] Put the result in your test as an assertion.
toggle quoted message
Show quoted text
Then you'll at least know when something changes. --- Avi Kessner <akessner@...> wrote: ... The math is too complicated for me to resolve easily. ... |
JeffGrigg wrote:
For a pragmatic answer: Write the code. Run it. Observe the result.I think thats not such a bad approach. We use it quite a lot: 1. write dirty code of what you "want to do" (aka "spike") 2. observe the result 3. write automatic tests on anything that you verified manually 4. refactor/test-drive "mercilessly" and write new tests as you go |
On Sun, Mar 24, 2013 at 11:40 AM, Michal Svoboda <pht@...> wrote:
**first introduced to it in Michael Feathers Work. but I'm not sure if it has a special section is his "Working with Legacy system": book or was it in a later video session i saw. A very useful technique in general, and should be an excellent idea in this case. Lior _ |
to navigate to use esc to dismiss