Learn 2 Code TDD Style


So it’s a Wednesday night & I won’t be able to sleep unless I get this post out. Overtime I get to talking about Agile and TDD I go overboard. Hi, I’m Cliff. You’re here because you wanna know what this TDD style learning thing is all about. I’m here because I shot off my mouth over Twitter ’bout some stuff I had no business talking about. Now I gotta make something out of my tall order claims. Here I will attempt to stretch the limits of a simple programming construct as well as the limits of your imagination in my explanation.

The approach I’m going to explain is something I learned from Dierk König in the Groovy In Action book, I take no credit for the awesome technique and I’m not sure of its origins. The technique is language agnostic, will out live your written wiki documentation and stays up to date as the code evolves. So now that I got your attention, let’s get started. (Disclaimer, though it is language agnostic I will be explaining using Java syntax. Different languages/platforms may behave differently.)

What’s an assert?

This question came up in the Twitter chat so we’ll start here. (BTW, I’m really starting to dig the #CodeNewbie chat because they ask the cutest questions like, “what’s an assert?”) The basic function of an “assert” is to check a value or an expression and its form (again in Java) is:

assert (expression) : "error message when false";

The expression can be any boolean expression and the message is whatever you want to see when the expression fails. You can have something like

assert 2+3 == 1024 : "I'm not good math";

Then when you run this code it would explode your computer sending shards of silicon in random directions. Actually it would merely fail the process and dump the error message and expression to the console:

java.lang.AssertionError: I'm not good math. Expression: ((2 + 3) == 1024)

Next you could try something like

x = 3;
assert 2+3 == 1024 : "I'm not good math";

which would dump the following error to the console:

java.lang.AssertionError: I'm not good math. Expression: ((2 + x) == 1024). Values: x = 3

The interesting thing here is the way the values are dumped to the console. I’ll explain why this is so significant in a moment but for now let’s move on. You could have something more involved like this (assuming you have a guessMyAge method that lives somewhere):

result = guessMyAge();
assert result == 39 : "I think I'm 39 years old last I checked."

If the guessMyAge function can work magic then the code would run without failing. However, if magic really doesn’t exist in my Macbook pro and it really couldn’t guessMyAge then I might see something such as:

java.lang.AssertionError: I think I'm 39 years old last I checked.. Expression: (result == 39). Values: result = 109

I would then say, “Nice try Macbook. I get to pick a prize now, right?” All dry jokes aside, you might notice a pattern here. To make it clear I’ll give another example. Pay close attention because I’m going to try to confuse you.

Let’s say you had a method named “fib” defined somewhere and I gave you the task of designing an app with this function. You might panic and be all, WTH??? What is “fib”??? Or you might try something like:

assert fib("I have bad breath") == true : "I really should not have bad breath";

You would do this because you would be asserting the sentence string you give to the fib method is a “fib” or a false statement. Furthermore you might be guessing that the fib method does some sort of lie detection so you would assume passing a fib to a fib detector would return true indicating that you do NOT actually have bad breath. Again, unless your computer has magic inside you would probably get a compile error saying that the fib method takes an int parameter and returns an int value. (This is the confusing part where my example an my dry humor jump the shark.)

Sloppy humor aside. Let’s take the fib example again. This time we know that it takes an int parameter and returns an int value. We could do something like so:

int x = fib(1);
assert x == 0 : "I really don't know what this does";

Here we are setting the value of x to the return of the “fib” method without really knowing what “fib” is or what it does. We use the value in an assert and when we run it we get:

java.lang.AssertionError: I really don't know what this does. Expression: (x == 0). Values: x = 1

If you look carefully you have a valuable piece of information, “Values: x = 1”. You Didn’t know this before. We can copy and paste the value back into the assert and change the error message:

int x = fib(1);
assert x == 1 : "fib(1) should be 1";

That’s not so interesting. but watch what happens when repeat the code with a few different parameters.

x = fib(2);
assert x == 1 : "fib(2) should be 1";

x = fib(3);
assert x == 1 : "fib(3) should be 1";

x = fib(4);
assert x == 1 : "fib(4) should be 1";

We are changing the passed parameter in each case but keeping the assertion the same. After a little experience coding you might notice that usually when a different parameter is passed to a method you get a different value returned, so what gives? Think a moment. If you run this code and repeatedly copy the errors from the console back into the assert you would end up with this:

int x = fib(1);
assert x == 1 : "fib(1) should be 1";

x = fib(2);
assert x == 2 : "fib(2) should be 2";

x = fib(3);
assert x == 3 : "fib(3) should be 3";

x = fib(4);
assert x == 5 : "fib(4) should be 5";

Everything looks sort of predictable until the last line where the number jumps to 5. A few more iterations give you:

int x = fib(1);
assert x == 1 : "fib(1) should be 1";

x = fib(2);
assert x == 2 : "fib(2) should be 2";

x = fib(3);
assert x == 3 : "fib(3) should be 3";

x = fib(4);
assert x == 5 : "fib(4) should be 5";

x = fib(5);
assert x == 8 : "fib(4) should be 8";

x = fib(6);
assert x == 13 : "fib(4) should be 13";

x = fib(7);
assert x == 21 : "fib(4) should be 21";

If you have a background in computer science or have spent a lot of time programming in your career you might recognize the series of numbers emerging as the fibonacci sequence. What you have done is explore a method without knowing if was a lie-detector or a numeric series generator and through a process of iterating with different parameters and asserts you discovered its behavior. Furthermore you have documentation in the form of sentences describing the method. You could come back weeks or months later and see what the method does without looking at any of the code inside the method.

This approach works particularly well with methods in Java but how does that help you learn anything? Well, because the assert is so incredibly simple you can use it anywhere and with any programming construct. For example what does the following left shift operation do?

int x = 32 << 3;
assert x==0 : "What does this do?";

java.lang.AssertionError: What does this do?. Expression: (x == 0). Values: x = 256

Becomes:

int x = 32 << 3;
assert x==256 : "Left shift 32 by 3 should result in 256";

But what does that that actually do? A Java programming manual would say something like binary bit shifting. You can lookup the Javadoc for the Integer class to see how numbers print in binary form. Then you can use an assert to make the entire picture clear:

assert "100000".equals(Integer.toBinaryString(32)) : "32 in binary form " + Integer.toBinaryString(32)
assert "100000000".equals(Integer.toBinaryString(32 << 3)) : "32 left shifted by 3 in binary form " + Integer.toBinaryString(32 << 3)

Clearly a left shift of 3 shows the “1” bit of the binary number 32 shifted over to the left by three positions. (It would be a little more clear if we added zero-padding but I’m keeping my examples simple.) The best part is that you get documentation as a secondary benefit of using the assert. You can print this next example and post it on your wall as a reference when learning how to bit shift. This is runnable documentation of how bit shift operators work:

assert "100".equals(Integer.toBinaryString(32 >> 3)) : "32 right shifted by 3 in binary form " + Integer.toBinaryString(32 >> 3)
assert "100000".equals(Integer.toBinaryString(32)) : "32 in binary form " + Integer.toBinaryString(32)
assert "100000000".equals(Integer.toBinaryString(32 << 3)) : "32 left shifted by 3 in binary form " + Integer.toBinaryString(32 << 3)

Living documentation
I have another disclaimer. The above examples were all snippets that I actually hacked together using Groovy so they may behave slightly different in an actual Java program but the principle still applies. The idea was to focus on the assert and how it works. I used Groovy to avoid the boiler plate surrounding class definition. Now let’s look at an actual Java program to see how far we can stretch the secondary benefit. Suppose we were given a Java jar file that included the earlier “fib” method and told to use it. We could define a static block in our program and code all of the asserts inside of it as follows:

import static com.company.Funny.fib;

public class MyMain extends Object {

static {
int x = fib(1);
assert x == 1 : "fib(1) should be 1";

x = fib(2);
assert x == 2 : "fib(2) should be 2";

x = fib(3);
assert x == 3 : "fib(3) should be 3";

x = fib(4);
assert x == 5 : "fib(4) should be 5";

x = fib(5);
assert x == 8 : "fib(4) should be 8";

x = fib(6);
assert x == 13 : "fib(4) should be 13";

x = fib(7);
assert x == 21 : "fib(4) should be 21";

}

public static void main(String[] args) {
int num = Integer.parseInt(args[0]);
System.out.println("The fibonacci of " + num + " is " + fib(num));
}
}

The static block documents what we discovered with asserts and runs as soon as the class file loads for the first time. As a result it doubles (triples?) as a sanity check. The assert has performed at least three tasks. We used it to learn the behavior of the method, it now documents what we know, and finally it works as a sanity check as the program runs. What if you get an updated copy of the jar file that contains the “fib” method and the behavior of “fib” changes? The asserts run with your code and dump the current behavior to the console. You merely repeat the process you used initially to discover the behavior and update the asserts accordingly.

How we learn programming languages
When learning a programming language you have two unknowns, syntax and runtime behavior. Learning the syntax is relatively trivial in many cases and usually the smaller part of the learning curve. Syntax is usually validated when you compile your program, and if you iterate adding small additions line by line as we did above then the compiler can almost function the same as the assert.

I find that the runtime behavior is far more tricky to learn and requires the experience of actually running variations of code. The bulk of the runtime behavior involves calling methods/functions in the language. Most languages have a set of functions and classes you must learn to achieve basic functions such as string concatenation, rounding, averaging, manipulating streams, etc. These functions make up the core of the language. In Java you have the Java API. Ruby has the Ruby API, ObjC/iOS uses the CocoaTouch API, and so forth. behave slightly different than what you would expect when you are first learning. Using the assert, you can discover the subtleties of how things behave and the end result is documentation that you can print and hang on your Christmas tree.

This post was intended to explain the power of assert. I actually stretched my examples a bit in a crude attempt to illustrate how assert can be used as a learning tool for beginners. In actually what I was really doing was a light weight no frills form of TDD. While you could start out with assert, In practice you really wouldn’t use a vanilla assert in a program this way. (at least not in Java) There a number of reasons, the first being that assert is disabled in Java and you must enable it by passing a flag on the command line. If you continue with a vanilla assert you will soon see other areas where it breaks down.

My overall intention is to introduce this new way of thinking. I use the assert as a gateway drug to unit test tools with more powerful assert abilities. It is indeed as simple and powerful as I depict in this post and it does have its place, specifically among other languages like Groovy where it is not disabled. (I particularly like the way Dierk used it in his book in lieu of traditional System.out.println statements.) If you find the approach at least somewhat interesting check back later when I attempt to use a more thorough approach to learning with TDD.

Last disclaimer: It is extremely late at night and I made only a feeble attempt at proof-reading/formatting. This is because I get super excited about the topic. There are definitely errors, misspellings/etc. so forgive me.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s