Thursday, January 28, 2010

3 Tips for Getting that Large Project Going

Introduction

In the past, I have had a hard time getting large projects off the ground. I kept thinking about all of the technical details, which libraries and languages I will use, and how successful the project will be once it is finished.

The problem is, I never started on the work. Every time I got 20 minutes or an hour to work on it, all I could think about were these technical details.

I have long since learned from my mistakes and have found 3 general processes for getting large programming projects off the ground. If you're stuck in design mode, try giving these methods a shot:

Method 1 - Requirements Are The Key

Write only the generic requirements on a single sheet, in a binder on its own, or in a single document.

Keep the requirements short and sweet.

Keep all technical notes that you just can't stop thinking about elsewhere - they are not important in this phase. If possible, don't write them down at all. You will think of them later (or better ideas) and you don't want to force yourself into the wrong library later.

Think about how you will use this application/library, what will be difficult, what will be beneficial (again staying away from technical details including the language and library).

Begin writing code or manipulating wire frames as if you are using your newly completed project. Keep this "test code" for reference but don't make it the golden rule.

Collect flaws and focus areas and add them to a "things to consider" sheet.

Start writing simple implementation code starting at the easiest thing first (very similar to TDD but without the tests).

Success

I have used this method for some of my larger research type projects. It was very easy to adopt.

Failure

Three projects using this method never made it past this phase due to marketability and usability factors that were exposed. They seemed like fun research projects but were not practical so they remained a paper-only experiment.

Method 2 - Spike It

Maybe the best thing to do is a quick Spike (term from XP). Simply start writing a bunch of code you won't keep but will learn from. You get a feel for the project and end up writing version 2 first.

Success

I have used this successfully when picking up a modified version of the MVP pattern and some complex UI code.

Failure

I have kept the code written using this method due to time constraints. It has bitten me and was rewritten at a later date.

Warning

This works best for new requirements to existing systems. New projects also benefit as long as you are disciplined enough to toss the spike when you're finished with it.

Method 3 - TDD It To Death

This method is the hardest to master but one of the most powerful. Using Test Driven Development to work top-down (never TDD up) is very fun and productive.

First you starting at what you want to be the outcome (your initial requirements). Continue testing down until it is the implementation.

This takes practice especially when writing and maintaining the requirements list the TDD way. Refactoring and writing as little as possible while still adding value is also difficult when you've been writing legacy code for so long.

This method helps isolate dependencies so you can replace them easily if requirements change down the road.

Success

I have used this for a simple C# device interface project and a string template class. Both were to help learn TDD and both were never 100% completed. These projects had a lot of power, worked very well, and the code looked like a work of art.

Failure

This has failed just as many times as it succeeded for me. The reason was simply not knowing TDD, how to write requirements, and keeping myself from writing more code than I need to.

Summary

Start doing something NOW! Don't wait, think more, put it off... start doing something. Even failures are learning experiences. You cannot succeed if you don't try.

Good luck!

Friday, January 15, 2010

Test Driven Development in One Page or Less

Introduction

I was writing a co-worker to explain TDD. It ended up being a short and sweet guide to test driven development that I wish I had when learning TDD so I decided to share it. This is barely a starting point for TDD. I suggest reading "Test Driven: Practical TDD and Acceptance TDD for Java Developers" (even if you don't write in Java). Amazon.ca link here

If you would like a sample project for each step including tests, please leave a comment.

Development Environment

Refactoring support is crucial because you do it so often with TDD. When developing with Flex Builder (no refactoring other than rename), it was very painful and I caught myself skipping steps.

I prefer to use Visual Studio 2008 Professional (C#) + Resharper + NUnit.

NetBeans + JUnit works well and it's free.

I'm sure IntelliJ Idea is also a nice environment.

TDD In One Page

  • You write out requirements in a certain way that makes producing tests from the requirement very easy. As you develop, you may think of new requirements (what if I pass in null?) so you add these to your list but don't start them right away unless they are the next best test to develop.
  • Then you start with your test class and write your first test function.
  • Then you instrument the class you intend to write before writing it.
  • Since your tests are very basic and you start with the easiest one first, this should be short and sweet.
  • Then you write the class with an empty method (just to pass compilation), and run your test. It should fail because you're probably not testing doing nothing.
  • Then adjust the class in the simplest way possible that adds value. So for this one, we just want to make it pass. Return the expected value and viola! You're green.
  • Now refactor (no need here - with this example)
  • Continue with your next test
  • This time you're looking at a different aspect of the same function. If we were making a function that returned string length, the first test may have been: when I pass in a null, I expect a NullPointerException. Now we may be expecting a 0 when an empty string is passed in.
  • Run test (red - expected 0, got NullPointerException)
  • So adjust the function to test for null & throw an exception, otherwise return 0. It still adds value because now we test for null.
  • Run tests (green)
  • Now refactor (no need here)
  • Add a test for a single character string.
  • Run tests (fails - expected 1, got 0)
  • So adjust the function to return the string length rather than 0.
  • Run tests (green)
As you can see, TDD is about Red, Green, Refactor, next test.

So What Do We Have Here?


At this point you have some great tests that stay with the project forever and didn't take long to write. Your code is clean and easy to use.

Without TDD, you may not have accounted for (or documented) what happens when you pass a null parameter into this function. We all get busy and working fast causes oversights such as this... ones that you will pay for later. *haunted house sounds*

More Complex Behaviors

If your function is more complex than this one, refactoring may bring pieces of the logic into private methods. These private methods still have test coverage which is why TDD is better than Unit Testing after the fact.

It could also become a new class. If so, you either pretend the class already exists (create a stub for now) or create the new class as if it were now the starting point and write tests for the new class first then integrate it back into your first class when finished. I prefer the 2nd method.

Your Implementation (not test code)
// first pass
int GetStringLength(string str)
{
throw new NullReferenceException();
}

// second pass
int GetStringLength(string str)
{
if (str == null)
{
throw new NullPointerException();
}

return 0;
}

// third pass
int GetStringLength(string str)
{
if (str == null)
{
throw new NullPointerException();
}

return str.Length;
}

When NOT to Unit Test

I may get some arguments here but TDD should be avoided when dealing with UI code. That said, Model, View, Presenter is a great pattern if you want to test the code directly behind the UI. Testing the front-end is not very productive unless you absolutely have to.

Finishing Up


Hope this helps at least one person figure out what TDD is all about. I found it to be faster to develop with because I wasn't troubleshooting bugs, my code was always clean, and I knew exactly what to do next.