Search the web
Sign In
New User? Sign Up
testdrivendevelopment · Test-driven Development
? Already a member? Sign in to Yahoo!

Yahoo! Groups Tips

Did you know...
Want your group to be featured on the Yahoo! Groups website? Add a group photo to Flickr.

Best of Y! Groups

   Check them out and nominate your group.
Having problems with message search? Fill out this form to ensure your group is one of the first to be migrated to the new message search system.

Messages

  Messages Help
Advanced
fixing a megafunction   Message List  
Reply | Forward Message #29507 of 32000 |
The way of pre and post and invariant to fixing megafunctions.

The short Fast and Filthy answer is...

Use valgrind see http://valgrind.org

On Wed, 3 Dec 2008, Alan Baljeu wrote:


> Problem: there is a bug, namely memory corruption. Demonstrating
> the bug requires elaborate setup and catching the access violation
> that shows up. Except for this situation, the function works quite
> well, although it has no unit tests.

The realist in me says... There is a bug... that he knows about. And
maybe a couple he doesn't!

Part of the problem of MegaFunctions is don't really know exactly what
they should be doing. If you could write down in few understandable
lines.. odds on the function would not many more lines than
that. ie. The very notion "this function does not behave according to
spec" is fuzzy because the spec is fuzzy.

> Writing good tests may be
> complicated because the datastructure it takes and produces is
> large, and there are many cases to cover.

Break up your notion of "test" into the following varieties...

Precondition asserts - If you know, by some line in the megafunction,
that certain assumptions must hold, "executably document"
them. ie. Write an assert that expresses and tests that
assumption. Explicitly label that assert as a precondition
assert. (Yes, yes, I know that precondition asserts are usually on the
parameters of a function, give me time and you will see where I'm
heading.)

Invariant checks - You are clearly maintaining some fairly complex
data structure(s?). Create a function that that checks that data
structure. Inevitable such a data structure is not just a "Bag of
Bits". The bits in a data structure (if it is in a Valid State) can never
have just any old value. There are range constraints, and parts that
are constrained to vary in some set relation with other
parts. "Executably document" those constraints in function that checks
all those constraints and throws a wobbly if any are violated.

Invoke that invariant check _at every point_ in the where you believe
the data structure to be in "a Valid State".

> Fixing the bug requires dramatic changes to the function. Careless
> changes will break the function. Careful changes might not break
> anything but it's hard to tell because there are no tests.
> Interactively I could try stuff and see what happens. I'll have a
> good indication if things are okay or not, but this is the time
> consuming way.

I keep telling people around me there is nothing new about unit tests,
nothing strange. Programmers have _always_ turned on logging and, as
you say, "tried stuff and see what happens", and have always had a
"Good indication if things are not".

All I'm asking is that "Oracle", that knowledge you have when you look
at the log trace and say "Ah yes, that looks right", to be captured
executably as an assert.

So at those logging points you have now, add a "postcondition assert"
that checks that the effect of the above lines were as you expected.

Even if it is really dumb and one off like, "If we're running test
dataset 5, the result should be 3".

Yes, yes, I know "Postcondition asserts" are usually done at the end
of a routine. But humour me and label them "postcondition" and scatter
them liberally inside this mega routine.

Yes, yes, I know "If we are running test dataset 5, the result should
be 3" is really lame coding, you wouldn't want to see in production
code, but bear with me.

An excellent place to look is at comments, wherever possible try and
replace comments by "executable comments".

So there you are, without changing a single line of existing code,
only adding side effect free code, you have strongly braced it with
unit tests.

And if you have added a couple of post checks like "we should have
freed this memory by now", you may have found and fixed the bug by
this stage.

In which case you're finished, check in and close the issue.

> How would you proceed?

By now you probably have a fairly good idea of the data structures
involved. See if you can copy and paste largish chunks of the code
into an entirely new class(es?) that encapsulates the data
structure(s?).

Hopefully you already have chunks of the invariant for
that class written, you should be able to invoke that invariant check
at the start and end of _every_ public method for that class.

Some of the precondition asserts you have written probably can be
slipped into the front of the various methods on that class.

Some of the postcondition asserts you have written probably can be
slipped into the Unit Test of the various methods on that class.

(See, that lame "If we running test dataset 5" code doesn't look so
lame now! Now, we only put "result must equal 3" in the unit test case
where we're using dataset 5!)

Once the unit tests on that class is running and you're reasonably
happy, replacing chunks of the megafunction by references to that
class and methods on that class.

Replace the least bit that can be expected to compile and run
correctly, even if you have to do some silly copy stuff into the
class, and copy stuff out again.

Compile and run and get working again. It should be utterly unchanged.

Gradually eat away more and more of the code until everything that
changes or accesses the data structure encapsulated by the class you
extracted is done via the methods on the class.

Repeat as often as needed.

By now the megafunction is starting to look quite a bit smaller. The
invariants are now mostly in terms of invariants of the worker
classes.

Probably now you can crumble the whole mega function into a couple of
smaller functions.

Warning! There is probably an irreducible core to the function, don't
endlessly slave to reduce it. Accept that some stuff is just complex
and brace it well with pre and posts and invariants.


John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@...
New Zealand




Tue Dec 9, 2008 10:55 pm

refactored
Offline Offline
Send Email Send Email

Forward
Message #29507 of 32000 |
Expand Messages Author Sort by Date

I have this legacy megafunction, written in C. (I'm embarrassed to admit I wrote it many years ago.) The operation of this function is to read a file, and...
Alan Baljeu
alanbaljeu
Offline Send Email
Dec 3, 2008
7:51 pm

Hi, Alan, ... 1) find a way to serialize your data structure, if not already extant; 2) write some example (non-unit) tests that give you fair coverage; 3)...
Carl Manaster
cmanaster
Offline Send Email
Dec 3, 2008
8:18 pm

