FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
Development Tools
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
July 01, 2005
One More Time

Robert C. Martin
Camaraderie hits rock bottom when Alphonse is assigned to another journeyman. But behind Jasper's gleaming grin and effusive exterior, he's got a point-much to our apprentice's increasing annoyance.

July 2005

Throughout the last quarter of 1942, FDR's advisers were pressing him to declare war on the Axis. The successful detonation of an atomic bomb in August, and the increasing arsenal of those terrible weapons and the rockets to deliver them, were emboldening the hawks. Horrible though it was, it made sense. The United States would probably be unable to hold its technological advantage for long. Eliminating the virulence of fascism might be possible at the moment, but the window of opportunity could quickly close, leaving the world to face an inexorable juggernaut.

The contingent had waited to tell the president about Turing's results as they checked and double-checked the results. They had improved the computers, the telescopes, the programs and the observations, but the results could not be denied: A 22-km rock named Clyde was almost certainly going to slam into the Pacific at 53 km per second on April 29, 1943, at 0943 GMT.

On November 12, 1942, as FDR read the contingent's report, the certainty of destruction seemed to rise from the pages and clamp down upon his skull like an iron fist. He called out to his secretary, "Grace, I have a terrific headache!" Grace Tully found him collapsed over his desk, never to regain consciousness.

22 Feb 2002, 0800: I walked into the lab as people were gathering for the morning stand-up meeting and joined Avery, Jasper, Jerry, Carole and Jean in a circle. Each of us answered three questions: "What did you do yesterday?" "What do you plan to do today?" and "What's in your way?"

When my turn came, I replied, "Avery and I got the RegisterNormalSuit acceptance test to pass. I don't know what I'm doing today, and nothing but that ignorance is in my way." I saw Carole roll her eyes at that remark, and Jerry smirked.

When it was Avery's turn, he simply said, "My report is the same as Alphonse's."

After the stand-up, Jean came over and said, "Boys, I think I can solve your problems. Avery, dear, why don't you work with Jerry? He already has his next acceptance test. Alphonse, I'd like you to work with Jasper today. He'll be putting together the acceptance test for manufacturing rejection. I'm sure you and Jasper will get along wonderfully; you're both such fine young men." She gave us a warm smile and trilled, "Off with you! Shoo!"

I caught Avery's eye and gave him a regretful wave before making my way to Jasper's workstation. He was staring intently at his screen and didn't seem to know I was there. Finally, I spoke: "Hello, Jasper. I guess we're working together today."

Jasper jerked around with a big grin on his face and said, "Alphonse! Yeah, great. Hey, should I call you Al or Fonse? I kinda like Fonse. Whaddya say?"

His toothy grin and sparkling eyes put me off guard. I was about to object to the nickname, but he cut me off with a fervent "Great, Fonse! Now let's get busy on this new test."

I sighed and sat down. "Jean said something about a rejection from manufacturing?"

"Yeah, that's right. Here; look at the story card." He handed me the index card from yesterday's planning meeting.

 Register new suit.
   - Bar Code Patch X(6)
   - Register new suit, screen function.
   - Send confirmation to mfg.
      O Reject registration on denial.
      O 10s time out & reject
   - If already reg'd
      o Reject reg & don't send conf. to prod.
   - Sched for inspection.

"Oh, yeah," I said. "I remember now. Carole told us that if someone tried to register a suit that didn't come from manufacturing, we should reject the registration."

"Right," Jasper replied. "We don't want someone trying to register some old suit they found in a locker somewhere, eh?"

"OK, so we need a new acceptance test for this case, don't we?"

"Right you are, Fonse. I was just working on that when you came by." He pointed to his screen. "I created a new page named SuitRegistrationRejectedByManufacturing. I took the RegisterNormalSuit page that you guys got working yesterday and pasted it into this new page."

I examined the page, and sure enough, it was a perfect copy of the RegisterNormalSuit page. "So I guess you want to alter it to reflect the fact that manufacturing rejects the confirmation request?"

"Right again, Fonse," Jasper said with a gleaming grin. "Wanna take a crack at it, buddy?"

"Uh, sure." I wasn't sure I liked his overfriendly demeanor, and suspected it could get very obnoxious very quickly. I edited the page, changing a few comments and titles. The meat of the difference was to change the message sent by manufacturing to a rejection and to then assert that the suit didn't get placed into inventory. The result, complete with test results, looked like this:

Manufacturing rejects a suit registration

Import

dtrack.fixtures

We assume that today is 2/21/2002.

DTrack context

Today's date

2/21/2002

We also assume that there are no suits in inventory.

Suit inventory parameters

Number of suits?

0

We attempt to register suit 314159.

Suit registration request

bar code

314159

DTrack sends the registration confirmation to manufacturing.

Message sent to manufacturing

message id?

message argument?

message sender?

Suit Registration

314159

Outside Maintenance

Manufacturing rejects the confirmation.

Message received from manufacturing

message id

message argument

message sender

message recipient

Suit registration rejected

314159

Manufacturing

Outside maintenance

The rejected suit should not be in the registered inventory.

Suits in inventory

bar code?

next inspection date?

314159 surplus

2/21/2002

"Nice work!" Jasper exclaimed. "That's exactly right. Now, can you make this pass?"

