Tuesday, May 31, 2005

Memorial Weekend - A Sample of Quality of Life with XP

First of all, the criteria of the quality of life are rather subjective. If you do enjoy working on your project at home, then all I can say is that you are lucky. For me, there are so many other things besides work and software engineering that I am just too interested in to give up.

One good thing that comes with XP is that you have the control of your time. Because you always know how far you are to finish the project, your project management is fairly predictable. As a result, you can deliver the project on time, and your personal life is not affected.

So, even though my work is still busy as hell, I was still able to put it behind and enjoy my long weekend. For some person it might be really obvious, but my old buddies at JBuilder team would only know too well how obsessed I can get.

Without further a due, here it is:

Stinson Beach Hiking
This is by far the best hiking place that I have been to around bay area. The reason is simple: This is the only place that you can hike on the beach, on the grass field, and the woods in one afternoon.

Brentwood Cherry Picking
Eat all that you can pick, and buy home the ones that you cannot. Just make sure that you need to pace yourself otherwise your stomache might not be able to take it.

Ninja Gaiden
I don't understand why they want to associate this game with Dead or Alive 3, because it is totally different kind of game. Besides the normal similar quest that is quite similar to Final Fintasy X, it requires the player to analyze the enemy's attacking patterns and come up with counter measures. The last big boss was quite disappointing, though, because I just chased him around like a mad man and that killed him.

Texas Hoedown
Yes I also do not believe that there is luck in poker. But, I do believe they should put the number on those chips so that I don't have to remember them.

Monday, May 23, 2005

Joy and Pain with Fitnesse

(This blog is entered using Dvorak input, which I am going to write a blog about after I either master it or give it up)

