C. Keith Ray

C. Keith Ray writes about and develops software in multiple platforms and languages, including iOS® and Macintosh®.
Keith's Résumé (pdf)

Tuesday, August 26, 2014

I and Me

If you're wondering whether to say "Bob and I" or "Bob and me," here's the trick: Take "Bob and" out of the sentence, correct the number implied by other words, if necessary, and judge whether the sentence sounds right.

Example 1: "Bob and I just want the best for you."

Drop Bob: "I just want the best for you."

The rewritten sentence sounds right, so "Bob and I" is correct in this example. The sentence should be, "Bob and I just want the best for you."

Example 2: "That award belongs to Bob and I."

Drop Bob: "That award belongs to I."

That doesn't sound right. So this example should be "That award belongs to Bob and me."

And you can test that again by changing "I" to "me" and leaving out Bob. "That award belongs to me." (But don't say that to Bob!)

Example 3: "We want to create the same experience you would have if you had called both Bob and I into your office for a meeting."

Drop Bob: "I want to create the same experience you would have if you had called I into your office  for a meeting."

That doesn't sound right. Let's try "me."  "I want to create the same experience you would have if you called me to your office  for a meeting." Better.

So, the better sentence is: "We want to create the same experience you would have if you had called both Bob and me into your office for a meeting."

That's it. Those of us who speak English as a native tongue, already know the unspoken rules of grammar; we just get confused when we try to follow the artificial rules we were taught in schools or by well-meaning friends.

Wednesday, August 13, 2014

Two Weird 'Tricks' For Testing Graphical Code

Before I do a bunch of "Extract Method" refactorings, I looked over the code and wrote this comment:

    // creates pdf context.
    // computes rowCount and columnCount from paper_size
    //    and major_grid_distance.
    // computes margin sizes (and thus origin.)
    // draws graph paper into context.
    // close context.
    -(void) drawMajorMinorGridAt: (CGPoint) origin
                     andRowCount: (int32_t) numberOfRows
                  andColumnCount: (int32_t) numberOfColumns

                       inContext: (CGContextRef) context;

What the extract methods will do, is let me draw while not in a pdf context. Code-reuse: yay!

Another way to achieve the same goal: copy & paste. While copy & paste may be quicker,  it bulks up the code and potentially doubles the number of defects that may "bug" us in the future. Technical debt.

One could argue that planning ahead would have created a better design. But... I didn't need to draw while not in a pdf context, a half-year ago.

One reason this code is so bad, is that I didn't exactly test-drive it. I ran some calculations, wrote the code, and looked at the output. In some early iterations, it produced grids with lines poking too far through other lines: I had to reduce the length of some lines, by the thickness of other lines. Similar glitches provoked a few other changes. And then it was done. I haven't touched the code in quite a while. 

Could I write some automated tests for this code? Yes. 

I could save some manually-verified pdf output as "Golden Data" and do file comparison in tests that are supposed to produce the same output. I have done something like this before. The only time the test failed in my project (without my changing code to cause the failure) was when a graphics library that my code depended on changed. 

So... few "false" failures. Drawbacks: slow tests, manual verification needed if the test fails. And manual intervention to re-create the "Golden Data" when the code is fixed or the failure is identified as not a bug. I also had to write a custom file-comparison routine in order to ignore parts of the file that change all the time (a time-stamp in the file itself.)

You do not want to do "Golden Data" test data when false failures are frequent. (Or any kind of manual intervention is frequent.)

Mocking. Yes, I could mock out the drawing code. It's a bit difficult because the drawing code below this Objective-C class consists of C functions. I would have to create a "seam" to allow compile-time, link-time, or run-time switching out of the drawing library. 

Mocking can create fragile tests. Since mocking works by verifying that the code-under-test executes an expected sequence of function-calls, and checks that the parameters passed into those functions have expected values, any change to the order of calls or the parameters passed in will cause the test to fail. This depends on how picky you configure the mock objects to be.

With some work, depending on the mocking framework, you could ignore the exact sequence of function calls, but still check that all of the calls have been made. Make the mocks too "loose" and then you're not testing anything. Make the mocks too strict, and you not only open yourself up to the possibility of frequent false failures, you also inhibit refactoring the drawing code.

There is also the danger that the functions you're avoiding calling will someday change their behavior, but the mock functions don't reflect that change. Instead of false test failures, you get false test successes. Some redundancy in testing helps avoid this problem: have some tests using mocks, have other tests using the real functions and some other form of verification, like Golden Data.)

Learn about Golden Data, mocks, and other xUnit Test Patterns here: xUnit Test Patterns: Refactoring Test Code

Test-drive safely, everyone!

Tuesday, August 12, 2014

When Your Brain Freezes Up

Some time ago, I was part of team for a trivia contest. There was no internet or computer access at that location, so no chance of cheating. I took the lead on some of the questions and got them wrong!

Why did that happen? I expected the questions to be hard. I expected the trivia questions to have non-obvious answers. It turned out that the obvious answers were the correct ones.

Go to this you-tube "video" (it's audio only) where a radio disk-jockey is posing a question to someone they randomly called. If the person they called gets the question right, they could win a motorcycle worth around $8,000 (US).

DJ: We've got to ask you a question before we put your name in the barrel. Spell AC/DC.
Mark: AD AC
DJ: I'm going to ask you again.
Mark: Hang on.
DJ: How do you spell AC/DC?
Mark: A… D… A… C
There's some overlapping dialog, and we hear Mark say "ACDC" in that noise. But his answer when asked a third time is still ADAC, until they call him an idiot and tell him it's AC/DC!

It could be this guy had other issues, but under stress, our body is preparing for flight or fight. The neocortex is only a recent invention. "Flight or fight" has been around for billions of years.