"I think I can," I said, opening up the fixture that handled the "Message received from manufacturing" table. It looked like this:

 public class MessageReceivedFromManufacturing 
  extends ColumnFixture {
    public String messageId;
    public int messageArgument;
    public String messageSender;
    public String messageRecipient;
    public void execute() {
      SuitRegistrationAccepted message =
        new SuitRegistrationAccepted(messageId,
                                    messageArgument,
                                    messageSender,
                                    messageRecipient);
     Registrar.acceptMessageFromManufacturing(message);
   }
 }

It just passed the table data along to the acceptMessageFromManufacturing method of the Registrar class. That method looked like this:

 public class Registrar {
   public static void acceptMessageFromManufacturing
      (Object message) {
     SuitRegistrationAccepted suitAck = 
      (SuitRegistrationAccepted) message;
     Suit acceptedSuit = new Suit(suitAck.argument, 
      Utilities.getDate());
     SuitGateway.add(acceptedSuit);
   }
 }

Next, I made the following simple change:

 public class Registrar {
   public static void acceptMessageFromManufacturing
      (Object message) {
     SuitRegistrationAccepted suitAck = 
      (SuitRegistrationAccepted) message;
     if (suitAck.id.equals("Suit Registration Accepted")) {
       Suit acceptedSuit = new Suit(suitAck.argument, 
        Utilities.getDate());
       SuitGateway.add(acceptedSuit);
     }
   }
 }

When I ran the test, it passed.

"Nicely done, but you didn't write a unit test!" Jasper said. "Do you really think it's necessary for just this if statement?" I asked. "How hard would it be to write?" He flashed me that grin again. I shook my head and began to type. It was a simple test to write.

 public class RegistrarTest extends TestCase {
   public void testAcceptRegistration() throws Exception {
     final String acceptId = "Suit Registration Accepted";
     SuitRegistrationAccepted suitAck =
       new SuitRegistrationAccepted(acceptId, 9999, "me", "you");
     Registrar.acceptMessageFromManufacturing(suitAck);
     Suit[] suits = (Suit[])SuitGateway.getArrayOfSuits();
     assertEquals(1, suits.length);
     assertEquals(9999, suits[0].barCode());
   }
 }

The test passed on its first try. I felt a little smug, so I looked over to Jasper and raised an eyebrow. His bowl haircut made him look clueless.

"You didn't write the negative case," he said, still grinning widely.

I thought to myself, "This must be how Avery feels." I suppressed the desire to roll my eyes and returned to the keyboard.

   public void testRejectRegistration() throws Exception {
     final String rejectId = "Suit Registration Rejected";
     SuitRegistrationAccepted suitNak =
       new SuitRegistrationAccepted(rejectId, 9999, "me", "you");
     Registrar.acceptMessageFromManufacturing(suitNak);
     Suit[] suits = (Suit[])SuitGateway.getArrayOfSuits();
     assertEquals(0, suits.length);
   }

This test also worked the first time. I raised my eyebrow again.

"Hey, Fonse, the name of that class isn't quite right, is it?" That grin was really beginning to wear on me.

I held back a silent curse. I'd been hoping he wouldn't notice what I'd observed while typing this test: SuitRegistrationAccepted wasn't the right name for this class anymore. I hated to admit it, but this was something that the unit test forced me to see—and that the acceptance test had completely hidden from me. So I changed the name to SuitRegistrationAcceptanceMessage.

Jasper tilted his head in thought and then chirped, "Fonse, do you think those message IDs should really be long strings, scattered around the code? I think that's kind of ugly, don't you?"

Drat. He'd done it again—that was just what I was thinking. Strings like "Suit Registration Accepted" and "Suit Registration Rejected" probably weren't good values to use as message IDs. Moreover, they probably shouldn't be scattered around the code. "Yeah, I agree," I admitted reluctantly. "What do you think we should do about it?"

"I think we should get all the tests to pass and then refactor those ID strings out of the code altogether. Maybe we can make them independent classes."

"Uh, wait. The tests do all pass."

"Have you run them all since that last change you made, Fonse?"

"Yeah, I ..." Actually, I'd run only the testRejectRegistration test—I hadn't run any of our other unit tests. So I turned back to the screen and pushed the button that ran all the existing unit tests in the DTrack system. To my horror, testRejectRegistration failed! "Wait!" I spluttered. "That test just passed!"

"Yeah," Jasper smiled. "I think we've got a database cleanup problem. Suits are being placed into inventory without being removed at the start of each test. Try running all the acceptance tests, Fonse. I'll bet they fail, too."

Sure enough, as I pushed the suite button on the top level of our acceptance tests, the RegisterNormalSuit page passed, but the SuitRegistrationRejectedByManufacturing page—the one that had just worked 10 minutes ago—failed.

Jasper slapped his hands together and started rubbing them. "OK, Fonsie, my young apprentice, let's clean all this up." I felt a sinking sensation in the pit of my stomach as I turned to face the keyboard.

To be continued ... See www.sdmagazine.com/columnists/ martin for past episodes and code listings.


Robert C. Martin is CEO, president and founder of Object Mentor Inc., in Vernon Hills, Ill., and a frequent speaker at SD conferences.

TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK