Archive

Archive for the ‘test-driven’ Category

Tools of The Effective Developer: Fail Fast!

October 2nd, 2007 5 comments

It’s a well known fact that we regularly introduce errors with the code we write. Chances are slim to get it right on the first try. If we do, the risk is great that changing requirements and murdering deadlines will mess things up later on.

It’s also well known that the cost of failure increases with time. The sooner you discover the flaw, the easier it is to fix. In other words, if we are going to fail, there are good reasons to do it fast.

When developers talk about failing fast they usually refer to the defensive coding technique that is based on assertions and exception handling. It’s true that assertions are the very foundation of failing fast, they should be your first line of defense against bugs. But it doesn’t stop there. Failing fast should pervade your whole process of making software. You should fail fast on all levels.

The most effective fail fast-technique is automated testing, the fastest way to get feedback. Be sure to write the tests first. And don’t just automate unit-testing; integration and acceptance testing are often easier to automate than you might think. The key is to isolate your code using mock objects.

The fail-fast property doesn’t apply to code and systems alone. It should be used on the project level too. By using agile practices like short iterations, small releases, and on-site customers you create an environment of continuous feedback. It will help you steer the project to success, or – by failing fast – avoid a disaster. Kate Gregory puts it this way in a nice post from 2005:

“Failure can be a good thing. If it saves you from following a doomed path for a year, you’re glad to have failed early rather than late.”

Failing takes courage, failing increases your knowledge, failing calls upon action. That’s why I like the habit of Failing Fast.

This was the fifth post in this series. Here are the other Tools of The Effective Developer posts:

  1. Tools of The Effective Developer: Personal Logs
  2. Tools of The Effective Developer: Personal Planning
  3. Tools of The Effective Developer: Programming By Intention
  4. Tools of The Effective Developer: Customer View

Quit Debugging!

September 17th, 2007 21 comments

I have a confession to make: I used to be addicted to debugging. Yes, it’s true. When I got hooked – damn you Delphi – I wasn’t able to see the dark side, the demonic side of the debugger. It lured me into the path of quick fixes. Heed my warning: debuggers are bad!

Fortunately I’m one of the lucky few who have been able to recover from this particularly addictive behavior. I’ve been clean – thank you jUnit – for almost 5 years now. And you can do it too, you can let go of the safety zone that these integrated debuggers provide, and break free just like I did.

The first thing to do is to realize that there is a better alternative: test-driven development. To get rid of a bug, the right thing to do is not to fire up your debugger, but to write a unit-test to reveal it. If necessary, keep writing tests and go deeper and deeper into your code. Eventually the tests will tell you what is wrong, and they’ll even point out a solution for you.

I know that using a debugger may seem like a faster way to find and extinguish a bug, but that is just an illusion. Here are the reasons:

  1. TDD improves the design. Being forced to think testability tends to divide your code into small manageable pieces. This will make your code a bad breeding ground for bugs.
  2. Tests remain useful for a long time. They become an addition to your testing harness, which helps protecting your code against future infestations. The work spent in a debugging session can never be reused.
  3. Unit-testing saves time, a lot! While this isn’t immediately obvious, the long term effects are huge. Think of it: all those debugging sessions can be run automatically at your command, whenever you want, how often you want, and in just a matter of seconds. All you have to do to achieve this is to let go of the debugger, and write relevant tests.
  4. Unit-testing gives you courage. There’s nothing like a good harness to make you feel invincible. I still remember the first time I felt the real power of unit-testing. I was working on a huge legacy application and had developed a new set of functionalities, using TDD for the very first time. Several months later I realized I had to do a major rewrite. The rewrite was risky business and took me a couple of days to complete. When finished, I ran the unit-tests which all came out green! I could be confident the program worked just as before the rewrite. And the best part: I drew the conclusion out of just five seconds of testing. Boy, I still get the goose bumps.

[PREACHING OFF]

Of course debuggers are useful tools. In certain situations they are even invaluable. For someone who’s new to the software they provide a great way of getting to know it. The problem is that a debugger makes you lazy. So be sure to get rid of it as soon as you identify a testing strategy.

Cheers!

Agile low level programming in D

August 21st, 2007 2 comments

