A few weeks ago on the TestDrivenDevelopment mailing list, Ron Jeffies, one of the XP gurus stated that "in order to obtain good code, writing tests and code is faster then just code". To find out if this is true or not let's make a small experiment.
The mini TDD experiment
We assume that we are programmers and we need to code a function that divides two positive numbers. For this experiment we will compare the traditional and the TDD approaches.
Approach #1. Code and fix
As programmers, for a simple division we will write the following “pseudo” code:
Function Divide(No1, No2)
Return No1/No2
For this very simple method, let’s assume we needed 5 seconds to write it. Now let’s test if it works. First we try 6 and 2, expecting 3. It works. Let’s try another combination: 1 and 2, expecting 0.5. It works. Now let’s try 8 and 0. An error just occurred. This means we need to modify the program to display a message to the user that the second number cannot be 0:
Function Divide(No1,No2)
If No2 = 0 then display message “Division by 0 cannot be performed”
Else Return No1/No2
Now let’s test our function again. 6 and 2, result 3, good, 1 and 2, 0.5 as expected, 8 and 0 and a message “Division by 0 cannot be performed” occurs as expected. Now, our program works fine.
Assuming that manual testing is slow and for each combination of numbers we need about 10 seconds, this means that a testing session takes 30 seconds. The total time in which we developed the code was: 5 seconds to write the function, 30 seconds to test and see it has problems with division by 0, then about another 5 to correct the function and 30 minutes to test it again and make sure it works: total 5+30+5+30=70 seconds, a minute and 10 seconds.
Approach #2: Test Driven development
In test driven development, there are a series of steps to write a piece of code, starting with and automated test written first and ending up making that test succeed, by writing the code that it tests. Let’s see how it goes:
Function TestNormalDivision()
Expect 3 as a result of Divide(6,2)
The code above compares the value expected and the value returned by our (yet unwritten code) and if they do not match it fails.
One very important step now is to make sure our test really tests something and it does not work every time, no matter what the code under test does. So for this we need to make sure that when it needs to fail, it fails. So we write the following function:
Function Divide(No1, No2)
Return 0
Now we run the test, and it fails saying: expected 3 but the result was 0. So now we modify the function to return pass the test.
Function Divide(No1, No2)
Return 3
Now we run the test again: 1 test succeeded. Excellent. Now let’s see if it works for 1 and 2, so we update the test:
Function TestNormalDivision()
Expect 3 as a result of Divide(6,2)
Expect 0.5 as a result of Divide(1,2)
We run the test. Failure. Oooh, we just realize the mistake we made (code always returns 3) and modify the Divide function:
Function Divide(No1, No2)
Return No1/No2
Running the test, now passes all our expectations. But now we think, what would happen if we used 8 and 0. Let’s add a new test to the test suite (now we have two) and make sure that if there is division by 0, the user is notified:
Function TestDivisionByZero()
Expect message “Division by 0 cannot be performed” displayed as a result of Divide(8,0)
We run the test. It fails. Now we modify our function to make it work:
Function Divide(No1,No2)
If No2 = 0 then display message “Division by 0 cannot be performed”
Else Return No1/No2
Running all our tests, we discover that they all succeed.
How much time did we need to write this code? We needed 5 seconds to write the first test, 5 seconds to make sure it fails, 1 second to run the test (now testing is done by the computer so we assume it should be at least 10 times faster then manual testing), 5 seconds to modify the code to make the test work, 1 second to run the test, another 5 seconds to extend the test to verify the 1,2 combination, 1 second to see that the test fails, 5 seconds to modify the function and 1 second to see it working, another 5 seconds to write the second test and 2 seconds to see the first test work but the second failing, and 5 seconds to complete the code and another two to run the 2 tests and make sure it works. Wow, a long way: 5+5+1+5+1+5+1+5+1+5+2+5+2 = 42 seconds.
Using both approaches, we ended up with the same code. The amount of code written for the second approach is bigger then for the first, having the code and the tests. The amount of time needed for the second approach was arguably smaller then the amount for the first approach, which leads us to Ron Jeffries’s conclusion: to obtain good code, writing tests and code is faster then code alone. The main advantage is that we use computer power to do the testing rather then human power, so we are much faster. Then we can run the automated tests over and over again and it will take 2 seconds to see if they work, manually it will take 30 to do the same thing.
Let’s go further with our experiment, assuming that now we need to extend the program to be able also to do addictions, subtractions and multiplications.
Approach #1. Code&Fix
Since all these operation are not affected by 0, but we test that anyway, the code written first will work, so it would take about 5 seconds to write each method, and testing each with 3 combinations of numbers would result in about 30 seconds to test each. The amount of time, needed would be 5+30+5+30+5+30 = 105 seconds, 1 minute and 45 seconds. Testing the whole program (the 3 new methods and the division method) would take us 4*30 = 120 seconds, which is 2 minutes.
Approach #2. TDD
Operations just as above will need only one test, checking 3 combinations. Let’s say it takes 10 seconds to write a test method like this:
Function TestMultiplication()
Expect 0 as a result of Multiply(6,0)
Expect 3 as a result of Multiply(3,1)
Expect -9 as a result of Multiply(3,-3)
Then we’d have to make sure it fails: 5 seconds, 1 second to run the test, then we’d write the code to make it work: 5 seconds and 1 second to make sure it works, so it takes about 10+5+1+5+1 = 22 seconds for each new function, resulting in 3*22 = 66 seconds or 1 minute and 6 seconds to write the new functions. Testing all the code would mean running 5 test methods (2 for division and 1 for the other three), which would be run in 5 seconds.
Tests and code, faster then just code
Comparing the times needed to test our incredibly simple system: 2 minutes vs. 5 seconds show us that not only the code is written faster (110+105=215 seconds vs 66+45=111 seconds), but making sure it works requires far less time for the TDD approach. And second big advantage, it can be done by a computer.
Using a continuous integration machine that downloads the program sources and runs the test suite, then sends us an email telling us what happened, means 5 seconds for the machine and 0 seconds on my side to test the whole system. Using the first approach, would take me 2 minutes to make sure the whole system works. I could delegate this responsibility of testing the whole system to the testing team, but the feedback times, telling me whether the system works as a whole or not, increase rapidly to days and weeks and by that time I should be doing something else.
Scalability
In the 3rd phase of our little experiment, we analyze what would happen if our system would have 400 functions instead of 4. Using the first approach it would need about 12000 seconds (that is over 3 hours) for a full test, while using the TDD and automated testing suite about 500 seconds or, better said, less then 10 minutes. This simple sample shows us scalability when it comes to TDD vs traditional coding approaches. The testing team could work, to some extent in parallel, but after, all I could set my integration machine to divide the tests and work in parallel.
After making this very small experiment, we showed how test driven development is, compared with just coding:
o faster to develop
o faster to test the whole system and give feedback
o scalable
Tests as documentation
Another advantage of the method described above is that, the automated tests can act as a very good documentation of the code written. In traditional approaches, just documenting things that can be very easily deduced from the automated tests, like how a function works, would increase even more the development time. After all, just reading:
Function TestDivisionByZero()
Expect message “Division by 0 cannot be performed” displayed as a result of Divide(8,0)
tells me or someone new in the project, that if you try to perform a division by 0, the system will display an error message on the screen.
Embrace change: how?
Having a system with 4, 400, 1000…100.000 methods, doesn’t really comfort me when it comes to making a change in it. If I change one tiny piece of code somewhere, could I break something in another part of the system? And if I do, how could I know fast enough, to be able to either correct it or reverse my changes?
To have the feedback from the code, telling me if and where I’ve broken some existing functionality, I would normally need to retest the whole system. For a 4 methods system, it would take 2 minutes, but for a more likely system, it might take hours, days or even weeks. So the courage to change decreases with the system getting bigger, thus is shortening the life of the system. When a system is too rigid and can no longer adapt to the changes on the market, it is bound to die.
Having a full regression automated test suite, that runs very fast and can be run very often, means fast feedback. Fast feedback means changes are less risky and can be done easier and faster, thus extending the life of a system.
Design advantages
Another advantage of writing automated tests for the code is that the code written tends to be very loosely coupled, thus better designed. Test driven development also tends to eliminate “partially completed code”, encouraging less code to be written, as the programmer is more focused on what is really needed, thus decreasing the amount of code and its complexity.
At a macro level, the fact that changes, even in the architecture are much easier to be performed, when using TDD combined with aggressive refactoring, allows the programmers to continuously upgrade the design and update the architecture. Since the changes are easy to do, the evolutionary design technique is encouraged, having a much smaller need to build a flexible architecture upfront, following the YAGNI principle from XP.
My insight on the business of software development, expecially in agile methodolgies and lately into functional programming
Monday, June 19, 2006
Saturday, May 20, 2006
Refactoring a legacy web application with Selenium
About two months ago, one of our clients decided, to change the way one java web application that we built for them a few years ago worked. The application is built to gather and process different kinds of measurements in a medical sector, building different charts and analysis reports on these measurements.
The requirements
When the application was first built, it was decided that each client (hospital etc) will have their own instance of the application installed at their location. That meant for instance that when a report is run, it is done on all the data from the database.
Now the client, after a market research decided that it was to hard to deploy and maintain a vast amount of applications in different locations, so they asked me if we could change the way the aplication working, so they could host the application, the application can have one database, but multiple clients can log into it and work. This would mean that the data in the database should be divided for each of their clients so they can only see their own data and now the other's.
The solution was to have a master table, I called it entities, which would now have a foreign key in all measurement tables. Although altering the database wasn't such a problem, I had to maintain the existing functionality as it was, and because of the domain there were some difficulties, especially because some complicated phisical methods of calculations were used troughout the software.
How can I change but keep existing functionality exactly the same?
If the application needs to stay the same, I had the idea of recording some testing scenarios using the great open source Selenium[1] and the Mozilla Firefox extention, called Selenium IDE [2], trough the web interface that worked for the legacy version, that would need to work with the new version also.
But if I record a database test, and want it to work after I change the internals of the project, this means that I need to have the same data into the database, when the test is rerun. For this first I created a servlet which I called CreateTestDatabaseServlet who's mission was to reset the entire data from a database to a known state. Based on that state I could record my tests, because I knew what should appear on the user interface. For instance, my servlet, cleared all FilmType rows from the database and added Film Type A, Film Type B and Film Type C. Now when going into the web application, I knew for sure that the combo on a screen , where I can choose a FilmType has the 3 values all the time:
The code of the servlet is like:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException{
this.session = HibernateUtil.getSession();
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println("");
out.println("
out.println("
try
{
out.println("
}
catch(Exception Ex)
{
Ex.printStackTrace();
}
finally
{
try {
this.session.close();
} catch (HibernateException ex) {
ex.printStackTrace();
}
this.session = null;
}
out.println("");
out.println("");
out.close();
}
where:
private String createTestDatabase() {
new AECBO(this.session).deleteAll();
new TubeRoomBO(session).deleteAll();
new UserBO(session).deleteAll();
new EntityBO(session).deleteAll();
new SUMBO(session).deleteAll();
...
return "";
}
and
private String insertTestData() {
...
createFilmType("Film Type A");
createFilmType("Film Type B");
createFilmType("Film Type C");
...
createProjection("Left Crano-Caudal");
createProjection("Right Crano-Caudal");
....
createUnit("FFD","centimeters (cm)",1);
createUnit("TRC","centimeters (cm)",1);
createUnit("FSD","meters (m)",1);
createUnit("BT","centimeters (cm)",1);
createUnit("CIO","micro-Grays (µGy)",1);
...
}
Now when a Selenium test is run, the first thing it does it reset the database to the known state, then login (I already know I have a user created by the servlet, that has a/a as credentials) and do what is necessary:
|open|/app/CreateTestDatabaseServlet|
|open|/app/login/login.faces?random=734574375|
|type|loginForm:userName|a|
|type|loginForm:password |a|
|clickAndWait|link=Login|
|clickAndWait|link=Image Quality|
|type|_id1:main:dateinput||
With the method to reset the database in place, using Selenium IDE [2] I started recording tests for all parts of the application, following different scenarios, which I then saved and created a suite of selenium tests, and after I made sure all of them work, I started dissecting the code.

Then I took a test, refactored the code and database until I made that selenium test work. Then I took the next test, until it and the one before it worked. I looked if I could make some refectorings, I did them ensuring nothing is broken and moved to the next test, until one month later all tests were working.
Although it doesn't seem like very much, the selenium regression tests helped me a great deal, telling me in 7 minutes if the existing functionality of the application (which took more then a year to develop because there are some very complicated phisics formulas in it) is working exactly as it did before, but with the extentions added. One of the big refactorings I did also was to remove the built in data access layer and business objects, and replace everything with Hibernate [3].
So it proved that my plan of action
1. Reset state of the database
2. Record the tests
3. Refactor - test until the recorded tests works again
worked very well and very fast.
Conclusion
Without Selenium, Selenium IDE and Hibernate, the entire operation could have taken a lot more then a month, because of the constant fear that the existing functionality will be broken and would need tobe rebuilt, after more then a year was already invested in the project.
[1] Selenium - www.openqa.org/selenium
[2] Selenium IDE - www.openqa.org
[3] Hibernate - www.hibernate.org
The requirements
When the application was first built, it was decided that each client (hospital etc) will have their own instance of the application installed at their location. That meant for instance that when a report is run, it is done on all the data from the database.
Now the client, after a market research decided that it was to hard to deploy and maintain a vast amount of applications in different locations, so they asked me if we could change the way the aplication working, so they could host the application, the application can have one database, but multiple clients can log into it and work. This would mean that the data in the database should be divided for each of their clients so they can only see their own data and now the other's.
The solution was to have a master table, I called it entities, which would now have a foreign key in all measurement tables. Although altering the database wasn't such a problem, I had to maintain the existing functionality as it was, and because of the domain there were some difficulties, especially because some complicated phisical methods of calculations were used troughout the software.
How can I change but keep existing functionality exactly the same?
If the application needs to stay the same, I had the idea of recording some testing scenarios using the great open source Selenium[1] and the Mozilla Firefox extention, called Selenium IDE [2], trough the web interface that worked for the legacy version, that would need to work with the new version also.
But if I record a database test, and want it to work after I change the internals of the project, this means that I need to have the same data into the database, when the test is rerun. For this first I created a servlet which I called CreateTestDatabaseServlet who's mission was to reset the entire data from a database to a known state. Based on that state I could record my tests, because I knew what should appear on the user interface. For instance, my servlet, cleared all FilmType rows from the database and added Film Type A, Film Type B and Film Type C. Now when going into the web application, I knew for sure that the combo on a screen , where I can choose a FilmType has the 3 values all the time:
The code of the servlet is like:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException{
this.session = HibernateUtil.getSession();
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println("");
out.println("
The servlet has received a " + request.getMethod() +
". This is the reply.
out.println("
"+this.createTestDatabase()+"
");try
{
out.println("
" + this.insertTestData() + "
");}
catch(Exception Ex)
{
Ex.printStackTrace();
}
finally
{
try {
this.session.close();
} catch (HibernateException ex) {
ex.printStackTrace();
}
this.session = null;
}
out.println("");
out.println("");
out.close();
}
where:
private String createTestDatabase() {
new AECBO(this.session).deleteAll();
new TubeRoomBO(session).deleteAll();
new UserBO(session).deleteAll();
new EntityBO(session).deleteAll();
new SUMBO(session).deleteAll();
...
return "";
}
and
private String insertTestData() {
...
createFilmType("Film Type A");
createFilmType("Film Type B");
createFilmType("Film Type C");
...
createProjection("Left Crano-Caudal");
createProjection("Right Crano-Caudal");
....
createUnit("FFD","centimeters (cm)",1);
createUnit("TRC","centimeters (cm)",1);
createUnit("FSD","meters (m)",1);
createUnit("BT","centimeters (cm)",1);
createUnit("CIO","micro-Grays (µGy)",1);
...
}
Now when a Selenium test is run, the first thing it does it reset the database to the known state, then login (I already know I have a user created by the servlet, that has a/a as credentials) and do what is necessary:
|open|/app/CreateTestDatabaseServlet|
|open|/app/login/login.faces?random=734574375|
|type|loginForm:userName|a|
|type|loginForm:password |a|
|clickAndWait|link=Login|
|clickAndWait|link=Image Quality|
|type|_id1:main:dateinput||
With the method to reset the database in place, using Selenium IDE [2] I started recording tests for all parts of the application, following different scenarios, which I then saved and created a suite of selenium tests, and after I made sure all of them work, I started dissecting the code.

Then I took a test, refactored the code and database until I made that selenium test work. Then I took the next test, until it and the one before it worked. I looked if I could make some refectorings, I did them ensuring nothing is broken and moved to the next test, until one month later all tests were working.
Although it doesn't seem like very much, the selenium regression tests helped me a great deal, telling me in 7 minutes if the existing functionality of the application (which took more then a year to develop because there are some very complicated phisics formulas in it) is working exactly as it did before, but with the extentions added. One of the big refactorings I did also was to remove the built in data access layer and business objects, and replace everything with Hibernate [3].
So it proved that my plan of action
1. Reset state of the database
2. Record the tests
3. Refactor - test until the recorded tests works again
worked very well and very fast.
Conclusion
Without Selenium, Selenium IDE and Hibernate, the entire operation could have taken a lot more then a month, because of the constant fear that the existing functionality will be broken and would need tobe rebuilt, after more then a year was already invested in the project.
[1] Selenium - www.openqa.org/selenium
[2] Selenium IDE - www.openqa.org
[3] Hibernate - www.hibernate.org
Saturday, April 08, 2006
Agile adaptive planning and fast delivery sample
After seeing that there are very many people that find it hard to see how agile handles adaptive planning, letting the customer not know from the beginning what he wants, I wanted to develop a mini sample to show these concepts in practice.
A small agile process practice sample
Let’s consider that we have a new client who wants a new software product to manage and track his sales and customers. He wants the system to go live in 2 months. We meet and establish what is required, then plan to meet the deadline.
After the first meetings we come up with the following feature list, that he thinks he wants, that is afterwards estimated by us:
Now together with the customer, we make the first plan, dividing the work in two iterations:
Iteration #1: 10 p
After we have a plan to deliver the 21 points features in 2 months, we start working, by starting on the first iteration, at the end of which we deliver features 1,2 and 3.
We now show the customer the first 3 features implemented, but he suddenly realizes that he needs more, then what was planned for the release. We start by adding what he wants to the list of features, which now becomes, after each of the new features are being estimated.
With the client we realize we cannot deliver all in the 2 months term, but we decide that we make a delivery after the two months and we plan another delivery after that will include other features that will make the system more compete. The new plan looks like:
Release #1: 2 months
Iteration #1: 10p
Iteration #3: 9p
As you can see, the customer considered that is more important to have the forecast reports in the first delivery so he moved the forecast report into the second iteration and the sales workflow to the 3rd iteration.
After the second iteration is over, we have the features 1-7 finished, in 2 1 month iterations, delivering on term what the customer wanted, and deploying it to be used by its end users.
At the beginning of the 3rd iteration, the customer realizes that he wants a few more things, and he would like to have the next delivery of the complete system, in another two months so he can fit his budget. He adds a few new features, having the following list now:
The plan now becomes:
Release #1: 2 months
Iteration #1: 10p
Iteration #3: 9p
After finishing and showing to the client the resulting product having now 10 features out of 12 implemented, he realizes that there is one more feature he’d like to have, and that can be implemented in the last iteration: sales processes. The list of feature becomes:
And the updated plan:
Release #1: 2 months
Iteration #1: 10 p
Iteration #3 – 9p
At the beginning of the 4th iteration the client says he’d like one more feature that is estimated by the team to be of 3 points. Adding that feature would mean not meeting the second release target, so after balancing the options he decides to drop it.
After the 4th iteration the final product is delivered. The sample above cannot show by any means how any project can be developed, but it shows the agile process at work, iteration by iteration, planning, adapting and delivering incrementally a product to the end customer.
The evolutive process of gathering the client requirements and a burn down chart, showing iteration by iteration the number of remaining features to be implemented would be like:

So after this very small sample do you think it could be useful for you?
A small agile process practice sample
Let’s consider that we have a new client who wants a new software product to manage and track his sales and customers. He wants the system to go live in 2 months. We meet and establish what is required, then plan to meet the deadline.
After the first meetings we come up with the following feature list, that he thinks he wants, that is afterwards estimated by us:
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Sales workflow (3p)
Now together with the customer, we make the first plan, dividing the work in two iterations:
Iteration #1: 10 p
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Sales workflow (3p)
After we have a plan to deliver the 21 points features in 2 months, we start working, by starting on the first iteration, at the end of which we deliver features 1,2 and 3.
We now show the customer the first 3 features implemented, but he suddenly realizes that he needs more, then what was planned for the release. We start by adding what he wants to the list of features, which now becomes, after each of the new features are being estimated.
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Sales workflow (3p)
- Activity calendar (3p)
- Forecast reports (3p)
- Document templates and document merging (3p)
With the client we realize we cannot deliver all in the 2 months term, but we decide that we make a delivery after the two months and we plan another delivery after that will include other features that will make the system more compete. The new plan looks like:
Release #1: 2 months
Iteration #1: 10p
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Forecast reports (3p)
Iteration #3: 9p
- Sales workflow (3p)
- Activity calendar (3p)
- Document templates and document merging (3p)
As you can see, the customer considered that is more important to have the forecast reports in the first delivery so he moved the forecast report into the second iteration and the sales workflow to the 3rd iteration.
After the second iteration is over, we have the features 1-7 finished, in 2 1 month iterations, delivering on term what the customer wanted, and deploying it to be used by its end users.
At the beginning of the 3rd iteration, the customer realizes that he wants a few more things, and he would like to have the next delivery of the complete system, in another two months so he can fit his budget. He adds a few new features, having the following list now:
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Sales workflow (3p)
- Activity calendar (3p)
- Forecast reports (3p)
- Document templates and document merging (3p)
- Contact communication management (3p)
- Microsoft Outlook integration (2p)
The plan now becomes:
Release #1: 2 months
Iteration #1: 10p
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Forecast reports (3p)
Iteration #3: 9p
- Sales workflow (3p)
- Activity calendar (3p)
- Document templates and document merging (3p)
- Contact communication management (3p)
- Microsoft outlook integration (2p)
After finishing and showing to the client the resulting product having now 10 features out of 12 implemented, he realizes that there is one more feature he’d like to have, and that can be implemented in the last iteration: sales processes. The list of feature becomes:
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Sales workflow (3p)
- Activity calendar (3p)
- Forecast reports (3p)
- Document templates and document merging (3p)
- Contact communication management (3p)
- Microsoft Outlook integration (2p)
- Sales Processes (5p)
And the updated plan:
Release #1: 2 months
Iteration #1: 10 p
- Client management (3p)
- Product management (3p)
- Sales leads management (4p)
- Sales reports (3p)
- Client activity management (3p)
- User management (2p)
- Forecast reports (3p)
Iteration #3 – 9p
- Sales workflow (3p)
- Activity calendar (3p)
- Document templates and document merging (3p)
- Contact communication management (3p)
- Microsoft outlook integration (2p)
- Sales processes (5p)
At the beginning of the 4th iteration the client says he’d like one more feature that is estimated by the team to be of 3 points. Adding that feature would mean not meeting the second release target, so after balancing the options he decides to drop it.
After the 4th iteration the final product is delivered. The sample above cannot show by any means how any project can be developed, but it shows the agile process at work, iteration by iteration, planning, adapting and delivering incrementally a product to the end customer.
The evolutive process of gathering the client requirements and a burn down chart, showing iteration by iteration the number of remaining features to be implemented would be like:

So after this very small sample do you think it could be useful for you?
Monday, December 19, 2005
TDDing the sales report
Download: Sources
You're starting a new project. You are talking with the customer, defining a few user stories, to make a release plan, when he says the most important thing for him would be a weekly sales report. Your immediate reaction is to say: you can't have the sales report before, you actually can put data into the system, the data entry forms should be developed first. Then he says, no, I need that first, and the data needs to come from our old system, and I will get one of my IT employees to write a data transformation code that transfers the data into your system, so that I can have the report after the first iteration.
Ok, then...so lets do that first. After a few more discussions, you and the customer write down a few acceptance tests for the sales reports as:
I have, 3 orders from 2 customers (one makes two orders as in the first forgets something).
|| order id || product || qty || unit price || customer || order total ||
|| order #123 || xxy mobile phone || 2 || 200 || company #1 limited || 400 ||
|| order #123 || xxy mobile charger || 2 || 15 || company #1 limited || 430 ||
|| order #124 || xxy mobile charger || 1 || 15 || company #1 limited || 15 ||
|| order #125 || bluetooth adapter || 1 || 20 || company #2 limited || 20 ||
|| order #125 || xxy mobile charger || 3 || 15 || company #2 limited || 65 ||
so, seeing my sales report, I would like to see how much has been sold of each product I have (sorted by product):
|| product name || qty || total ||
|| bluetooth adapter || 1 || 20 ||
|| product #no name || 0 || 0 ||
|| xxy mobile charger || 6 || 90 ||
|| xxy mobile phone || 2 || 400 ||
If I also want to include the customer I would get:
|| product name || qty || total || customer ||
|| bluetooth adapter || 1 || 20 || company #2 limited ||
|| product #no name || 0 || 0 || - ||
|| xxy mobile charger || 3 || 45 || company #1 limited ||
|| xxy mobile charger || 3 || 45 || company #2 limited ||
|| xxy mobile phone || 2 || 200 || company #1 limited ||
Ok, now let's make it work. TDD with a database. Testing with a database is not considered unit testing (Michael Feathers [1] ), but there are situations when this kind of tests could prove very good to have.
Over the years I discovered that there are three techniques that can be applied when testing code that interacts with a database:
The best technique is to avoid direct interaction with the database, by using mock objects. That can be a very good technique in many cases, as mock objects are very fast, and quite easy to use, but in this case using mock objects, might mean that out tests could cover very little of our actual functionality, so we can leave mock objects for a better situation.
Now if we really need to touch the database, and the automated tests need to be independent from one another, it is important that the state (data) of a database is the same before running each tests. For this there are two techniques: either you recreate the database in a specific state before each test is run, or any eventual changes made by a test when being run are rolled back after its execution. For the latter technique, you could use database or application transactions that can facilitate it. See Roy Osherove's: ....
The reset database technique, can be done in several ways, however speed in TDD is essential as the faster you get feedback from you tests the faster you learn what decisions to take next, so the most common technique is an in memory database, like HypersonicSQL or Cloudscape for Java, or SqlLite or Firebird for everyone. However this technique can be just as misleading as the mocking of the database in some cases, as database engines are different, and you could end up with your tests working but deployed on the real server the code to fail. In order to avoid this, you can write your tests directly against the database engine you will deploy, sacrificing speed for safety.
In order to recreate a database's state, you can clean/re-create the database and populate it from code (using an ORM/ DataSets etc) or using a sql script that does all this. The second approach might prove faster but, it is even less maintainable then the first so great caution must be imposed. However, there is a tool, that can really help us with this latter technique, who's usage in this context will be proven today.
Back to work
In TDD the first step is to write a test, make it fail then make it work (red/green factor - see: ....). Let's write the test:
[TestFixture]
public class TestSalesReport
{
SalesReportDAO dao = new SalesReportDAO();
[SetUp]
public void ResetDatabase()
{
}
[Test]
public void TestProductsAndQtySold()
{
DataSet reportDataSet = dao.GetSalesReport();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(4, report.Rows.Count, "we should have 4 rows");
}
}
As you can see we will need to add the code to the test that resets the database state. Now let's create the database and put data the test data into it, then using the amazing Tychotic Database Scripter [2] we will export the whole database state as a stored procedure that can be run in our test's setup.

and put the values in the acceptance test into it (OrderLines table):

Now let's export the script with the database scripter and create the stored procedure. The stored procedure's code is:
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[SETUP]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[SETUP]
GO
CREATE PROCEDURE [dbo].[SETUP]
AS
BEGIN
-- DELETES
DELETE FROM [dbo].[OrderLines];
DELETE FROM [dbo].[Orders];
DELETE FROM [dbo].[Customers];
DELETE FROM [dbo].[Products];
-- Products
SET IDENTITY_INSERT [dbo].[Products] ON;
INSERT INTO [dbo].[Products]
(
ID
,Name
,Price
)
SELECT 1,'xxy mobile phone',200.0000 UNION
SELECT 2,'xxy mobile charger',15.0000 UNION
SELECT 3,'bluetooth adapter ',20.0000 UNION
SELECT 4,'product #no name ',50.0000
SET IDENTITY_INSERT [dbo].[Products] OFF;
-- Customers
SET IDENTITY_INSERT [dbo].[Customers] ON;
INSERT INTO [dbo].[Customers]
(
ID
,Name
,Address
)
SELECT 1,'company #1 limited',NULL UNION
SELECT 2,'company #2 limited',NULL
SET IDENTITY_INSERT [dbo].[Customers] OFF;
-- Orders
SET IDENTITY_INSERT [dbo].[Orders] ON;
INSERT INTO [dbo].[Orders]
(
ID
,CustomerID
,OrderNo
,Total
)
SELECT 1,1,'order #123',430.0000 UNION
SELECT 2,1,'order #124',15.0000 UNION
SELECT 3,2,'order #125',65.0000
SET IDENTITY_INSERT [dbo].[Orders] OFF;
-- OrderLines
SET IDENTITY_INSERT [dbo].[OrderLines] ON;
INSERT INTO [dbo].[OrderLines]
(
ID
,OrderID
,ProductID
,UnitPrice
,Quantity
,Total
)
SELECT 1,1,1,200.0000,2,400.0000 UNION
SELECT 2,1,2,15.0000,2,30.0000 UNION
SELECT 3,2,2,15.0000,1,15.0000 UNION
SELECT 4,3,3,20.0000,1,20.0000 UNION
SELECT 5,3,2,15.0000,3,45.0000
SET IDENTITY_INSERT [dbo].[OrderLines] OFF;
END;
GO
As you can see the scripter preserves the original primary key values in the database, thus making testing easier. If you run it manually you will notice that it is very fast. Now it is time to add the code to our test that runs this stored procedure and resets the database state.
[TestFixture]
public class TestSalesReport
{
SalesReportDAO dao = new SalesReportDAO();
[SetUp]
public void ResetDatabase()
{
//we run the clean and populate with data, stored procedure
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlCommand command = new SqlCommand("SETUP", conn);
command.CommandType = CommandType.StoredProcedure;
conn.Open();
command.ExecuteNonQuery();
}
}
[Test]
public void TestProductsAndQtySold()
{
DataSet reportDataSet = dao.GetSalesReport();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(4, report.Rows.Count, "we should have 4 rows");
Assert.AreEqual("bluetooth adapter", report.Rows[0]["product_name"].ToString().Trim(), "the first product should be a bluetooth adapter");
Assert.AreEqual(DBNull.Value, report.Rows[1]["qty"], "no product #no name has been sold");
Assert.AreEqual("90.0000", report.Rows[2]["total"].ToString(), "6 xxy mobile charger sold results in 90");
}
}
To make it compile we need:
public class SalesReportDAO
{
public DataSet GetSalesReport()
{
return null;
}
}
Now we need to see if our code fails as it should since the data is not extracted from the database at this time:
------ Test started: Assembly: TDDSalesReport.dll ------
TestCase 'TDDSalesReport.Tests.TestSalesReport.TestProductsAndQtySold' failed: System.NullReferenceException : Object reference not set to an instance of an object.
D:\Projects\Dan Bunea\TDDSalesReport\TDDSalesReport\TDDSalesReport\Tests\TestSalesReport.cs(37,0): at TDDSalesReport.Tests.TestSalesReport.TestProductsAndQtySold()
0 succeeded, 1 failed, 0 skipped, took 1.02 seconds.
---------------------- Done ----------------------
Running the code will make it fail, but if we alter the database's state then rerun the test we notice that it is in the previous state, so our stored procedure works. Now all we need to do is write the code to pass the test:
public class SalesReportDAO
{
public DataSet GetSalesReport()
{
DataSet results = new DataSet();
results.Tables.Add("SalesReport");
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlDataAdapter adapter = new SqlDataAdapter(GetCommandByProduct(), conn);
adapter.Fill(results.Tables[0]);
}
return results;
}
private string GetCommandByProduct()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name,");
builder.Append(" Sum(OrderLines.Quantity) as qty,");
builder.Append(" Sum(OrderLines.Total) as total ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("group by Products.Name");
return builder.ToString();
}
}
And running it:
------ Test started: Assembly: TDDSalesReport.dll ------
1 succeeded, 0 failed, 0 skipped, took 1.19 seconds.
---------------------- Done ----------------------
Excellent, we have written a report that is accompanied by an automated test that is independent and fast enough (unfortunately my computer is rather degenerated, but on a more powerful computer the times might be decreased dramatically).
Now we could improve o by adding a few more asserts but in my opinion asserts should be handled with care, as if their number increases, they become harder to maintain so there should always be a balance between the number of asserts and the coverage a test should do, as I tried to show above.
For the second test, exactly the same approach will be used, writing the test, making it compile, making it fail, and then developing the code to make it work as in any TDD scenario. So we start with this test:
[TestFixture]
public class TestSalesReport
{
SalesReportDAO dao = new SalesReportDAO();
[SetUp]
public void ResetDatabase()
{
//we run the clean and populate with data stored procedure
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlCommand command = new SqlCommand("SETUP", conn);
command.CommandType = CommandType.StoredProcedure;
conn.Open();
command.ExecuteNonQuery();
}
}
[Test]
public void TestProductsAndQtySold()
{
DataSet reportDataSet = dao.GetSalesReportByProduct();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(4, report.Rows.Count, "we should have 4 rows");
Assert.AreEqual("bluetooth adapter", report.Rows[0]["product_name"].ToString().Trim(), "the first product should be a bluetooth adapter");
Assert.AreEqual(DBNull.Value, report.Rows[1]["qty"], "no product #no name has been sold");
Assert.AreEqual("90.0000", report.Rows[2]["total"].ToString(), "6 xxy mobile charger sold results in 90");
}
[Test]
public void TestProductsQtySoldAndCustomer()
{
DataSet reportDataSet = dao.GetSalesReportByProductAndCustomer();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(5, report.Rows.Count, "we should have 5 rows");
Assert.AreEqual("bluetooth adapter", report.Rows[0]["product_name"].ToString().Trim(), "the first product should be a bluetooth adapter");
Assert.AreEqual(DBNull.Value, report.Rows[1]["qty"], "no product #no name has been sold");
Assert.AreEqual("45.0000", report.Rows[2]["total"].ToString(), "3 xxy mobile charger sold to company #1 limited results in 45");
Assert.AreEqual("company #2 limited", report.Rows[3]["customer"].ToString().Trim(), "company #2 limited bought these");
}
}
Doing a small refactoring to the names of the methods that extract the report data from the database. Of course it doesn’t compile, but we fix that:
public class SalesReportDAO
{
public DataSet GetSalesReportByProduct()
{
DataSet results = new DataSet();
results.Tables.Add("SalesReport");
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlDataAdapter adapter = new SqlDataAdapter(GetCommandByProduct(), conn);
adapter.Fill(results.Tables[0]);
}
return results;
}
public DataSet GetSalesReportByProductAndCustomer()
{
throw new Exception("The method or operation is not implemented.");
}
private string GetCommandByProduct()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name,");
builder.Append(" Sum(OrderLines.Quantity) as qty,");
builder.Append(" Sum(OrderLines.Total) as total ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("group by Products.Name");
return builder.ToString();
}
}
then we start by running all the tests and making sure the second test fails:
------ Test started: Assembly: TDDSalesReport.dll ------
TestCase 'TDDSalesReport.Tests.TestSalesReport.TestProductsQtySoldAndCustomer' failed: System.Exception : The method or operation is not implemented.
D:\Projects\Dan Bunea\TDDSalesReport\TDDSalesReport\TDDSalesReport\DataLayer\SalesReportDAO.cs(26,0): at TDDSalesReport.DataLayer.SalesReportDAO.GetSalesReportByProductAndCustomer()
D:\Projects\Dan Bunea\TDDSalesReport\TDDSalesReport\TDDSalesReport\Tests\TestSalesReport.cs(48,0): at TDDSalesReport.Tests.TestSalesReport.TestProductsQtySoldAndCustomer()
1 succeeded, 1 failed, 0 skipped, took 1.85 seconds.
---------------------- Done ----------------------
Now let’s write the proper code to make it run:
public class SalesReportDAO
{
public DataSet GetSalesReportByProduct()
{
return GetReportResults(GetCommandByProduct());
}
public DataSet GetSalesReportByProductAndCustomer()
{
return GetReportResults(GetCommandByProductAndCustomer());
}
private DataSet GetReportResults(string sql)
{
DataSet results = new DataSet();
results.Tables.Add("SalesReport");
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlDataAdapter adapter = new SqlDataAdapter(sql, conn);
adapter.Fill(results.Tables[0]);
}
return results;
}
private string GetCommandByProduct()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name,");
builder.Append(" Sum(OrderLines.Quantity) as qty,");
builder.Append(" Sum(OrderLines.Total) as total ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("group by Products.Name");
return builder.ToString();
}
private string GetCommandByProductAndCustomer()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name, ");
builder.Append(" Sum(OrderLines.Quantity) as qty, ");
builder.Append(" Sum(OrderLines.Total) as total, ");
builder.Append(" Customers.Name as customer ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("left outer join Orders ");
builder.Append(" on Orders.Id = OrderLines.OrderID ");
builder.Append("left outer join Customers ");
builder.Append(" on Orders.CustomerId = Customers.Id ");
builder.Append("group by Products.Name,Customers.Name ");
builder.Append("order by Products.Name ");
return builder.ToString();
}
As you may see several refactorings have been made but let’s see what happens when we run it:
------ Test started: Assembly: TDDSalesReport.dll ------
2 succeeded, 0 failed, 0 skipped, took 1.32 seconds.
---------------------- Done ----------------------
I guess, we can call our customer now (. Although it might not be the most optimized code, the code does what the customer wants, backed up by automated tests that prove it and if there is need for optimizations and refactorings it is always easier to do them protected by the automated tests then without.
Conclusion
By writing just a few lines of code and with the help of a brilliant tool we managed to TDD our sales report as requested by the client, fast and in a convenient way. However, there should be caution in using this technique, as the database script might become rapidly a test maintenance nightmare if the database structure changes, so having as few scripts like this as possible as well as combining this technique with other database testing techniques, will make this maintenance work easier.
[1] Michael Feathers – A Set of Unit Testing Rules http://www.artima.com/weblogs/viewpost.jsp?thread=126923
[2] Thycotic DatabaseScripter - http://www.thycotic.com/dotnet_dbscripter.html
You're starting a new project. You are talking with the customer, defining a few user stories, to make a release plan, when he says the most important thing for him would be a weekly sales report. Your immediate reaction is to say: you can't have the sales report before, you actually can put data into the system, the data entry forms should be developed first. Then he says, no, I need that first, and the data needs to come from our old system, and I will get one of my IT employees to write a data transformation code that transfers the data into your system, so that I can have the report after the first iteration.
Ok, then...so lets do that first. After a few more discussions, you and the customer write down a few acceptance tests for the sales reports as:
I have, 3 orders from 2 customers (one makes two orders as in the first forgets something).
|| order id || product || qty || unit price || customer || order total ||
|| order #123 || xxy mobile phone || 2 || 200 || company #1 limited || 400 ||
|| order #123 || xxy mobile charger || 2 || 15 || company #1 limited || 430 ||
|| order #124 || xxy mobile charger || 1 || 15 || company #1 limited || 15 ||
|| order #125 || bluetooth adapter || 1 || 20 || company #2 limited || 20 ||
|| order #125 || xxy mobile charger || 3 || 15 || company #2 limited || 65 ||
so, seeing my sales report, I would like to see how much has been sold of each product I have (sorted by product):
|| product name || qty || total ||
|| bluetooth adapter || 1 || 20 ||
|| product #no name || 0 || 0 ||
|| xxy mobile charger || 6 || 90 ||
|| xxy mobile phone || 2 || 400 ||
If I also want to include the customer I would get:
|| product name || qty || total || customer ||
|| bluetooth adapter || 1 || 20 || company #2 limited ||
|| product #no name || 0 || 0 || - ||
|| xxy mobile charger || 3 || 45 || company #1 limited ||
|| xxy mobile charger || 3 || 45 || company #2 limited ||
|| xxy mobile phone || 2 || 200 || company #1 limited ||
Ok, now let's make it work. TDD with a database. Testing with a database is not considered unit testing (Michael Feathers [1] ), but there are situations when this kind of tests could prove very good to have.
Over the years I discovered that there are three techniques that can be applied when testing code that interacts with a database:
- mock testing
- rollback changes technique
- reset database technique.
The best technique is to avoid direct interaction with the database, by using mock objects. That can be a very good technique in many cases, as mock objects are very fast, and quite easy to use, but in this case using mock objects, might mean that out tests could cover very little of our actual functionality, so we can leave mock objects for a better situation.
Now if we really need to touch the database, and the automated tests need to be independent from one another, it is important that the state (data) of a database is the same before running each tests. For this there are two techniques: either you recreate the database in a specific state before each test is run, or any eventual changes made by a test when being run are rolled back after its execution. For the latter technique, you could use database or application transactions that can facilitate it. See Roy Osherove's: ....
The reset database technique, can be done in several ways, however speed in TDD is essential as the faster you get feedback from you tests the faster you learn what decisions to take next, so the most common technique is an in memory database, like HypersonicSQL or Cloudscape for Java, or SqlLite or Firebird for everyone. However this technique can be just as misleading as the mocking of the database in some cases, as database engines are different, and you could end up with your tests working but deployed on the real server the code to fail. In order to avoid this, you can write your tests directly against the database engine you will deploy, sacrificing speed for safety.
In order to recreate a database's state, you can clean/re-create the database and populate it from code (using an ORM/ DataSets etc) or using a sql script that does all this. The second approach might prove faster but, it is even less maintainable then the first so great caution must be imposed. However, there is a tool, that can really help us with this latter technique, who's usage in this context will be proven today.
Back to work
In TDD the first step is to write a test, make it fail then make it work (red/green factor - see: ....). Let's write the test:
[TestFixture]
public class TestSalesReport
{
SalesReportDAO dao = new SalesReportDAO();
[SetUp]
public void ResetDatabase()
{
}
[Test]
public void TestProductsAndQtySold()
{
DataSet reportDataSet = dao.GetSalesReport();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(4, report.Rows.Count, "we should have 4 rows");
}
}
As you can see we will need to add the code to the test that resets the database state. Now let's create the database and put data the test data into it, then using the amazing Tychotic Database Scripter [2] we will export the whole database state as a stored procedure that can be run in our test's setup.
and put the values in the acceptance test into it (OrderLines table):
Now let's export the script with the database scripter and create the stored procedure. The stored procedure's code is:
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[SETUP]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[SETUP]
GO
CREATE PROCEDURE [dbo].[SETUP]
AS
BEGIN
-- DELETES
DELETE FROM [dbo].[OrderLines];
DELETE FROM [dbo].[Orders];
DELETE FROM [dbo].[Customers];
DELETE FROM [dbo].[Products];
-- Products
SET IDENTITY_INSERT [dbo].[Products] ON;
INSERT INTO [dbo].[Products]
(
ID
,Name
,Price
)
SELECT 1,'xxy mobile phone',200.0000 UNION
SELECT 2,'xxy mobile charger',15.0000 UNION
SELECT 3,'bluetooth adapter ',20.0000 UNION
SELECT 4,'product #no name ',50.0000
SET IDENTITY_INSERT [dbo].[Products] OFF;
-- Customers
SET IDENTITY_INSERT [dbo].[Customers] ON;
INSERT INTO [dbo].[Customers]
(
ID
,Name
,Address
)
SELECT 1,'company #1 limited',NULL UNION
SELECT 2,'company #2 limited',NULL
SET IDENTITY_INSERT [dbo].[Customers] OFF;
-- Orders
SET IDENTITY_INSERT [dbo].[Orders] ON;
INSERT INTO [dbo].[Orders]
(
ID
,CustomerID
,OrderNo
,Total
)
SELECT 1,1,'order #123',430.0000 UNION
SELECT 2,1,'order #124',15.0000 UNION
SELECT 3,2,'order #125',65.0000
SET IDENTITY_INSERT [dbo].[Orders] OFF;
-- OrderLines
SET IDENTITY_INSERT [dbo].[OrderLines] ON;
INSERT INTO [dbo].[OrderLines]
(
ID
,OrderID
,ProductID
,UnitPrice
,Quantity
,Total
)
SELECT 1,1,1,200.0000,2,400.0000 UNION
SELECT 2,1,2,15.0000,2,30.0000 UNION
SELECT 3,2,2,15.0000,1,15.0000 UNION
SELECT 4,3,3,20.0000,1,20.0000 UNION
SELECT 5,3,2,15.0000,3,45.0000
SET IDENTITY_INSERT [dbo].[OrderLines] OFF;
END;
GO
As you can see the scripter preserves the original primary key values in the database, thus making testing easier. If you run it manually you will notice that it is very fast. Now it is time to add the code to our test that runs this stored procedure and resets the database state.
[TestFixture]
public class TestSalesReport
{
SalesReportDAO dao = new SalesReportDAO();
[SetUp]
public void ResetDatabase()
{
//we run the clean and populate with data, stored procedure
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlCommand command = new SqlCommand("SETUP", conn);
command.CommandType = CommandType.StoredProcedure;
conn.Open();
command.ExecuteNonQuery();
}
}
[Test]
public void TestProductsAndQtySold()
{
DataSet reportDataSet = dao.GetSalesReport();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(4, report.Rows.Count, "we should have 4 rows");
Assert.AreEqual("bluetooth adapter", report.Rows[0]["product_name"].ToString().Trim(), "the first product should be a bluetooth adapter");
Assert.AreEqual(DBNull.Value, report.Rows[1]["qty"], "no product #no name has been sold");
Assert.AreEqual("90.0000", report.Rows[2]["total"].ToString(), "6 xxy mobile charger sold results in 90");
}
}
To make it compile we need:
public class SalesReportDAO
{
public DataSet GetSalesReport()
{
return null;
}
}
Now we need to see if our code fails as it should since the data is not extracted from the database at this time:
------ Test started: Assembly: TDDSalesReport.dll ------
TestCase 'TDDSalesReport.Tests.TestSalesReport.TestProductsAndQtySold' failed: System.NullReferenceException : Object reference not set to an instance of an object.
D:\Projects\Dan Bunea\TDDSalesReport\TDDSalesReport\TDDSalesReport\Tests\TestSalesReport.cs(37,0): at TDDSalesReport.Tests.TestSalesReport.TestProductsAndQtySold()
0 succeeded, 1 failed, 0 skipped, took 1.02 seconds.
---------------------- Done ----------------------
Running the code will make it fail, but if we alter the database's state then rerun the test we notice that it is in the previous state, so our stored procedure works. Now all we need to do is write the code to pass the test:
public class SalesReportDAO
{
public DataSet GetSalesReport()
{
DataSet results = new DataSet();
results.Tables.Add("SalesReport");
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlDataAdapter adapter = new SqlDataAdapter(GetCommandByProduct(), conn);
adapter.Fill(results.Tables[0]);
}
return results;
}
private string GetCommandByProduct()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name,");
builder.Append(" Sum(OrderLines.Quantity) as qty,");
builder.Append(" Sum(OrderLines.Total) as total ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("group by Products.Name");
return builder.ToString();
}
}
And running it:
------ Test started: Assembly: TDDSalesReport.dll ------
1 succeeded, 0 failed, 0 skipped, took 1.19 seconds.
---------------------- Done ----------------------
Excellent, we have written a report that is accompanied by an automated test that is independent and fast enough (unfortunately my computer is rather degenerated, but on a more powerful computer the times might be decreased dramatically).
Now we could improve o by adding a few more asserts but in my opinion asserts should be handled with care, as if their number increases, they become harder to maintain so there should always be a balance between the number of asserts and the coverage a test should do, as I tried to show above.
For the second test, exactly the same approach will be used, writing the test, making it compile, making it fail, and then developing the code to make it work as in any TDD scenario. So we start with this test:
[TestFixture]
public class TestSalesReport
{
SalesReportDAO dao = new SalesReportDAO();
[SetUp]
public void ResetDatabase()
{
//we run the clean and populate with data stored procedure
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlCommand command = new SqlCommand("SETUP", conn);
command.CommandType = CommandType.StoredProcedure;
conn.Open();
command.ExecuteNonQuery();
}
}
[Test]
public void TestProductsAndQtySold()
{
DataSet reportDataSet = dao.GetSalesReportByProduct();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(4, report.Rows.Count, "we should have 4 rows");
Assert.AreEqual("bluetooth adapter", report.Rows[0]["product_name"].ToString().Trim(), "the first product should be a bluetooth adapter");
Assert.AreEqual(DBNull.Value, report.Rows[1]["qty"], "no product #no name has been sold");
Assert.AreEqual("90.0000", report.Rows[2]["total"].ToString(), "6 xxy mobile charger sold results in 90");
}
[Test]
public void TestProductsQtySoldAndCustomer()
{
DataSet reportDataSet = dao.GetSalesReportByProductAndCustomer();
DataTable report = reportDataSet.Tables[0];
Assert.AreEqual(5, report.Rows.Count, "we should have 5 rows");
Assert.AreEqual("bluetooth adapter", report.Rows[0]["product_name"].ToString().Trim(), "the first product should be a bluetooth adapter");
Assert.AreEqual(DBNull.Value, report.Rows[1]["qty"], "no product #no name has been sold");
Assert.AreEqual("45.0000", report.Rows[2]["total"].ToString(), "3 xxy mobile charger sold to company #1 limited results in 45");
Assert.AreEqual("company #2 limited", report.Rows[3]["customer"].ToString().Trim(), "company #2 limited bought these");
}
}
Doing a small refactoring to the names of the methods that extract the report data from the database. Of course it doesn’t compile, but we fix that:
public class SalesReportDAO
{
public DataSet GetSalesReportByProduct()
{
DataSet results = new DataSet();
results.Tables.Add("SalesReport");
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlDataAdapter adapter = new SqlDataAdapter(GetCommandByProduct(), conn);
adapter.Fill(results.Tables[0]);
}
return results;
}
public DataSet GetSalesReportByProductAndCustomer()
{
throw new Exception("The method or operation is not implemented.");
}
private string GetCommandByProduct()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name,");
builder.Append(" Sum(OrderLines.Quantity) as qty,");
builder.Append(" Sum(OrderLines.Total) as total ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("group by Products.Name");
return builder.ToString();
}
}
then we start by running all the tests and making sure the second test fails:
------ Test started: Assembly: TDDSalesReport.dll ------
TestCase 'TDDSalesReport.Tests.TestSalesReport.TestProductsQtySoldAndCustomer' failed: System.Exception : The method or operation is not implemented.
D:\Projects\Dan Bunea\TDDSalesReport\TDDSalesReport\TDDSalesReport\DataLayer\SalesReportDAO.cs(26,0): at TDDSalesReport.DataLayer.SalesReportDAO.GetSalesReportByProductAndCustomer()
D:\Projects\Dan Bunea\TDDSalesReport\TDDSalesReport\TDDSalesReport\Tests\TestSalesReport.cs(48,0): at TDDSalesReport.Tests.TestSalesReport.TestProductsQtySoldAndCustomer()
1 succeeded, 1 failed, 0 skipped, took 1.85 seconds.
---------------------- Done ----------------------
Now let’s write the proper code to make it run:
public class SalesReportDAO
{
public DataSet GetSalesReportByProduct()
{
return GetReportResults(GetCommandByProduct());
}
public DataSet GetSalesReportByProductAndCustomer()
{
return GetReportResults(GetCommandByProductAndCustomer());
}
private DataSet GetReportResults(string sql)
{
DataSet results = new DataSet();
results.Tables.Add("SalesReport");
using (SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["connection_string"]))
{
SqlDataAdapter adapter = new SqlDataAdapter(sql, conn);
adapter.Fill(results.Tables[0]);
}
return results;
}
private string GetCommandByProduct()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name,");
builder.Append(" Sum(OrderLines.Quantity) as qty,");
builder.Append(" Sum(OrderLines.Total) as total ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("group by Products.Name");
return builder.ToString();
}
private string GetCommandByProductAndCustomer()
{
StringBuilder builder = new StringBuilder();
builder.Append("select ");
builder.Append(" Products.Name as product_name, ");
builder.Append(" Sum(OrderLines.Quantity) as qty, ");
builder.Append(" Sum(OrderLines.Total) as total, ");
builder.Append(" Customers.Name as customer ");
builder.Append("from Products ");
builder.Append("left outer join OrderLines ");
builder.Append(" on Products.Id = OrderLines.ProductID ");
builder.Append("left outer join Orders ");
builder.Append(" on Orders.Id = OrderLines.OrderID ");
builder.Append("left outer join Customers ");
builder.Append(" on Orders.CustomerId = Customers.Id ");
builder.Append("group by Products.Name,Customers.Name ");
builder.Append("order by Products.Name ");
return builder.ToString();
}
As you may see several refactorings have been made but let’s see what happens when we run it:
------ Test started: Assembly: TDDSalesReport.dll ------
2 succeeded, 0 failed, 0 skipped, took 1.32 seconds.
---------------------- Done ----------------------
I guess, we can call our customer now (. Although it might not be the most optimized code, the code does what the customer wants, backed up by automated tests that prove it and if there is need for optimizations and refactorings it is always easier to do them protected by the automated tests then without.
Conclusion
By writing just a few lines of code and with the help of a brilliant tool we managed to TDD our sales report as requested by the client, fast and in a convenient way. However, there should be caution in using this technique, as the database script might become rapidly a test maintenance nightmare if the database structure changes, so having as few scripts like this as possible as well as combining this technique with other database testing techniques, will make this maintenance work easier.
[1] Michael Feathers – A Set of Unit Testing Rules http://www.artima.com/weblogs/viewpost.jsp?thread=126923
[2] Thycotic DatabaseScripter - http://www.thycotic.com/dotnet_dbscripter.html
Thursday, December 08, 2005
Test a little, code a little - a practical introduction to TDD
Introduction
Test Driven Development is one of the most well known practices in and outside agile communities. However, the level of understanding is in my opinion low as the term seems to be surrounded by lots of misunderstanding and misuse.
Biggest confusions regarding TDD
Many people that do not know too many things about agile practices, or beginners tend to think that test driven development, means having written automated test for your code or even worse that test driven development is a method to test the code, rather then develop it.
1. Test Driven Development is for testers
A lot of confusion comes from the name: Test Driven Development, which to some developers means a method of writing automated tests for software, something that should be the QA team’s responsibility. Having the test word in the name tends to confuse a lot of developers, who presume as explain above that TDD should be ignored as it is a practice for the QA. This comes from a partial read of the title, imagining the rest. The title was intended to be quite clear: automated tests that drive the development of the code
2. I do TDD because I have automated tests that test my code
Beginners in agile practices, have the tendency to believe that having automated tests that cover parts of the whole code, means they are doing TDD. In fact it is right, only of those tests were developed before the code was developed and not after. If the test code did not influence the development of the code, then it is not TDD, it is just having automated tests, which is a good thing, anyway.Having automated tests can say that is partially TDD even if the tests were not developed before the code, at a high or better said project level, as the biggest purpose of the tests in a project as a whole is detecting when something is broken by a change a developer makes, which influences the decisions he makes later in the design and in the code he writes, thus driving the way the software is written.
Theory
Test Driven development is a software development technique, targeted for software developers, and not software testers, that uses automated tests that are written at first, to influence and drive the code that is being written. In the end the code passes the tests, which means that it has been driven towards passing a specific number of tests.
The technique has been widely described, so I will try to keep my introduction as simple as possible. The technique is also called red-green factor, test a little, code a little or test, fail, code , pass and consists from a list of steps that are followed in order to obtain the code we want.
So it is a coding technique, one a little bit different, as it presumes the following steps:
- Test: Write a small test (one, not more)
- Compile: Make the code compile, and make the test fail
- Fail: running the test will show it failing (red)
- Code: write the code, just enough to make the test pass, not more
- Pass: run the test , it should pass. If it doesn’t code a little more (step 4). If it passes, you get the red (red-green factor)
- Refactor: refactor the code written so far (both test and code)
- Pass again. If it doesn’t go to step 4.
- Repeat: Go to step 1 and do it again, until you have the desired code, passing all the tests it should pass.
This would be the simplified list of steps that need to be done in test driven development. In fact, the list is a little bit longer as the first step is always think: about what you need and then the second is to think about making a simple test, then following the 1-8 steps and going back sufficient times to make the code good. This is an iterative process that presumes making a test (test a little) and building the code that passes it (code a little), and repeating this step as much as needed.
Practice
Suppose we have a order processing system, requested by the customer and I am asked to write the part where the clients are given a discount if the order total is over a certain limit. In Extreme Programming, this would be a programming task of a user story .
At this time, I have absolutely no code written. First I think I should have an Order class and maybe also an OrderLine class. Let me write a test about that (step 1):
[TestFixture]
public class OrderTests
{
[Test]
public void EmptyOrder()
{
Order order = new Order();
Assert.AreEqual(0,order.Total);
}
}
I have no such class Order. So at step 2 I should make the code compile and them and at the same time make the test fail. So I write the following code:
public class Order
{
public decimal Total
{
get{throw new NotImplementedException();}
}
}
I can compile the code now, so I should see if the code fails:

It seems steps 1-3 were simple, let’s move on and add the code that passes the test. You might be surprised:
public class Order
{
public decimal Total
{
get{return 0;}
}
}
The fact that I intentionally wrote return 0, makes the code be bad but still pass the test. However this is very good way of understanding that the code needs to pass the tests, as they are influencing the development and that it is important not to write code I advance.And now let’s if it passes as it should (step 5):

Wow, now we have implemented a passing test, we should see if any refactoring is needed. So far I don’t see any so since the code still passes the test, I can consider the first cycle completed. Back to the first step, adding a new test, for a few order lines.
[TestFixture]
public class OrderTests
{
[Test]
public void EmptyOrder()
{
Order order = new Order();
Assert.AreEqual(0,order.Total);
}
[Test]
public void TwoOrderLinesTotal()
{
Order order = new Order();
OrderLine ol1 = new OrderLine();
ol1.Product = "Laptop";
ol1.Quantity = 1.0;
ol1.Price = 1000.0;
OrderLine ol2 = new OrderLine();
ol2.Product = "Monitor";
ol2.Quantity = 2.0;
ol2.Price = 200.0;
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
Assert.AreEqual(1400.0, order.Total);
}
}
Let’s make it compile and fail, by adding the OrderLine class and AddOrderLine method:
public class OrderLine
{
public string Product
{
get {throw new NotImplementedException();}
set { }
}
public decimal Quantity
{
get { throw new NotImplementedException(); }
set { }
}
public decimal Price
{
get { throw new NotImplementedException(); }
set { }
}
}
And:
public class Order
{
public decimal Total
{
get{return 0;}
}
public void AddOrderLine(OrderLine ol)
{
}
}
Let’s see if it fails (we run all the tests):

Now it is time to code to make the test pass.We add a little code, then if it compiles, run the tests. If it fails, then we need to code some more, and run again and so on until the code passes the tests. The code becomes:
public class Order
{
private IList orderLines = new ArrayList();
public decimal Total
{
get
{
decimal sum = (decimal)0;
foreach(OrderLine ol in this.orderLines)
{
sum += ol.Total;
}
return sum;
}
}
public void AddOrderLine(OrderLine ol)
{
this.orderLines.Add(ol);
}
}
And OrderLine:
public class OrderLine
{
private decimal quantity;
private decimal price;
private string product;
public string Product
{
get { return product; }
set { product = value; }
}
public decimal Quantity
{
get { return quantity; }
set { quantity = value; }
}
public decimal Price
{
get { return price; }
set { price = value; }
}
public decimal Total
{
get
{
return this.quantity * this.price;
}
}
}

Wow, this is the second time in the last 10 minutes, now let’s look for some refactoring possibilities. The code seems ok, but maybe we can do something about the test, as it seems the order initialization code is duplicated. We move it into the SetUp method, as it is run before every method is run, then the OrderLine initialization code could be moved to another method:
[TestFixture]
public class OrderTests
{
Order order = null;
[SetUp]
public void SetUp()
{
order = new Order();
}
[Test]
public void EmptyOrder()
{
Assert.AreEqual(0,order.Total);
}
[Test]
public void TwoOrderLinesTotal()
{
OrderLine ol1 = CreateOrderLine("Laptop",1,1000);
OrderLine ol2 = CreateOrderLine("Monitor", 2, 200);
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
Assert.AreEqual(1400.0, order.Total);
}
private OrderLine CreateOrderLine(string product, decimal quantity, decimal price)
{
OrderLine ol1 = new OrderLine();
ol1.Product = product;
ol1.Quantity = quantity;
ol1.Price = price;
return ol1;
}
}
Now see if it still passes:

It does, so we have just finished the second cycle, and we have an almost good code, pretty much tested if it works ok. Now let’s add the part with the discount, using another “test a little, code a little” cycle. First we add the test:
[TestFixture]
public class OrderTests
{
Order order = null;
[SetUp]
public void SetUp()
{
order = new Order();
}
[Test]
public void EmptyOrder()
{
Assert.AreEqual(0,order.Total);
}
[Test]
public void TwoOrderLinesTotal()
{
OrderLine ol1 = CreateOrderLine("Laptop",1,1000);
OrderLine ol2 = CreateOrderLine("Monitor", 2, 200);
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
Assert.AreEqual(1400.0, order.Total);
}
[Test]
public void Discount10PercentOver2000()
{
IRule discountRule = new DiscountRule(10, 2000);
OrderLine ol1 = CreateOrderLine("Laptop", 1, 1000);
OrderLine ol2 = CreateOrderLine("Monitor", 2, 200);
OrderLine ol3 = CreateOrderLine("MimiMac", 2, 500);
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
order.ApplyBusinessRule(discountRule);
Assert.AreEqual(2400.0, order.Total);
Assert.AreEqual(2160.0, order.TotalAfterDiscount);
}
private OrderLine CreateOrderLine(string product, decimal quantity, decimal price)
{
OrderLine ol1 = new OrderLine();
ol1.Product = product;
ol1.Quantity = quantity;
ol1.Price = price;
return ol1;
}
}
We ensure everything is compilable and then that the test fails, then we struggle to make it pass, fixing the code, then we realize something very ugly: the test should work but it doesn’t.


We have a bug in the test. Now we see that in the test we forgot to add the order line #3 at the order (totals 1400), so we add it, then rerun the test. It seems the relationship between tests and code makes the bugs easy to find in both parts of the code:

Well, it seems that we have a few simple tests that helped us build a piece of code. Now these tests helped us so far, and by adding them to a test suite on the project, and running them regularly, can really tell us when they have been broken and where.
Hopefully, the above lines will clear a little the "fog" around what TDD means and how it can be applied practically.
Test Driven Development is one of the most well known practices in and outside agile communities. However, the level of understanding is in my opinion low as the term seems to be surrounded by lots of misunderstanding and misuse.
Biggest confusions regarding TDD
Many people that do not know too many things about agile practices, or beginners tend to think that test driven development, means having written automated test for your code or even worse that test driven development is a method to test the code, rather then develop it.
1. Test Driven Development is for testers
A lot of confusion comes from the name: Test Driven Development, which to some developers means a method of writing automated tests for software, something that should be the QA team’s responsibility. Having the test word in the name tends to confuse a lot of developers, who presume as explain above that TDD should be ignored as it is a practice for the QA. This comes from a partial read of the title, imagining the rest. The title was intended to be quite clear: automated tests that drive the development of the code
2. I do TDD because I have automated tests that test my code
Beginners in agile practices, have the tendency to believe that having automated tests that cover parts of the whole code, means they are doing TDD. In fact it is right, only of those tests were developed before the code was developed and not after. If the test code did not influence the development of the code, then it is not TDD, it is just having automated tests, which is a good thing, anyway.Having automated tests can say that is partially TDD even if the tests were not developed before the code, at a high or better said project level, as the biggest purpose of the tests in a project as a whole is detecting when something is broken by a change a developer makes, which influences the decisions he makes later in the design and in the code he writes, thus driving the way the software is written.
Theory
Test Driven development is a software development technique, targeted for software developers, and not software testers, that uses automated tests that are written at first, to influence and drive the code that is being written. In the end the code passes the tests, which means that it has been driven towards passing a specific number of tests.
The technique has been widely described, so I will try to keep my introduction as simple as possible. The technique is also called red-green factor, test a little, code a little or test, fail, code , pass and consists from a list of steps that are followed in order to obtain the code we want.
So it is a coding technique, one a little bit different, as it presumes the following steps:
- Test: Write a small test (one, not more)
- Compile: Make the code compile, and make the test fail
- Fail: running the test will show it failing (red)
- Code: write the code, just enough to make the test pass, not more
- Pass: run the test , it should pass. If it doesn’t code a little more (step 4). If it passes, you get the red (red-green factor)
- Refactor: refactor the code written so far (both test and code)
- Pass again. If it doesn’t go to step 4.
- Repeat: Go to step 1 and do it again, until you have the desired code, passing all the tests it should pass.
This would be the simplified list of steps that need to be done in test driven development. In fact, the list is a little bit longer as the first step is always think: about what you need and then the second is to think about making a simple test, then following the 1-8 steps and going back sufficient times to make the code good. This is an iterative process that presumes making a test (test a little) and building the code that passes it (code a little), and repeating this step as much as needed.
Practice
Suppose we have a order processing system, requested by the customer and I am asked to write the part where the clients are given a discount if the order total is over a certain limit. In Extreme Programming, this would be a programming task of a user story .
At this time, I have absolutely no code written. First I think I should have an Order class and maybe also an OrderLine class. Let me write a test about that (step 1):
[TestFixture]
public class OrderTests
{
[Test]
public void EmptyOrder()
{
Order order = new Order();
Assert.AreEqual(0,order.Total);
}
}
I have no such class Order. So at step 2 I should make the code compile and them and at the same time make the test fail. So I write the following code:
public class Order
{
public decimal Total
{
get{throw new NotImplementedException();}
}
}
I can compile the code now, so I should see if the code fails:
It seems steps 1-3 were simple, let’s move on and add the code that passes the test. You might be surprised:
public class Order
{
public decimal Total
{
get{return 0;}
}
}
The fact that I intentionally wrote return 0, makes the code be bad but still pass the test. However this is very good way of understanding that the code needs to pass the tests, as they are influencing the development and that it is important not to write code I advance.And now let’s if it passes as it should (step 5):
Wow, now we have implemented a passing test, we should see if any refactoring is needed. So far I don’t see any so since the code still passes the test, I can consider the first cycle completed. Back to the first step, adding a new test, for a few order lines.
[TestFixture]
public class OrderTests
{
[Test]
public void EmptyOrder()
{
Order order = new Order();
Assert.AreEqual(0,order.Total);
}
[Test]
public void TwoOrderLinesTotal()
{
Order order = new Order();
OrderLine ol1 = new OrderLine();
ol1.Product = "Laptop";
ol1.Quantity = 1.0;
ol1.Price = 1000.0;
OrderLine ol2 = new OrderLine();
ol2.Product = "Monitor";
ol2.Quantity = 2.0;
ol2.Price = 200.0;
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
Assert.AreEqual(1400.0, order.Total);
}
}
Let’s make it compile and fail, by adding the OrderLine class and AddOrderLine method:
public class OrderLine
{
public string Product
{
get {throw new NotImplementedException();}
set { }
}
public decimal Quantity
{
get { throw new NotImplementedException(); }
set { }
}
public decimal Price
{
get { throw new NotImplementedException(); }
set { }
}
}
And:
public class Order
{
public decimal Total
{
get{return 0;}
}
public void AddOrderLine(OrderLine ol)
{
}
}
Let’s see if it fails (we run all the tests):
Now it is time to code to make the test pass.We add a little code, then if it compiles, run the tests. If it fails, then we need to code some more, and run again and so on until the code passes the tests. The code becomes:
public class Order
{
private IList orderLines = new ArrayList();
public decimal Total
{
get
{
decimal sum = (decimal)0;
foreach(OrderLine ol in this.orderLines)
{
sum += ol.Total;
}
return sum;
}
}
public void AddOrderLine(OrderLine ol)
{
this.orderLines.Add(ol);
}
}
And OrderLine:
public class OrderLine
{
private decimal quantity;
private decimal price;
private string product;
public string Product
{
get { return product; }
set { product = value; }
}
public decimal Quantity
{
get { return quantity; }
set { quantity = value; }
}
public decimal Price
{
get { return price; }
set { price = value; }
}
public decimal Total
{
get
{
return this.quantity * this.price;
}
}
}
Wow, this is the second time in the last 10 minutes, now let’s look for some refactoring possibilities. The code seems ok, but maybe we can do something about the test, as it seems the order initialization code is duplicated. We move it into the SetUp method, as it is run before every method is run, then the OrderLine initialization code could be moved to another method:
[TestFixture]
public class OrderTests
{
Order order = null;
[SetUp]
public void SetUp()
{
order = new Order();
}
[Test]
public void EmptyOrder()
{
Assert.AreEqual(0,order.Total);
}
[Test]
public void TwoOrderLinesTotal()
{
OrderLine ol1 = CreateOrderLine("Laptop",1,1000);
OrderLine ol2 = CreateOrderLine("Monitor", 2, 200);
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
Assert.AreEqual(1400.0, order.Total);
}
private OrderLine CreateOrderLine(string product, decimal quantity, decimal price)
{
OrderLine ol1 = new OrderLine();
ol1.Product = product;
ol1.Quantity = quantity;
ol1.Price = price;
return ol1;
}
}
Now see if it still passes:
It does, so we have just finished the second cycle, and we have an almost good code, pretty much tested if it works ok. Now let’s add the part with the discount, using another “test a little, code a little” cycle. First we add the test:
[TestFixture]
public class OrderTests
{
Order order = null;
[SetUp]
public void SetUp()
{
order = new Order();
}
[Test]
public void EmptyOrder()
{
Assert.AreEqual(0,order.Total);
}
[Test]
public void TwoOrderLinesTotal()
{
OrderLine ol1 = CreateOrderLine("Laptop",1,1000);
OrderLine ol2 = CreateOrderLine("Monitor", 2, 200);
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
Assert.AreEqual(1400.0, order.Total);
}
[Test]
public void Discount10PercentOver2000()
{
IRule discountRule = new DiscountRule(10, 2000);
OrderLine ol1 = CreateOrderLine("Laptop", 1, 1000);
OrderLine ol2 = CreateOrderLine("Monitor", 2, 200);
OrderLine ol3 = CreateOrderLine("MimiMac", 2, 500);
order.AddOrderLine(ol1);
order.AddOrderLine(ol2);
order.ApplyBusinessRule(discountRule);
Assert.AreEqual(2400.0, order.Total);
Assert.AreEqual(2160.0, order.TotalAfterDiscount);
}
private OrderLine CreateOrderLine(string product, decimal quantity, decimal price)
{
OrderLine ol1 = new OrderLine();
ol1.Product = product;
ol1.Quantity = quantity;
ol1.Price = price;
return ol1;
}
}
We ensure everything is compilable and then that the test fails, then we struggle to make it pass, fixing the code, then we realize something very ugly: the test should work but it doesn’t.
We have a bug in the test. Now we see that in the test we forgot to add the order line #3 at the order (totals 1400), so we add it, then rerun the test. It seems the relationship between tests and code makes the bugs easy to find in both parts of the code:
Well, it seems that we have a few simple tests that helped us build a piece of code. Now these tests helped us so far, and by adding them to a test suite on the project, and running them regularly, can really tell us when they have been broken and where.
Hopefully, the above lines will clear a little the "fog" around what TDD means and how it can be applied practically.
Sunday, November 27, 2005
Model View Presenter - is testing the presenter enough?
Source code: Download
Lately, I have noticed that the Humble Dialog Box or Model View Presenter are gaining more and more acceptance among software developers, especially in agile communities, because of its benefits regarding the very good separation between the view and the behavior and because it can be very easily unit tested, on a problematic field: user interface.
Let's meet Model View Presenter
In model view presenter just as Martin Fowler or Michael Feathers [2] say, the logic of the UI is separated into a class called presenter, that handles all the input from the user and that tells the "dumb" view what and when to display. The special testability of the pattern comes from the fact that the entire view can be replaced with a mock object and in this way the presenter, which is the most important part, can be easily unit tested in isolation. Let's take a small sample:
A client writes in a user story:
User management
The system will support managing users. Each user can have a username and a password. The system will present a list of user and when one is selected, it can be edited. Also there will be functionality to add new users and to be able to select a user from the list and delete it.
Ok, now let's get to work:
Our view should need the following data, which will be put into an interface:

The UsersList represents the list of users, and the User is the current user selected at a certain time.
When the UI is displayed, we want to be able to see the list of available users, and by default the first in the list to be selected. Let’s write a small test for that. Having no view, we will make a simple implementation of the IUsersView, called UsersMockView. Using it we will be able to see if the presenter when it is initialized sets the needed list and the first is selected in it.

where we have:

And for the data we use a separate model class, like:

If I want to make my test compile, I must write my presenter, see the test failing then keep working on it until the test is working:

and now it is time for a new test, and a small refactoring in the test code:

Now we can go further and add the missing code ... until it works. We then follow the same procedure until we have quite a suite that test selecting a user in the list, updating its details, deleting a user, deleting all the users, and others. Now we know we have a Presenter that works fine. At least where it is tested.
Could we have used a dynamic mock?
I like writing in some cases the mock objects by hand. However there are a few dynamic solutions that can prove quite helpful, like NMock [3] for instance. NMock can create mock objects, using Reflection.Emit and your interfaces “on the fly”. Then it is also very useful when it comes to seeing what methods were invoked in the mock object by your class under test. You can also set predefined responses, when the class under test invokes your mock object, but that is another matter. Let’s make a small sample, just as we did before manually. For the TestInit, using NMock it will be like:

It works. The presenter has invoked the properties of the mock object, once as expected and set the expected values. This way we can throw away our previous tests, and can build a new presenter based on testing with dynamic mock objects.
Implementing the real view
If you read Michael Feather’s “Humble Dialog Box” article, you’ll be able to see very well how the real view should be built. The presenter sets the values into the view which are the propagated to the properties of the controls, much like:

but once .NET was released, it comes with the concept of data binding, and there are some developers that do not want to ignore it and use the “old and safe” ways as above.
How does MVP cope with data-binding?
.NET 2.0 comes with a new and much better concept for data binding then 1.0 or 1.1 did, the BindingSource. This now has the possibility to be connected to different kinds of data sources, including business objects. For our interface we create two: bsUser for User and bsUserList for the list of Users. Then for binding we can use, the designer as:

Now, we go back to our properties that are used by the presenter to “push” data into the view to be displays, and modify the code to use the binding sources as follows:

As you can also see, user actions on the view are delegated to the presenter, which is now fully in control of what behavior of out user management interface.
If we run the tests again, they are all green, all succeed. This is great, but this green is false if you think that it works with data-binding because the tests do not touch in any way the actual view. So what do we do?
A first option would be to leave it like that. But since a view for a desktop application is not exactly as “dumb” as we would like, and can quickly become a source of error, we need to add some tests.
Using a functional testing framework like NUnitForms or SharpRobo could be a solution but this can result in tests that test the same thing, and that is not exactly maintenance friendly. But wait, what if our stub is not exactly a stub but an extension of the view itself, to which we can add testing code. For this we inherit, the real view and create ExtendedUsersView. Now we want to modify the testing code in such a way, that the existing code is still reused. For this we inherit the manual test we have written, and just override the SetUp method:

If we run it, it will run the initial tests but on the actual view. It needs to be shown as data-binding to the controls is done when the controls become visible, but that is not a problem. The problem can be speed, but if you run the code you’ll be able to see that the difference is not that significant. If speed is a problem, then maybe you can run the tests that use the actual view, more rarely, as you can get quite enough feedback from the mock tests.
The process
About the process of building destop application pieces, the way I have constructed the application above, might seem wrong, as using TDD, I built the presenter, but I did not have the view yet, and that was constructed later on the exact same set of tests. In practice I wouldn't recommend this, as the first step, building the presenter without the view, using TDD might lead to a code that will need big refactorings (both presenter and tests) when the view is built. A better approach would be to construct, a two test cases, one inheriting teh other, with two setup methods, one with the mock view, and one with the actual extended view, then build a test inside the first, and build some code on it in both the presenter and the view, then add a new test and so on, until we have tested both the presenter and the view, having both tests that are fast and isolate the presenter's bahavoius and tests that also cover the view.
Conclusion
I have tried to present a solution, that can cover more of the code with unit tests, then only the presenter, as for desktop applications this can be an important issue. I have also tried to find a solution that works with data-binding, and what I have found seems ok so far, but only time and more research and tests can really tell if this was a good choise….
1. Martin Fowler - Model View Presenter
2. Michel Feathers - The humble dialog box
3. Peter Provost - TDD in .NET
4. Jeremy Miller - A simple example of "humble dialog box"
5. Ben Reichelt - Learning teh model view presenter pattern
Lately, I have noticed that the Humble Dialog Box or Model View Presenter are gaining more and more acceptance among software developers, especially in agile communities, because of its benefits regarding the very good separation between the view and the behavior and because it can be very easily unit tested, on a problematic field: user interface.
Let's meet Model View Presenter
In model view presenter just as Martin Fowler or Michael Feathers [2] say, the logic of the UI is separated into a class called presenter, that handles all the input from the user and that tells the "dumb" view what and when to display. The special testability of the pattern comes from the fact that the entire view can be replaced with a mock object and in this way the presenter, which is the most important part, can be easily unit tested in isolation. Let's take a small sample:
A client writes in a user story:
User management
The system will support managing users. Each user can have a username and a password. The system will present a list of user and when one is selected, it can be edited. Also there will be functionality to add new users and to be able to select a user from the list and delete it.
Ok, now let's get to work:
Our view should need the following data, which will be put into an interface:

The UsersList represents the list of users, and the User is the current user selected at a certain time.
When the UI is displayed, we want to be able to see the list of available users, and by default the first in the list to be selected. Let’s write a small test for that. Having no view, we will make a simple implementation of the IUsersView, called UsersMockView. Using it we will be able to see if the presenter when it is initialized sets the needed list and the first is selected in it.
where we have:
And for the data we use a separate model class, like:
If I want to make my test compile, I must write my presenter, see the test failing then keep working on it until the test is working:
and now it is time for a new test, and a small refactoring in the test code:
Now we can go further and add the missing code ... until it works. We then follow the same procedure until we have quite a suite that test selecting a user in the list, updating its details, deleting a user, deleting all the users, and others. Now we know we have a Presenter that works fine. At least where it is tested.
Could we have used a dynamic mock?
I like writing in some cases the mock objects by hand. However there are a few dynamic solutions that can prove quite helpful, like NMock [3] for instance. NMock can create mock objects, using Reflection.Emit and your interfaces “on the fly”. Then it is also very useful when it comes to seeing what methods were invoked in the mock object by your class under test. You can also set predefined responses, when the class under test invokes your mock object, but that is another matter. Let’s make a small sample, just as we did before manually. For the TestInit, using NMock it will be like:
It works. The presenter has invoked the properties of the mock object, once as expected and set the expected values. This way we can throw away our previous tests, and can build a new presenter based on testing with dynamic mock objects.
Implementing the real view
If you read Michael Feather’s “Humble Dialog Box” article, you’ll be able to see very well how the real view should be built. The presenter sets the values into the view which are the propagated to the properties of the controls, much like:
but once .NET was released, it comes with the concept of data binding, and there are some developers that do not want to ignore it and use the “old and safe” ways as above.
How does MVP cope with data-binding?
.NET 2.0 comes with a new and much better concept for data binding then 1.0 or 1.1 did, the BindingSource. This now has the possibility to be connected to different kinds of data sources, including business objects. For our interface we create two: bsUser for User and bsUserList for the list of Users. Then for binding we can use, the designer as:
Now, we go back to our properties that are used by the presenter to “push” data into the view to be displays, and modify the code to use the binding sources as follows:
As you can also see, user actions on the view are delegated to the presenter, which is now fully in control of what behavior of out user management interface.
If we run the tests again, they are all green, all succeed. This is great, but this green is false if you think that it works with data-binding because the tests do not touch in any way the actual view. So what do we do?
A first option would be to leave it like that. But since a view for a desktop application is not exactly as “dumb” as we would like, and can quickly become a source of error, we need to add some tests.
Using a functional testing framework like NUnitForms or SharpRobo could be a solution but this can result in tests that test the same thing, and that is not exactly maintenance friendly. But wait, what if our stub is not exactly a stub but an extension of the view itself, to which we can add testing code. For this we inherit, the real view and create ExtendedUsersView. Now we want to modify the testing code in such a way, that the existing code is still reused. For this we inherit the manual test we have written, and just override the SetUp method:
If we run it, it will run the initial tests but on the actual view. It needs to be shown as data-binding to the controls is done when the controls become visible, but that is not a problem. The problem can be speed, but if you run the code you’ll be able to see that the difference is not that significant. If speed is a problem, then maybe you can run the tests that use the actual view, more rarely, as you can get quite enough feedback from the mock tests.
The process
About the process of building destop application pieces, the way I have constructed the application above, might seem wrong, as using TDD, I built the presenter, but I did not have the view yet, and that was constructed later on the exact same set of tests. In practice I wouldn't recommend this, as the first step, building the presenter without the view, using TDD might lead to a code that will need big refactorings (both presenter and tests) when the view is built. A better approach would be to construct, a two test cases, one inheriting teh other, with two setup methods, one with the mock view, and one with the actual extended view, then build a test inside the first, and build some code on it in both the presenter and the view, then add a new test and so on, until we have tested both the presenter and the view, having both tests that are fast and isolate the presenter's bahavoius and tests that also cover the view.
Conclusion
I have tried to present a solution, that can cover more of the code with unit tests, then only the presenter, as for desktop applications this can be an important issue. I have also tried to find a solution that works with data-binding, and what I have found seems ok so far, but only time and more research and tests can really tell if this was a good choise….
1. Martin Fowler - Model View Presenter
2. Michel Feathers - The humble dialog box
3. Peter Provost - TDD in .NET
4. Jeremy Miller - A simple example of "humble dialog box"
5. Ben Reichelt - Learning teh model view presenter pattern
Sunday, November 06, 2005
The problem of communication
1. Introduction
A lot of waste and rework is done because of bad communication. In fact, communication is the main factor in a project success or failure. And that does not refer only to software. Alistair Cockburn, wrote an entire book about the importance of communication and builds a methodology around improving communication: the crystal family
2. The big misunderstanding: improving means increasing quantity
The great misunderstanding: improving communication means increase quantity: more meetings, more documentation, more emails and more phone calls. This is profoundly wrong: Communication can only be improve by quality and in many cases improving quantity means increasing the communication problem and not solving it.
One of the most important principles in software is in my opinion looking back to what you did , so you can learn what was good and what was bad, and find ways to improve your activity. This is emphasized in the principles behind the agile manifesto as:
At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.
In a project we did recently we looked back with the customer and we noticed that the bad things in a project developed were mostly caused by bad communication. By bad communication I mean much time needed to get questions answered, ambiguous requirements, not completely specified parts of the system, etc. The immediate answer was that we need to improve communication. For that the answer was that more emails will be sent, more meetings will be help, more conference calls will be held, the specification document will be even larger.
The immediate problem was overcommunication: we held meetings for the sake of having meetings, without a real need, which was in my opinion a great waste of valuable time. We wrote more emails, we held more conference calls, where we discussed about the weather or other pointless things and usually the discussions were very high management level, like are you confident with the plan, with statistics, with waste of time. There were gains, but unfortunately they were shadowed by the new problems.
I realized that people , no matter where they are from, treat the problem of communication not seriously enough. They just say we will do more, when more means quantity instead of quality. But quality is not an easy matter when it comes to communication.
Can communication be improved? What is quality in communication?
What is quality in communication? In seems that Alistair Cockburn discovered a way, based on his long and great experience, to measure communication quality. He says:
Interactive, face-to-face communication is the cheapest and fastest channel for exchanging information (see 1.)
Continuing with a communication top:

Following Alistair’s advice we need to speak more in front of a whiteboard. Why in front of a whiteboard? Because sometimes, a picture is worth a 1000 words, and this applies to software very well.
Going even further, I have found that a very practical way to improve the quality of communication is visual communication. I noticed that when describing bugs and ways to reproduce then, we or our clients have trouble describing then and describing a step by step process to reproduce them. For this one of the things I did was to ask that customers and others, when reporting bugs even changes, enhancements to include screenshots.
A single screenshot can show even the context in which the bug appeared and give you a great deal of information about the user actions. Screenshots are very cheap, and communicate a lot of information. They can even be automated into the software, so whenever you have a bug, the software takes a screenshot and sends it to you by email along with the last x lines in the log.
Many times, I am just lazy and I don’t want to read. Joel (www.joelonsoftware.com) says in his book: (Users Don't Read the Manual). Well that is very true. I want to use a new technology but I am too lazy to read the help files or the documentation. But wait, a new way of improving communication, emerged: small flash movies, showing you , visually what you need. They seem to pop everywhere. Just take a look at Ruby On Rails: [link] This can be done for bugs, for help, for a lot of things. And they are easier to do and send then writing a step by step document.
3. Communication divided by direction.
If we consider ourselves and the team the center of the communication, and we consider where the source and target of communication is, we can divide communication in:
- Communication within organization, team etc
- Communication outside with other stakeholders
3.1 Communication inside the team and organization
Depending on what needs to be communicated, the agile methodologies have ways to deal with communication inside the organization. In my opinion communication inside the team can be divided into two categories: project related and team performance related.
3.1.1 Project related
The project related information must go very fast inside the team. Crystal calls this osmotic communication and it is at the very core of the methodology. It says that people working on the same project need to be able to use the best communication technique: face to face communication , with and without a whiteboard. For this the best technique is to have the entire team collocated, in the same room as much as possible , all facing each other, to be able to ask each other questions and to enable others to hear discussions etc. The team must also have a whiteboard close.
Extreme Programming goes even further, addressing the communication problem mainly with user stories written on pieces of paper and stuck to the wall, and with writing all the business code by pair programming. This means that two programmers, work together at the same computer, understanding 100% of what’s done, and not 50% as if they were doing it separately.
The techniques above and others mainly address communication when time is crucial, but there are other problems of communication within the organization, where time is not that crucial. This is best described by a situation, where you have a team developing a program for a few months, delivering it to the client. Now the client wants to continue the program, add extensions to it etc, but the team that built it is not available anymore or it is available partially. How will the new programmers that come in contact with the program understand what was required, what was done, and how it was done.
Extreme Programming comes up and says that the best way to document a computer program is the code itself and the automated tests, it has and not documents describing what was done, as these documents need to be written by someone who is costly and become obsolete very soon. In most cases, I find this approach very good, as I noticed that recently whenever I download an open source framework or look at code written in the past, the first thing I instinctually do when I want to learn how to use it, I look at the unit tests. They show me how the software can be used, and which are the limitations, in the same language I want to use it: code.
3.1.2 Team performance related
We all want to improve our skills. Many times, we don’t have the information or the time to explore it. A learning environment has been clearly specified as a way to keep programmers motivated on the long term. In fact, this is one of the 7 principles of lean software development (see 3)
It has been proven that pair programming can help a less experienced programmer that is paired with a more experienced one move very fast ahead. The same result is achieved when the team is collocated and the less experienced can hear and see at the whiteboard the more experienced doing something, being able to ask and be given answers very fast.
One great technique, described by Alistair Cockburn is information radiators. These are things you would like to be communicated to others. These can be of help both in project, as you might have the stories stuck on the wall, divided in iterations and in sections: done, in progress and not done. Whomever goes by can see which are done, which are not, very easily without the need of asking anyone about the progress. Ron Jeffries wrote a great article about how to use the walls to communicate about progress, called Big Visible Charts. (see 4)
The information radiator are usually characterized by being pieces of paper with information that are put in places that readers might find them and read them. Usually, after reading a book, in order to get the others to read it, I cut some of the paragraphs I liked most, print it on pieces of paper and put it all over the working environment: on the walls, where people take breaks and smoke cigarettes, in places they feel comfortable. Usually after sticking them on the walls I hear the others referring to them in our conversations. It is also a very good way to speak to managers, with notes stuck on the walls.
Another technique, I found very valuable, to get people to move ahead, improve fast is what I call school like meetings. I have described them in : [Self training … ]. This is mainly , an hour where we take a subject and all read it, then based on some questions we discuss it so we can make sure everyone understands it. This is done within working hours, usually at the first hour in the morning. We have read even a book, chapter by chapter in this manner. It has proven an enormously healthy practice. Let me give you an example.
We started using an ORM framework. I started using it in a project where I teamed up with another developer. I had more experience with ORMs and I showed him a few tricks. At some time, I moved to another project and he was on his own. Then a new project was started and the ORM was used, then another all by other people. After about 4 months I looked into the code of one and I was very badly surprised that is was completely misused. People even were complaining about using this ORM because it is not of any real help. I decided to go to the bottom of the problem and I noticed that the second project was started, having the first project as an example. The mistakes from the first project that my colleague did were moved to the second and taken from granted. The third even more. A lot of people were using the ORM, but the level of knowledge after 4 months was very low.
I had to do something. I immediately gathered everyone, in that afternoon, took the documentation of the ORM and we stopped work and everyone had to read the documentation. I established a set of questions, so I can discover if the technology was reasonably well understood and we started reading. To read, answer the questions it took 4 hours. It took 4 hours to get everyone to understand how this technology. Four hours of no work, a time that could be used to build software. But those for hours proved later one of the best well spent hours in our activity. By understanding the technology in 4 hour they avoided hundred of hours of misusing it and building code that was just reinvented or badly written. Countless hours of debugging were avoided by understanding the ORM and using it right, which decreased the quantity if code by up to 75% and by having a smaller code, less bugs were produced and debugging was a lot easier.
3.2 Communication outside with other stakeholders
The usual stakeholders in a software project are: the customer, the management and the programmers. The management and the programmers can be considered either inside or outside the same circle, so both techniques are applicable. One of the very effective, silent techniques of communicating with management inside is by using the big visible charts that Ron Jeffries describes. Management can be considered depending on specific contexts both inside the programming environment and outside.
Communicating outside the programming environment is divided in my opinion in 2 sections:
1. From outside the team to programmers
2. To outside by programmers
The first can be further divided between:
1. From outside at the beginning, when code is to be written according to what is communicated
2. From outside at the end or after some code is delivered, commonly known as feedback
The software industry seems to consider that the first forms of communication from outside, about what needs to be coded are the requirements document or functional specifications.
Are functional requirements a good way to tell programmers what to build?
In a project we did before, we joined another company to develop it, having developers from the two companies developing the project. With the other company not being an agile oriented company, but more like waterfall process oriented, they came to us with a big functional specification of more then 100 pages. This was later estimated by us to be included in the first 3 week iteration.
The interesting part is that usually when people see such a nicely layout with so much information about screens, user interaction , use cases, their first thought is that this is such a good document with all the information captured and put where it belonged. Everyone looks up to those that did it. It makes some people just say: now this is how things get done properly. But are they?
My first thought was, if we develop this part of the software in 3 weeks, how many weeks was the functional spec written on? I just hoped it was clear so it does not need even more time to be invested in it. Another reaction I saw in my colleagues was that because the document was so big the tended to overlook some of the content. It was too much text. What a mistake that was, because we missed some well hidden big requirements, that were missed in the estimate, but were required at the end of the iteration.
So, now the conclusion: although big functional specification documents seem very good to the untrained eye:
- They are very costly to build (how much time do you need to write 100 pages of text?),
- They might miss important aspects of the program. As Alistair already pointed out, they are not very good at communicating things. They are indirection. The writer cannot capture whatever he needs to capture and the one that reads tends to imagine the rest. Imagination is good, but not in this case because in this case is very costly. This is a problem with alternative means of capturing requirements like direct talk, stories and acceptance tests but the main difference is the amount of time needed to spot those misunderstandings.
- They tend to push the customer proxy, which is the root of all evil. The more indirection, the more misunderstandings. When the information needs several nodes to be transmitted from the ones that knows the business to the one that builds the program, important time is lost, and important precision.
- Big documents are hard to read. Someone might say it is important to capture everything there otherwise programmers would complain about not being complete, but over completing it is just as bad
- What if something changes? What if at the time the doc was written there was one situation and it just changed? What do you do? Throw up the part or the entire document? If you wrote it in 1 month, and it cost you x, you have just lost a 10-20-30-...100% of x and need to pay again for the new one.
My belief is that big functional documents are written to replace trust between the parties involved. We need to write everything in the spec and cast it in stone, so it can't change and we can't be attacked by the customer later. My belief is that where there isn't trust, there isn't good business. Lack of trust is usually compensated with enormous overhead and cost. But after all, not everyone is to be trusted.
Although they are not evil, I am trying to show that big requirements documents are just not the answer in most projects, anymore. We need to move faster and for that the communication needs to be efficient and light. All agile methodologies say that you should have the customer (or customer representative) with you while developing. That enables the most efficient way to communicate. Direct, face to face talk, in front of the running program and in front of the whiteboard. But in order to be organized and not to replace big heavy, beaurecratic methods to communicate to chaos, we still need to have something written so we can organize, plan light. This text that is being written needs only to remind us of a thing that the customer needs implemented. It needs to be able to be written fast, so in case changes come up can be thrown away with no remorse, can be estimated and have business value. This is what is known as a user story.
In the wonderful book ‘User Stories Applied’ of Mike Cohn he defines these characteristics of a user story:
- Independent
- Negotiable
- Valuable to users or customers
- Estimable
- Small
- Testable
To demonstrate a way of improving quality vs quantity in communicating what needs to be done, agile methodologies (re)invented acceptance tests. Instead of making the customer describe what he wants you ask him: “how will I know that what I did is according to what you want?”. And he will start saying what needs to be done to be able to know if what was requested was build and finished or not. Instead of heavy descriptions, two purposes are achieved: you know how you can test and what needs to be done at the same time. Also, ambiguity tends to be dissolved by acceptance tests, because a man in order to know how to test something he must have a very intimate knowledge and understanding of that thing.
Feedback
One of the Extreme Programming values is feedback. If the customer knows how to specify how you can test that you’re done building what he requested, after delivering how can you really be sure? You need his input after seeing and testing the program.
Improvement can only be done as a result of feedback. You write a program, the customer sees it and tells you if that program is good or not. He can also tell you what would be even better to improve the program’s quality.
The virtual nature of software makes it very hard for customers to understand how it’s build and done, so it is very hard for them to communicate you what they really want. To address this extremely important problem, software should be shown very often to the customer. This has two very important benefits:
- he can see where you are, the real progress, and this increases his trust that you’re doing what you were planning to do and that his money is not wasted
- he can see if something is not what he wanted and tell you, so you can fix it or after seeing it he can start to ‘feel’ the software and be able to give you much better information about what he wants. The smaller the delivery cycles, the better.
The small delivery cycles are incredibly important in a project’s communication. They are called within agile communities, iterations and it has been proven that it is best to be between one and 4 weeks in length. As previously stated they give you one very good technique to avoid derailing the project and they embrace changing requirements.
In the past there have been projects, in which we worked for 4-6-8 months and then one day, it was the big day: the software was presented to the client. That day was one of the most stressful situations I and the other programmers could be in. It feels just like waiting in the court of law for the verdict to be pronounced. And the stress is as big as the risk is. What if the customer says that that is not what he wanted? The losses for your company’s 4 months of development are big, and redoing the software is something any business can very hardly cope with. With iterative development, showing the customer the result of the latest iteration, can mean in the worst scenario, that 2 weeks of work are useless. But 2 weeks is much easier to solve then 4 months or more. It is much easier to put one wagon on the rails again, then the whole train.
When the first requirements are being gathered from the customer, you explain him how something can be done, but it is very easy for him to imagine a completely different thing. It is also very hard for him to understand what can be and what cannot be done. What costs more or what costs less. After you deliver the first result of an iteration, he can see a computer program, and everything seems to take shape in his mind. He can use this as a basis for future requirements, and can see about how much time one thing or another takes to be implemented. The second iteration is even better and as the project progresses, the dark foggy unknown that software seemed for him in the beginning is stating to become more easy to control, more clear and he becomes less and less stressed. He starts to understand how things are done and he sees real progress. There is nothing more honest then showing the customer the real program from which he can see the progress.
If feedback is the base for all improvement, how about the internal quality of a project. What we discussed earlier about feedback is the external quality that can be improved, the part that the customer understands and helps improving, but what about internal quality. But what is internal quality in a software project?
A project in my opinion is of high internal quality if it can be tested and debugged easily and it can changed with very few effort. Being able to be changed easily assures the program a much longer life in production, which makes it more cheaper. If the customer pays $1.000.000 for a software and the software is used for 5 years, it will cost $200.000 every year. If the same software can be fixed, readapted and maintained longer in usage, for instance for 10 years, it costs $100.000 per year. Twice cheaper. Well, customers love that.
But how can you make the software give you feedback about its health? In agile methodologies the best technique for receiving feedback from the code itself about its health are automated tests. They can detect problems very early and report them to you so you can act very fast on them. I call my automated tests, break detectors. They help me by giving me fast feedback about things that broke in my software. If I can detect them fast, I can fix them fast and that allows me a great flexibility. I make a change in the software, even in code I didn’t write. Then I run the tests. If they detect a break, I know and I can choose either to reverse the change or repair the affected part. A big problem in a program’s flexibility is that if it becomes big, it is very rigid, and making a change can affect parts of it that you cannot know of. So you are afraid to change it. So the project starts to be doomed. The hardest it is to be changed, the hardest it is for it to cope with the market requirements so the shorter its life will be.
If I were to make a comparison, I would say that If I were the general and my code the army fighting the requirements, my automated tests would be my intelligence center. The bigger my army would get, and the larger the war zone, the hardest it would be for me to know what’s happening in all areas and be able to adapt my strategy to the new conditions. But If I have the break agents placed with the different parts of the army they can report to me about problems and defeat situations very fast. The more agents, the largest the areas of coverage, from where I can receive information from and act upon it.
Feedback is the one thing that corrects and improves the software.
Communicating with the outside
Before starting a project, teach your customer about the importance of good communication and how that is achieved in software and with you in particular. Show a very honest plan, of how the project will be build.
On misunderstanding with agile methodologies, is that it is believed that it is not well planned and to the uninformed this seems like cowboy programming, where everyone takes arbitrary decisions and wait to see what happens. In fact, agile software methodologies are very well planned. They plan light, having the possibility of change in their minds, making the plans simple and very easy to change. The plans are built together with the customers, management and the programmers, on very honest and proved facts, both at a high level, called release planning and at low level called iteration planning.
Projects in Extreme Programming for instance, are divided into releases, which are to be delivered to the real users, or that are going ‘live’ and usually take one to four months to develop and they are also divided into iterations that are between one and four weeks in length and which need to deliver a tested, production ready system to the customer that is in charge of developing the software.
When making the big, release plans, the customer tells the programmers about what he wants as small sentences written on small paper cards, called user stories. All these are gathered from the customer and then estimated roughly by the customer. After being estimated, the customer can see their cost, and then be able to prioritize them. After the prioritization is done, the user stories are put in the iterations, to be developed. Well, this isn’t very different from traditional planning, excepting the level of detail of the user stories. But wait, I forgot to tell you that the plans can be updated after each iteration. This gives great flexibility in what is being built, and it also gives the customer great control on how and what is being built. He is in charge. After all, if you planned to release the software after three months with the customer, and after one month he realized that he misspecified what he wanted, or the business conditions changed, he can turn the direction very easily to the new one. This gives agile project great adaptability which can deliver the customer a much better product, as it can be easily changed and the control is in his hands.
After each iteration, the customer sees the software planned and developed in that iteration, and can readapt according to what he sees. He can reprioritize, give up some features and add new ones. If the plan is light, it can be easily changed and readapted. He receives the best feedback about what you’re doing for him by seeing the software and this gives him the possibilities to tell you how to improve it, by giving you feedback.
Showing the customer, the product instead of reports, in the middle of the production, is a great way to communicate and build a product of much bigger value to the customer.
Conclusion
Although, maybe what I have said earlier might need a level of knowledge about agile technologies, I hope it can also open an interest in those that have not used them , by showing different strategies on how the problem of communication is addressed by agile methodologies. This really can improve products, customer satisfaction, can decrease costs and in all improve the way we do business.
Charging the customer for miscommunication, is the worst way to address the communication problem, however it is still extensively used. This makes software more expensive, and generates new problems and new stresses that can be pushed to programmers or customer. Just as a simple example, if it costed me x+something to build the detailed requirements documents, and the customer doesn't want to pay more then I'll just get the programmers to build the software in less time with less people. Guess how much programmers under stress cost?
1. Agile Software Development, Alistair CockBurn
2. User Interface Design for Programmers, Joel Spolsky
3. Lean Software Development: An Agile Toolkit, Mary and Tom Poppendiek
4. Big Visible Charts, Ron Jeffries
A lot of waste and rework is done because of bad communication. In fact, communication is the main factor in a project success or failure. And that does not refer only to software. Alistair Cockburn, wrote an entire book about the importance of communication and builds a methodology around improving communication: the crystal family
2. The big misunderstanding: improving means increasing quantity
The great misunderstanding: improving communication means increase quantity: more meetings, more documentation, more emails and more phone calls. This is profoundly wrong: Communication can only be improve by quality and in many cases improving quantity means increasing the communication problem and not solving it.
One of the most important principles in software is in my opinion looking back to what you did , so you can learn what was good and what was bad, and find ways to improve your activity. This is emphasized in the principles behind the agile manifesto as:
At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.
In a project we did recently we looked back with the customer and we noticed that the bad things in a project developed were mostly caused by bad communication. By bad communication I mean much time needed to get questions answered, ambiguous requirements, not completely specified parts of the system, etc. The immediate answer was that we need to improve communication. For that the answer was that more emails will be sent, more meetings will be help, more conference calls will be held, the specification document will be even larger.
The immediate problem was overcommunication: we held meetings for the sake of having meetings, without a real need, which was in my opinion a great waste of valuable time. We wrote more emails, we held more conference calls, where we discussed about the weather or other pointless things and usually the discussions were very high management level, like are you confident with the plan, with statistics, with waste of time. There were gains, but unfortunately they were shadowed by the new problems.
I realized that people , no matter where they are from, treat the problem of communication not seriously enough. They just say we will do more, when more means quantity instead of quality. But quality is not an easy matter when it comes to communication.
Can communication be improved? What is quality in communication?
What is quality in communication? In seems that Alistair Cockburn discovered a way, based on his long and great experience, to measure communication quality. He says:
Interactive, face-to-face communication is the cheapest and fastest channel for exchanging information (see 1.)
Continuing with a communication top:
Following Alistair’s advice we need to speak more in front of a whiteboard. Why in front of a whiteboard? Because sometimes, a picture is worth a 1000 words, and this applies to software very well.
Going even further, I have found that a very practical way to improve the quality of communication is visual communication. I noticed that when describing bugs and ways to reproduce then, we or our clients have trouble describing then and describing a step by step process to reproduce them. For this one of the things I did was to ask that customers and others, when reporting bugs even changes, enhancements to include screenshots.
A single screenshot can show even the context in which the bug appeared and give you a great deal of information about the user actions. Screenshots are very cheap, and communicate a lot of information. They can even be automated into the software, so whenever you have a bug, the software takes a screenshot and sends it to you by email along with the last x lines in the log.
Many times, I am just lazy and I don’t want to read. Joel (www.joelonsoftware.com) says in his book: (Users Don't Read the Manual). Well that is very true. I want to use a new technology but I am too lazy to read the help files or the documentation. But wait, a new way of improving communication, emerged: small flash movies, showing you , visually what you need. They seem to pop everywhere. Just take a look at Ruby On Rails: [link] This can be done for bugs, for help, for a lot of things. And they are easier to do and send then writing a step by step document.
3. Communication divided by direction.
If we consider ourselves and the team the center of the communication, and we consider where the source and target of communication is, we can divide communication in:
- Communication within organization, team etc
- Communication outside with other stakeholders
3.1 Communication inside the team and organization
Depending on what needs to be communicated, the agile methodologies have ways to deal with communication inside the organization. In my opinion communication inside the team can be divided into two categories: project related and team performance related.
3.1.1 Project related
The project related information must go very fast inside the team. Crystal calls this osmotic communication and it is at the very core of the methodology. It says that people working on the same project need to be able to use the best communication technique: face to face communication , with and without a whiteboard. For this the best technique is to have the entire team collocated, in the same room as much as possible , all facing each other, to be able to ask each other questions and to enable others to hear discussions etc. The team must also have a whiteboard close.
Extreme Programming goes even further, addressing the communication problem mainly with user stories written on pieces of paper and stuck to the wall, and with writing all the business code by pair programming. This means that two programmers, work together at the same computer, understanding 100% of what’s done, and not 50% as if they were doing it separately.
The techniques above and others mainly address communication when time is crucial, but there are other problems of communication within the organization, where time is not that crucial. This is best described by a situation, where you have a team developing a program for a few months, delivering it to the client. Now the client wants to continue the program, add extensions to it etc, but the team that built it is not available anymore or it is available partially. How will the new programmers that come in contact with the program understand what was required, what was done, and how it was done.
Extreme Programming comes up and says that the best way to document a computer program is the code itself and the automated tests, it has and not documents describing what was done, as these documents need to be written by someone who is costly and become obsolete very soon. In most cases, I find this approach very good, as I noticed that recently whenever I download an open source framework or look at code written in the past, the first thing I instinctually do when I want to learn how to use it, I look at the unit tests. They show me how the software can be used, and which are the limitations, in the same language I want to use it: code.
3.1.2 Team performance related
We all want to improve our skills. Many times, we don’t have the information or the time to explore it. A learning environment has been clearly specified as a way to keep programmers motivated on the long term. In fact, this is one of the 7 principles of lean software development (see 3)
It has been proven that pair programming can help a less experienced programmer that is paired with a more experienced one move very fast ahead. The same result is achieved when the team is collocated and the less experienced can hear and see at the whiteboard the more experienced doing something, being able to ask and be given answers very fast.
One great technique, described by Alistair Cockburn is information radiators. These are things you would like to be communicated to others. These can be of help both in project, as you might have the stories stuck on the wall, divided in iterations and in sections: done, in progress and not done. Whomever goes by can see which are done, which are not, very easily without the need of asking anyone about the progress. Ron Jeffries wrote a great article about how to use the walls to communicate about progress, called Big Visible Charts. (see 4)
The information radiator are usually characterized by being pieces of paper with information that are put in places that readers might find them and read them. Usually, after reading a book, in order to get the others to read it, I cut some of the paragraphs I liked most, print it on pieces of paper and put it all over the working environment: on the walls, where people take breaks and smoke cigarettes, in places they feel comfortable. Usually after sticking them on the walls I hear the others referring to them in our conversations. It is also a very good way to speak to managers, with notes stuck on the walls.
Another technique, I found very valuable, to get people to move ahead, improve fast is what I call school like meetings. I have described them in : [Self training … ]. This is mainly , an hour where we take a subject and all read it, then based on some questions we discuss it so we can make sure everyone understands it. This is done within working hours, usually at the first hour in the morning. We have read even a book, chapter by chapter in this manner. It has proven an enormously healthy practice. Let me give you an example.
We started using an ORM framework. I started using it in a project where I teamed up with another developer. I had more experience with ORMs and I showed him a few tricks. At some time, I moved to another project and he was on his own. Then a new project was started and the ORM was used, then another all by other people. After about 4 months I looked into the code of one and I was very badly surprised that is was completely misused. People even were complaining about using this ORM because it is not of any real help. I decided to go to the bottom of the problem and I noticed that the second project was started, having the first project as an example. The mistakes from the first project that my colleague did were moved to the second and taken from granted. The third even more. A lot of people were using the ORM, but the level of knowledge after 4 months was very low.
I had to do something. I immediately gathered everyone, in that afternoon, took the documentation of the ORM and we stopped work and everyone had to read the documentation. I established a set of questions, so I can discover if the technology was reasonably well understood and we started reading. To read, answer the questions it took 4 hours. It took 4 hours to get everyone to understand how this technology. Four hours of no work, a time that could be used to build software. But those for hours proved later one of the best well spent hours in our activity. By understanding the technology in 4 hour they avoided hundred of hours of misusing it and building code that was just reinvented or badly written. Countless hours of debugging were avoided by understanding the ORM and using it right, which decreased the quantity if code by up to 75% and by having a smaller code, less bugs were produced and debugging was a lot easier.
3.2 Communication outside with other stakeholders
The usual stakeholders in a software project are: the customer, the management and the programmers. The management and the programmers can be considered either inside or outside the same circle, so both techniques are applicable. One of the very effective, silent techniques of communicating with management inside is by using the big visible charts that Ron Jeffries describes. Management can be considered depending on specific contexts both inside the programming environment and outside.
Communicating outside the programming environment is divided in my opinion in 2 sections:
1. From outside the team to programmers
2. To outside by programmers
The first can be further divided between:
1. From outside at the beginning, when code is to be written according to what is communicated
2. From outside at the end or after some code is delivered, commonly known as feedback
The software industry seems to consider that the first forms of communication from outside, about what needs to be coded are the requirements document or functional specifications.
Are functional requirements a good way to tell programmers what to build?
In a project we did before, we joined another company to develop it, having developers from the two companies developing the project. With the other company not being an agile oriented company, but more like waterfall process oriented, they came to us with a big functional specification of more then 100 pages. This was later estimated by us to be included in the first 3 week iteration.
The interesting part is that usually when people see such a nicely layout with so much information about screens, user interaction , use cases, their first thought is that this is such a good document with all the information captured and put where it belonged. Everyone looks up to those that did it. It makes some people just say: now this is how things get done properly. But are they?
My first thought was, if we develop this part of the software in 3 weeks, how many weeks was the functional spec written on? I just hoped it was clear so it does not need even more time to be invested in it. Another reaction I saw in my colleagues was that because the document was so big the tended to overlook some of the content. It was too much text. What a mistake that was, because we missed some well hidden big requirements, that were missed in the estimate, but were required at the end of the iteration.
So, now the conclusion: although big functional specification documents seem very good to the untrained eye:
- They are very costly to build (how much time do you need to write 100 pages of text?),
- They might miss important aspects of the program. As Alistair already pointed out, they are not very good at communicating things. They are indirection. The writer cannot capture whatever he needs to capture and the one that reads tends to imagine the rest. Imagination is good, but not in this case because in this case is very costly. This is a problem with alternative means of capturing requirements like direct talk, stories and acceptance tests but the main difference is the amount of time needed to spot those misunderstandings.
- They tend to push the customer proxy, which is the root of all evil. The more indirection, the more misunderstandings. When the information needs several nodes to be transmitted from the ones that knows the business to the one that builds the program, important time is lost, and important precision.
- Big documents are hard to read. Someone might say it is important to capture everything there otherwise programmers would complain about not being complete, but over completing it is just as bad
- What if something changes? What if at the time the doc was written there was one situation and it just changed? What do you do? Throw up the part or the entire document? If you wrote it in 1 month, and it cost you x, you have just lost a 10-20-30-...100% of x and need to pay again for the new one.
My belief is that big functional documents are written to replace trust between the parties involved. We need to write everything in the spec and cast it in stone, so it can't change and we can't be attacked by the customer later. My belief is that where there isn't trust, there isn't good business. Lack of trust is usually compensated with enormous overhead and cost. But after all, not everyone is to be trusted.
Although they are not evil, I am trying to show that big requirements documents are just not the answer in most projects, anymore. We need to move faster and for that the communication needs to be efficient and light. All agile methodologies say that you should have the customer (or customer representative) with you while developing. That enables the most efficient way to communicate. Direct, face to face talk, in front of the running program and in front of the whiteboard. But in order to be organized and not to replace big heavy, beaurecratic methods to communicate to chaos, we still need to have something written so we can organize, plan light. This text that is being written needs only to remind us of a thing that the customer needs implemented. It needs to be able to be written fast, so in case changes come up can be thrown away with no remorse, can be estimated and have business value. This is what is known as a user story.
In the wonderful book ‘User Stories Applied’ of Mike Cohn he defines these characteristics of a user story:
- Independent
- Negotiable
- Valuable to users or customers
- Estimable
- Small
- Testable
To demonstrate a way of improving quality vs quantity in communicating what needs to be done, agile methodologies (re)invented acceptance tests. Instead of making the customer describe what he wants you ask him: “how will I know that what I did is according to what you want?”. And he will start saying what needs to be done to be able to know if what was requested was build and finished or not. Instead of heavy descriptions, two purposes are achieved: you know how you can test and what needs to be done at the same time. Also, ambiguity tends to be dissolved by acceptance tests, because a man in order to know how to test something he must have a very intimate knowledge and understanding of that thing.
Feedback
One of the Extreme Programming values is feedback. If the customer knows how to specify how you can test that you’re done building what he requested, after delivering how can you really be sure? You need his input after seeing and testing the program.
Improvement can only be done as a result of feedback. You write a program, the customer sees it and tells you if that program is good or not. He can also tell you what would be even better to improve the program’s quality.
The virtual nature of software makes it very hard for customers to understand how it’s build and done, so it is very hard for them to communicate you what they really want. To address this extremely important problem, software should be shown very often to the customer. This has two very important benefits:
- he can see where you are, the real progress, and this increases his trust that you’re doing what you were planning to do and that his money is not wasted
- he can see if something is not what he wanted and tell you, so you can fix it or after seeing it he can start to ‘feel’ the software and be able to give you much better information about what he wants. The smaller the delivery cycles, the better.
The small delivery cycles are incredibly important in a project’s communication. They are called within agile communities, iterations and it has been proven that it is best to be between one and 4 weeks in length. As previously stated they give you one very good technique to avoid derailing the project and they embrace changing requirements.
In the past there have been projects, in which we worked for 4-6-8 months and then one day, it was the big day: the software was presented to the client. That day was one of the most stressful situations I and the other programmers could be in. It feels just like waiting in the court of law for the verdict to be pronounced. And the stress is as big as the risk is. What if the customer says that that is not what he wanted? The losses for your company’s 4 months of development are big, and redoing the software is something any business can very hardly cope with. With iterative development, showing the customer the result of the latest iteration, can mean in the worst scenario, that 2 weeks of work are useless. But 2 weeks is much easier to solve then 4 months or more. It is much easier to put one wagon on the rails again, then the whole train.
When the first requirements are being gathered from the customer, you explain him how something can be done, but it is very easy for him to imagine a completely different thing. It is also very hard for him to understand what can be and what cannot be done. What costs more or what costs less. After you deliver the first result of an iteration, he can see a computer program, and everything seems to take shape in his mind. He can use this as a basis for future requirements, and can see about how much time one thing or another takes to be implemented. The second iteration is even better and as the project progresses, the dark foggy unknown that software seemed for him in the beginning is stating to become more easy to control, more clear and he becomes less and less stressed. He starts to understand how things are done and he sees real progress. There is nothing more honest then showing the customer the real program from which he can see the progress.
If feedback is the base for all improvement, how about the internal quality of a project. What we discussed earlier about feedback is the external quality that can be improved, the part that the customer understands and helps improving, but what about internal quality. But what is internal quality in a software project?
A project in my opinion is of high internal quality if it can be tested and debugged easily and it can changed with very few effort. Being able to be changed easily assures the program a much longer life in production, which makes it more cheaper. If the customer pays $1.000.000 for a software and the software is used for 5 years, it will cost $200.000 every year. If the same software can be fixed, readapted and maintained longer in usage, for instance for 10 years, it costs $100.000 per year. Twice cheaper. Well, customers love that.
But how can you make the software give you feedback about its health? In agile methodologies the best technique for receiving feedback from the code itself about its health are automated tests. They can detect problems very early and report them to you so you can act very fast on them. I call my automated tests, break detectors. They help me by giving me fast feedback about things that broke in my software. If I can detect them fast, I can fix them fast and that allows me a great flexibility. I make a change in the software, even in code I didn’t write. Then I run the tests. If they detect a break, I know and I can choose either to reverse the change or repair the affected part. A big problem in a program’s flexibility is that if it becomes big, it is very rigid, and making a change can affect parts of it that you cannot know of. So you are afraid to change it. So the project starts to be doomed. The hardest it is to be changed, the hardest it is for it to cope with the market requirements so the shorter its life will be.
If I were to make a comparison, I would say that If I were the general and my code the army fighting the requirements, my automated tests would be my intelligence center. The bigger my army would get, and the larger the war zone, the hardest it would be for me to know what’s happening in all areas and be able to adapt my strategy to the new conditions. But If I have the break agents placed with the different parts of the army they can report to me about problems and defeat situations very fast. The more agents, the largest the areas of coverage, from where I can receive information from and act upon it.
Feedback is the one thing that corrects and improves the software.
Communicating with the outside
Before starting a project, teach your customer about the importance of good communication and how that is achieved in software and with you in particular. Show a very honest plan, of how the project will be build.
On misunderstanding with agile methodologies, is that it is believed that it is not well planned and to the uninformed this seems like cowboy programming, where everyone takes arbitrary decisions and wait to see what happens. In fact, agile software methodologies are very well planned. They plan light, having the possibility of change in their minds, making the plans simple and very easy to change. The plans are built together with the customers, management and the programmers, on very honest and proved facts, both at a high level, called release planning and at low level called iteration planning.
Projects in Extreme Programming for instance, are divided into releases, which are to be delivered to the real users, or that are going ‘live’ and usually take one to four months to develop and they are also divided into iterations that are between one and four weeks in length and which need to deliver a tested, production ready system to the customer that is in charge of developing the software.
When making the big, release plans, the customer tells the programmers about what he wants as small sentences written on small paper cards, called user stories. All these are gathered from the customer and then estimated roughly by the customer. After being estimated, the customer can see their cost, and then be able to prioritize them. After the prioritization is done, the user stories are put in the iterations, to be developed. Well, this isn’t very different from traditional planning, excepting the level of detail of the user stories. But wait, I forgot to tell you that the plans can be updated after each iteration. This gives great flexibility in what is being built, and it also gives the customer great control on how and what is being built. He is in charge. After all, if you planned to release the software after three months with the customer, and after one month he realized that he misspecified what he wanted, or the business conditions changed, he can turn the direction very easily to the new one. This gives agile project great adaptability which can deliver the customer a much better product, as it can be easily changed and the control is in his hands.
After each iteration, the customer sees the software planned and developed in that iteration, and can readapt according to what he sees. He can reprioritize, give up some features and add new ones. If the plan is light, it can be easily changed and readapted. He receives the best feedback about what you’re doing for him by seeing the software and this gives him the possibilities to tell you how to improve it, by giving you feedback.
Showing the customer, the product instead of reports, in the middle of the production, is a great way to communicate and build a product of much bigger value to the customer.
Conclusion
Although, maybe what I have said earlier might need a level of knowledge about agile technologies, I hope it can also open an interest in those that have not used them , by showing different strategies on how the problem of communication is addressed by agile methodologies. This really can improve products, customer satisfaction, can decrease costs and in all improve the way we do business.
Charging the customer for miscommunication, is the worst way to address the communication problem, however it is still extensively used. This makes software more expensive, and generates new problems and new stresses that can be pushed to programmers or customer. Just as a simple example, if it costed me x+something to build the detailed requirements documents, and the customer doesn't want to pay more then I'll just get the programmers to build the software in less time with less people. Guess how much programmers under stress cost?
1. Agile Software Development, Alistair CockBurn
2. User Interface Design for Programmers, Joel Spolsky
3. Lean Software Development: An Agile Toolkit, Mary and Tom Poppendiek
4. Big Visible Charts, Ron Jeffries
Subscribe to:
Posts (Atom)