Last Wednesday (May 18th.) I gave a presentation to the BayXP (http://groups.yahoo.com/group/bayxp/) titled "Joy and Pain with Fitness". I am putting the presentation material here, and try to explain the examples.

Joy and Pain with Fitnesse

Presentation of what we have learned during our usage with Fitnesse, an acceptance test framework, and how we have benefited from it. This presentation is intended on purpose to avoid raising philosophical issues, software engineering methodology, or what the correct usage of the Fitnesse should be. Rather, it concentrates on the retrospective of our experience with Fitnesse. It is more important to understane the reason behind

Overview
Fitness' own description can be found at its website "OneMinuteDescripiton", with the following in particular in our project:
  1. Fitnesse is an acceptance testing framework. Its targeting audience is not only the developer but also the user who is going to write and run acceptance tests, like domain experts, QA, manager, etc. (And it has done a great job to achieve this goal).
  2. Fitnesse is written in Java, which makes it easy for developer to assist the acceptance test writing.
What We Have Achieved
Just like an application product, we slowly developed a set of Fitnesse fixtures that allow everyone on the team, including the QAs and BAs, to set up the system state, simulate the events processing, and assert the end state of the system by writing XML document assertions and database assertions.

In order to document how to use the fixtures, we also created a "Fixture Tutorial" page, which contains all the fixtures that are available, with detailed descriptions. Each page is a test by itself, which means that people can change them and run them. This is very similar to the ones on Fitnesse page, e.g. JdbcSample, except ours are related directly to our domain.

How Fitnesse Works
The following is the outline of what we have learned in our project. It is quite possible that there are useful features that we have not discovered so you should make sure to check out Fitnesse website.
  1. Fixtures are loaded through reflection by very simple naming convention. For example, if the header of the table is "Insert Person Data", then the class "InsertPersonData" will be loaded and instantiated. The packages in which Fitnesse should look for the classes can be specified through "Import" fixtures.
  2. A page called "SuiteSetup" will run at the beginning of the suite and will not run for a single test. A page called "SetUp" will run at the beginning of each test all the time. The same rule applies to "SuiteTearDown" and "TearDown".
  3. The following are the four most useful features to us in this project:
    1. Column Fixture: The column name without the question mark is a public field in the fixture that Fitnesse will set value to. The column name with the question mark is a public method in the fixture that Fitnesse will call and compare to the value in the table.
    2. Row Fixture: Great for doing assertion on a set of data. For example, if you want to assert that the person has three specific phone numbers (555-2222, 555-4444, 555-9999), you just need write the Fitnesse page with these numbers and implement a row fixture that simply returns all the phone numbers this person has. Fitnesse will do a fantastic job of comparing these two sets and show you the difference.
    3. Action Fixture: The first column of each row is mapped to a public method. This is especially useful to run a sequence of actions and check the result between the actions. This fixture is being utilized by jWebFit.
    4. If you use standard fixtures, all data type conversions are handled seamlessly. As explained in "DataTypesInFixtures".
Why We Love Fitnesse
We believe that tests are good and that we as XP and Agile developers should do everything we can to encourage developers to write unittests and QA/BA to write acceptance tests. In this project, we would never have achieved this level of tests without Fitnesse. To quote from our QA:
It is great to have a tool that allows me writing tests for our system. I have been quite uncomfortable with matching logic. With these many tests and assertions (over 23,000) I am feeling a lot better now.
Because it is easy and fun to write test, many things just follow naturally. Stories are written with test in mind, making them easy to verify. Acceptance tests are also written early, sometimes even ahead of the iteration. Consider this is the team that didn't know what a story card is and didn't have any automated tests, we are really satisfied with the result.

For BA and QA, or any non-technical member of the team, Fitnesse is great because it has very clean UI with neat user interaction design. It is much less itimidating than a programming language. You just feel that you are writing a Wiki page with tables that are runnable, instead of a program with limited way of writing comments. The pages are much more readable than the JUnit tests.

For developers, there are already fixtures helping them writing unit tests. With Fitnesse written in Java and loading fixtures through simple reflections, it is quite easy to hook up the Fitnesse with the existing testing fixtures, thus greatly reduces the code duplications athe cost of the Fitnesse fixtures.

Why We Hate Fitnesse
I believe it is as important to explain the struggle we had with Fitnesse as well as the success, because this way the reader can learn to use this tool effectively. It is also possible that in the limited amount of time and with project development to bring business value as our ultimate goal, we might not have learned the way that Fitnesse was originally designed for. And I'd very much like to be directed to the right direction.

No matter how many times that I say it is very easy to write Fitnesse, you still have to spend time writing it. Also because it is not the developers who write and run the Fitnesse, you get the same issues that you have for any project. What this means is that developers are taking requirement request. It is only natural that you want to help, and the better a developer you are, the more likely you are going to put down your story and write fixture instead. Before you know it, your velocity is down and you are only overwhelmed with more and more fixture requests. There is another member of BayXP who encountered the similar problem.

The target audience of Fitnesse are the none-technical member of the team so it is doing its best job to achieve that. This achievement, however, comes with the cost of the usability for developers. A developer who has been infected by TDD is a developer who has been spoiled by JUnit. With Fitnesse we have to again and again wait patiently for the suite to finish. While waiting, we have no idea how many have been run, how many there are in total, how long it is going to take. When there is a failure, we have to wait for all the tests to finish before we can see the report. (You can copy the URL and open it in another browser window but then you have to worry about running two acceptance test processes at the same time on the same machine, which can give you some trouble sometimes.) Even with the report, you still cannot open that line of code with one click. And it is a lot harder to put breakpoint at the place that you want in debug a problem.

In the spirit of Continuous Integration, we run some of our Fitnesse tests through CruiseControl. The best way we were able to figure out is to launch the server, then use the Fitnesse runner connecting to it. With the way Fitnesse is implemented, we ended up with a server thread serving the HTML, a client thread reading it, and another thread monitor the communication between these two. Somewhere it is not managed correctly and it is causing the process to hang. We spent a lot of time trying to figure out the reason but this problem only occurs on one of the Solaris machine (which happened to be our release machine), occurs 10% of the chance on our Linux machine (which is our build machine) and never on the windows machine. The closest thing that we found online is this post about how an earlier similar bug was fixed. We moved to an Linux machine for the release and bounce build machine every now and then, and moved on.

Fitnesse also tries too hard, in my humble opinion, to be everything. Rather than a simple webapp, it is a stand alone web server. This means that you have another server to manage, another account to manage and another port to open. It also has its own Wiki engine so it is another set of rule to remember (after played with 5 different rules among Wiki, Twiki, Confluence, Rubywiki, one really gets tired.) Fitnesse dose not extend JUnit framework. The whole suite is actually run as one test, which means memory will increase as the test is running because of the HTML page.

Patterns
As we work with Fitnesse, we have developed the following patterns that helped us to use it successfully.

Just like any product feature request, every Fitnesse fixture request needs to be considered and discussed. We include them in our iteration planning meeting, we estimate them, and we pair up to implement them.

As we develop the fixtures, we write the tutorial pages first, which serves as our tests for the fixtures themselves.

Fitnesse pages are saved in their original format in TXT files. We launch the server with the correct arguments so that it does not manage the history of the pages. Then we check the files into our version control system.

For each project, we use one singleton class to manage the data that we want the fixtures to pass to each other, and make sure that all fixtures are stateless. In this way, the fixtures can stay simple and we were able to optimize the tests to make all the test run under 5 minutes.

For each project, we designated one suite as our acceptance tests area. Once a tests pass, we move it in there so that it never fails. In this way, the QA can feel free to write any tests they want and still can check in.

Always remember, it is nice and cool to do everything, but it is worth the effort only when the benefit outweighs the cost. We didn't have Fitnesse tests for a project that involve Peoplesoft because it uses views that are oracle specific. We resort to jWebUnit tests for another webapp because it was not as easy to use jWebFit (However, with the helper classes that we developed later on for web tests, we are taking another look at it to see how much it would cost now. The QAs is getting a hang of automated testing and starts feeling bad about not able to write them for Web apps).

References

Friday, May 13, 2005

ThoughtBlog

Adewale Oshineye sent me an email because there was a link from my profile page on ThoughtWorks linking to this blog, to ask me if I want to add mine to the ThoughtBlog. The reason that I have not done it is because I want to start publishing this blog only when I really know what kind of blog I am going to keep here, or even if I think it is worth it to keep a blog about my experience in ThoughtWorks.

But I figure, help is already here it really does not make sense to turn it down so I replied yes. Then I figure it is time to subscribe to the blog feed to see what my fellow ThoughtWorkers are writing about, especially with ThunderBird it is so easy.

So already I have learned something new today! I thought I have known all that is to know about writing assertions (assertEquals, assertNotEquals, assertTrue, assertFalse, simple, eh?). Boy was I wrong. Joe's blog "Flexible JUnit assertions with assertThat()" sure opened up my eye.

When I was working for JBuilder, I wrote a test framework for unit-testing some part of JBuilder modules. When a test fail, it is always desirable to see as much information as possible in the error message regarding information like project configuration, run configuration, etc. However, JUnit requires you to provide a message before the assertion happens, which means that all the tests will need to spend a lot of time constructing the messages, even though they might not be needed. So I wrote this LazyAssert that only constructs the message if the assertion fails, and ended up duplicating a lot of Assert APIs. I was quite bugged by that result but concluded that there was nothing I can do.

And now I know the right way.

My hats off to Joe for sharing it with us. And again to my fellow ThoughtWorkers.

Update of an example:

Check this out:

before:
junit.framework.AssertionFailedError
...(Click for full stack trace)...
at com.company.product.person.dao.jdbc.JDBCAffiliationDAOTest.testInsertAffiliation(JDBCAffiliationDAOTest.java:92)
...
at org.jmock.core.VerifyingTestCase.runBare(Unknown Source)
...


after:
junit.framework.AssertionFailedError:
Expected: timestamp is after 2005-05-16 15:21:34.871
but got : Mon May 16 15:21:34 PDT 2005

...(Click for full stack trace)...
at com.company.product.test.BaseAsserts.assertThat(BaseAsserts.java:31)
at com.company.product.test.BaseAsserts.assertThat(BaseAsserts.java:23)
at com.company.product.person.dao.jdbc.JDBCAffiliationDAOTest.testInsertAffiliation(JDBCAffiliationDAOTest.java:93)
...
at org.jmock.core.VerifyingTestCase.runBare(Unknown Source)
...

Sunday, May 01, 2005

Fellow ThoughtWorkers

One thing that I found different working at ThoughtWorks, are the fellow ThoughtWorkrs. Here are three examples:

Names
I am the kind of person that cannot remember people's name unless I get to know them personally. So even though I greatly enjoyed the book Patterns of Enterprise Application Architecture, I only know the name of the main author Martin Fowler. Well, after working at Yabe project, I picked it up one day again to look up a pattern. Guess how surprised for me to find out that of the people that I worked with, three are on the cover (David Rice, Edward Hieatt, Robert Mee). Even though only Dave works for ThoughtWorks, I think this still shows that this company is well connected.

Arguments
ThoughtWorkers are all opinionated and love a good argument. Someone told me this the first week that I joined, and I have seen it again and again. I think this is good because it will bring out the best from all sides so that we can always think of the way we look at things or do things. Of course, I can understand that it is not for everybody, even though I enjoyed every argument.

Humorous
Here is a good example. During a discussion about the practical use of loosely coupled architecture like web services, EJB, or CORBA, Dan North made the following comment that cracked me up:
You mean you don't use CORBA?? Are you mad??

How on earth do you instantiate an object without first looking up a Factory Factory using IIOP to register as a Listener for a Factory to call a Factory Method via reflection, if you don't have CORBA?

Bloody amateurs.