I would try to start with two tests - one "happy path" test, and a test that sets up the conditions to provoke the bug. One test should pass, and the other...
Keith Ray
attkeithray
Offline Send Email
Dec 3, 2008
11:42 pm

As much as I believe what I said, what Keith says here is also correct and may be the more pragmatic view. Look at M.Feathers' book and you'll see that there...
Tim Ottinger
linux_tim
Offline Send Email
Dec 4, 2008
8:18 pm

... You can't work with a megafunction reliably. That is the nature of megafunctions. They're subsystems or maybe systems unto themselves. Get a good partner,...
Tim Ottinger
linux_tim
Offline Send Email
Dec 4, 2008
2:48 pm

... I recently did much the same thing to a similar sounding piece of code that *I* originally wrote. What I did was first go through and extract out any piece...
Brad Stiles
bradley.stiles@...
Send Email
Dec 4, 2008
4:18 pm

Thanks Tim and everyone for your suggestions. Unfortunately right now I'm overwhelmed by this feeling that writing tests will take "forever" when I could just...
Alan Baljeu
alanbaljeu
Offline Send Email
Dec 4, 2008
9:12 pm

... That's okay. THe quote is "Don't despair, but if you do despair work on in despair." Try to split out the minimal bits and test them. It may be that the ...
Tim Ottinger
linux_tim
Offline Send Email
Dec 4, 2008
9:13 pm

Hi, Alan, ... and ... Obviously, I can't know the right answer for your specific issue, and I don't mean to contradict you. I'm just trying to offer what I...
Carl Manaster
cmanaster
Offline Send Email
Dec 4, 2008
9:28 pm

Oh, please say you'll resist the dark side and at least do the 2 tests (happy path + bug reproducer). Inspire me! :) Al...
Al Chou
HotFusionMan
Offline Send Email
Dec 4, 2008
9:30 pm

I currently believe 1) Fixing the bug requires dramatic changes to the function. 2) Careful changes might not break anything but it's hard to tell because...
Alan Baljeu
alanbaljeu
Offline Send Email
Dec 4, 2008
9:37 pm

Hi, Alan, ... For my part, I can't get anything "dramatic" done in an hour or two. And I'd worry a lot about ... A "dramatic" change that I "just snipped,...
Carl Manaster
cmanaster
Offline Send Email
Dec 4, 2008
9:43 pm

I've been in the situation where writing a test seemed to take way too long. And I've also been in the situation where snip/tuck/rearrange etc. SEEMS like it...
Keith Ray
attkeithray
Offline Send Email
Dec 5, 2008
12:34 am

Alan; First I recommend Michael Feathers "Working Effectively with Legacy Code". It is the bible when it comes to fixing bugs in large functions. I can...
Olof Bjarnason
olof.bjarnason@...
Send Email
Dec 5, 2008
7:27 am

Alan, FWIW, I want to chime in with the idea of writing several characterization tests, preferably based on several real-world input data sets which both do ...
Walter Prins
bytejuggler
Offline Send Email
Dec 5, 2008
12:37 pm

Alrighty then. I have seen Michael's book recommended soo many times now, I given in. I'll order it. As for the function in question, I caved. I did a bit...
Alan Baljeu
alanbaljeu
Offline Send Email
Dec 9, 2008
8:48 pm

The short Fast and Filthy answer is... Use valgrind see http://valgrind.org ... The realist in me says... There is a bug... that he knows about. And maybe a...
John Carter
refactored
Offline Send Email
Dec 9, 2008
10:55 pm

Thank you very much for your post. The Valgrind part is useless to me as I'm not using Linux nor GCC, but I like the suggestion of throwing asserts into the...
Alan Baljeu
alanbaljeu
Offline Send Email
Dec 10, 2008
4:17 am

Alan, I had a case somewhat similar I think. It was about 400 lines of code tied to an event. When the event fired, an object representing a page of html was...
Donaldson, John (GEO)
geo_johnfr
Offline Send Email
Dec 10, 2008
8:17 am

I've been doing some megafunction refactoring, the process feels like carving marble and now my thumbs hurt :) One interesting result is that cleaning up the...
Steve Freeman
smg_freeman
Offline Send Email
Dec 13, 2008
8:26 pm

First up, I changed my precompiled header to include "cpptest\unittestdef.h". Now I can put my asserts anywhere :-) I think though I want a switch to turn...
Alan Baljeu
alanbaljeu
Offline Send Email
Dec 15, 2008
3:09 pm

Alan, Sounds weird to me. Perhaps it would read more easily if you said: 1. Replace the crashing line(s) with the simplest change that doesn't crash. 2. Run...
Donaldson, John (GEO)
geo_johnfr
Offline Send Email
Dec 15, 2008
4:34 pm
Advanced

Copyright © 2009 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Guidelines - Help