Agile software development techniques have long been utopia for low level system developers. The C programming language has been the most reasonable choice for implementing hardware near applications and drivers; But C was not designed with agility in mind. Hence methods like test driven development has been a pain to implement using C.

Now an alternative exists: The D Programming Language is designed to combine the low level programming abilities and performance of languages like C and C++, with the productivity features of modern languages.

You could describe D as C with features like object oriented programming, exception handling, garbage collection and design by contract. Cool agile features indeed, but D has another one that I instantly fell in love with: built in support for unit testing.

In D you can declare unittest blocks.

unittest {
  assert(sometest, "sometest failed");
}

The unittest construct makes it very easy to practice test-driven development. For instance, lets say we want to create a new type for three dimensional vectors. In order to be test-driven we need to start with the test:

unittest {
  Vector3 v;
}

We compile the program using the -unittest switch.

dmd -unittest test.d

Of course we get a compiler error, Vector3 is still undefined. Lets define it.

struct Vector3 {
}

This time the program compiles. Back to the unittest. Now let’s try a simple assignment.

unittest {
  Vector3 v = Vector3(1.0, 2.0, 3.0);
}

This, again, produces a compile time error. Vector3 doesn’t have the x, y and z fields, so we implement them.

struct Vector3 {
  real x, y, z;
}

The code passes compilation. Next step: implement vector addition. We start with the test.

unittest {
  Vector3 v1 = Vector3(1, 2, 3);
  Vector3 v2 = Vector3(3, 2, 1);
  Vector3 vr = v1 + v2;
}

As we expect, the code doesn’t compile. We need to overload the + operator.

struct Vector3 {
  real x, y, z;

  // Overload + operator
  Vector3 opAdd(Vector3 a)
  {
    return Vector3(0, 0, 0);
  }
}

Now the program compiles, but we don’t know if the add operator produces the right result (which it doesn’t with the current code). To check the result we can use assert.

unittest {
  Vector3 v1 = Vector3(1, 2, 3);
  Vector3 v2 = Vector3(3, 2, 1);
  Vector3 vr = v1 + v2;

  assert(vr.x == 4);
  assert(vr.y == 4);
  assert(vr.z == 4);
}

We compile, and it compiles without error. To run the unittest code we simply run the program. Unittest code is executed after program initialization, but before the main function. If a unittest fails the program terminates prematurely. Our program terminates (as expected) with an AssertError. Lets correct the add operator.

struct Vector3 {
  real x, y, z;

  Vector3 opAdd(Vector3 a)
  {
    return Vector3(x + a.x, y + a.y, z + a.z);
  }
}

It compiles and runs without errors. Great!

As you can see, test-driven development is a very smooth and simple process in D. There is no need for a separate framework, just compile and run your application. Also, the test code dwells close to the production code, which makes it easier to maintain and keep up-to-date. In fact, you can put unittest blocks anywhere in your code, even within the piece of code you are testing.

struct Vector3 {
  real x, y, z;

  // unittest blocks are allowed
  // within structs.
  unittest { ... }
}

Any type of code is allowed within a unittest block. This means that you can declare functions to do repetitive tasks.

unittest {
  function assertEqual(Vector3 a, Vector3 b)
  {
    assert(a.x == b.x);
    assert(a.y == b.y);
    assert(a.z == b.z);
  }

  Vector3 v1 = Vector3(1, 2, 3);
  Vector3 v2 = Vector3(3, 2, 1);

  assertEqual(v1 + v2, Vector3(4, 4, 4));
  assertEqual(v1 - v2, Vector3(2, 0, -2));
}

The test code is only included in the executable if it is compiled with the unittest flag, so there’s no need for a separate test project or conditional compilation. This is a very clean solution, highly suitable for a traditional language that compiles directly to machine code. Although I’m a big fan of testing framworks such as JUnit, I find it much easier to work with the built in unit testing features of D. Of course you don’t have advanced features like mock object support, but I guess that will be offered soon with some kind of unittest-based framework add-on.

If you have doubts about the foundation of the D Programming Language, you should be relieved to hear that it’s been designed by Walter Bright, who have spent almost a lifetime constructing C and C++ compilers.

You’ll find the complete code within my code sample pages.