Monday, March 27, 2006

A Dozen Ways to get the Testing Bug

I was pretty excited about this presentation. I've long toyed with the idea of Test Driven Development and Mike Clark just added fuel to the fire.

You can Grab the Presentation Here

Mike talked a lot about Test Driven Development - which involves writing tests first, before you actually write your code - as really being a design tool. In the recent WITS conference, I talked about Software Design and how to develop good design skills. I'm very tempted to add TDD as something to consider to help improve designs.

Mike freely admits that unit testing is hard to do consistently. It's something that we often try to just dive into and do after the fact. I can't tell you how often I've looked at a completed project and said "I really need to write tests for that", but I don't actually do it. When we put off writing tests until after the code is complete, we can never justify the added time. It's also much more painful to actually sit down and write tens or hundreds of tests at once. It's easier to do it as you go.

Mike also discussed the impact of not having tests. See the presentation slides for some pretty images... ok, not that pretty, but effective in getting the message across. The gist of it is that when we don't have tests, we are reluctant to change our code. Why? because we might break something. With tests in place, you can change code without fear of breaking it. You'll know immediately if you broke something because the test will fail. At that point, it's generally cheap and easy to fix (compared to pushing the code out to test).

Mike made the case that testing helps you develop code faster. The justification for this statement comes from the idea that whether we write tests or not, we still spend a lot of time testing our code. Take a minute and think about the mental checklists that you go through for your app and the manual deploys and tests that you do on every code iteration. If you're honest with yourself, you'll see that you do spend a considerable amount of time doing testing throughout the development process. Why not just write a simple test instead of adding a scenario to your mental check list?

To use Mike's words, Let the computer do the boring stuff and replace Visual code inspection with automated tests. You'll have a 1 time cost that can generally be less than an iteration of visual inspection, and you'll reap the rewards of this investment every time you touch the code!

So, Automated Testing is good and we already have a framework for it - JUnit. Note that there are similar frameworks for other languages such as PLSQLUnit for PL/SQL or JSUnit for JavaScript.

Another thing we need to do to get back some inefficient testing time is to do away with Debugger testing. Now, wait a second, I didn't say do away with Debuggers or with using the Debugger. I said do away with Debugger Testing. Many programmers use their debugger to walk through their code and visually inspect values as a matter of testing their code. "Is value A really incrementing here?" and so on. This includes System.out.println(). So Debuggers are good for Debugging... like for finding out why a given test fails, but it is not a regression testing tool. Now, repeat after me, "My Debugger is NOT a regression testing tool." Time spent manually testing the code is not recyclable or reusable. We need to move toward automated testing.

Again, look at how much time you spend visually inspecting your code or walking through your debugger to test your code. Compare that to the amount of time you would spend writing simple JUnit tests up front and you'll see how much time you can get back.

I'll try to get off the soapbox now. I think you get the idea that we can actually save time by writing automated tests. Now we'll move on to how and, more importantly, when to do it.
It's really quite simple. Write your tests first. Yep, that means before you implement a business rule or feature into the code, you should write the test.

Here's the basic formula:
  1. Write new code only if an automated test has failed

  2. Refactor to keep the code clean

  3. Repeat


If you look at this it seems odd. I can't code unless a test fails, but how can I write a test for code that doesn't if the code doesn't exist yet? We'll just have to get over the Chicken-Egg syndrome here and move on :)
When you receive a new requirement, or an enhancement request, the first thing you should do is to write a test. Now, compile your code and run the tests. Guess what? The test will fail since you haven't implemented the use case yet. Now, go and implement the use case, run the test and watch it pass. Now go clean up and refactor the code until it is clean. Run the test and watch it pass. It's simple.

Think of this as part of the design process. Mike spent quite a bit of time talking about how testing first actually helps in design. This may sound crazy at first, but I really believe he's right. The underlying idea is that as you code, you have to think about how you will test the code. This means that your tests are actually the first user of your code. Mike took us through a design / development use case of a shopping cart and showed the complex design that he came up with. The first instinct is to couple the shopping cart code with the Database. The cart saves stuff into a database as stuff is added to the cart. Then he asked "How do I test this?" Of course, his tests will be dependant on the Database and on specific data in the database. This is difficult to maintain over time. Someone will eventually change or archive your test data and your tests will suddenly fail. This also makes the test much more complex. In this scenario, you'd actually be testing your cart functionality, the JDBC layer, possibly the Application Container (for JNDI lookups) and your database. That's a bit much for a test that should only focus on the cart itself.
So, when you look at it from the testing perspective, you realize that you abstract the database stuff away into a separate class, and bury it behind an interface. Once you've done this, you can easily create a mock class to take the place of your database for the test.

In short, by looking at the problem from a testing perspective, you end up with a much more robust design:
  • Your Data Access Layer is now completely separated from your cart

  • Your Data Access Layer is abstracted behind an interface so that it can be changed as needed

  • You can test your code without having a dependency on the database

There is a great value in being able to test your code independantly of the Database or the App Container. Think about how much time you spend deploying your app to the dev tier... It adds up quickly.

Mike also mentioned the Mock Objects Framework (http://mockobjects.com) which provides mock implementations of crazy complex things such as HttpServlet (over 100 methods that you'd have to implement if you wanted to mock this yourself). This should be a valueable resource for creating mock objects for testing.

Another advantage to building tests is that you corner bugs for life. When you find a bug, you'll write a test around that bug, then you'll add code to make the test pass. Now, you'll never get hit by that bug again! You'll always catch it in your tests.

I know I've rambled on here. I hope it makes some sense. The goal of Mikes presentation was to get folks excited about Test Driven Development and to show some simple ways to get started. Do take a look at the slides for source-code examples on the shopping-cart example above.

One point to remember in all this is that some tests are better than no tests, so don't strive to be perfect, rather do something, write one test and you are better off than you were yesterday.

Now, start writing tests!

Keynote: Transforming Enterprise Java into an Enterprise Commodity

I'm not sure what I expected from the opening keynote, but the title didn't give me much to go on :)

This keynote was quickly transformed into a panel discussion on the current state of Java Enterprise Edition (JEE) and other enterprise technologies.

A couple of interesting points and polls came out of the discussion that I wanted to share, even if my notes on this session aren't the most organized.

  1. Apparently many people have stopped using J2EE in their organization. I don't remember the percentage, but it was a minority. Reasons given were that J2EE is too slow, too complex, and too much to maintain. These folks are moving to more POJO implementations and ORM Frameworks.
    I believe that these folks were talking about EJB 2.0 and all of its overhead and problems. From what I understand EJB 3.0 and JEE 5 try to address these issues. I will be interested to see how EJB 3.0 and the Java Persistence Framework actually take off.

  2. A poll was taken on Web 2.0. I believe the question was "What is Web 2.0?" I didn't write down all of the choices. They included Community, All Client, All Server, and Hype. But the result was that 50% of the conference attendees said it was all Hype. This may be a bit harsh, but I found it interesting.
    The panel explored Web 2.0 a bit further. One observation was that Web 2.0 is not necessarily AJAX. It ranges from making web services available through a real client-side app to full browser-based implementations. The panel seemed especially interested in leveraging web services from real rich desktop clients rather than the browser.

  3. Is AJAX and Web 2.0 the 80s all over again?
    Now, this one got my attention. I've always been hesitant to buy in to the hype around AJAX because I remember the pains of trying to cram everything into the browser. There are some real pain points that we have to consider when we talk about pushing everything into the browser.

    • Security

    • Now all apps are running in a browser which was designed to display HTML. As we proliferate apps, we have to worry about security issues that come up in browsers. Also, we have to worry about inter-app security as we have multiple apps running in a browser. Browsers don't really have protected memory and such application boxing that is provided by an OS
    • Stability

    • Continuing on the point about Security. A browser is not an OS. It's an application. As such, we have problems with stability, especially in tabbed browsers where one app crashing causes the entire browser to crash and all your apps are gone. Think back to the glory days of windows 3.1. Remember crashing a single app and having to reboot your entire OS? Maybe you are all too young... I feel like we are reverting to those days if we try to put everything into the browser.
      Maybe browsers will mature and become more OS like over time, but until that day, this is a real concern.


    One of the panelists made a statement that I particularly enjoyed. "Now we've ended up with chat clients in the browser and word processors in the browser - 2 things that make God cry."
    Of course, it's tempting to shove everything into a browser, because deployment is trivial. Everyone has a browser. Not everyone has a full JVM installed. And managing multiple versions of client-side software can be painful.

  4. The panel mentioned that writing AJAX apps is actually more complex than writing Desktop apps. This seems odd, because we typically think of AJAX as adding some Bling to our web pages. But imagine trying to create a word processor in AJAX. You are basically developing in JavaScript. There just aren't any good tools available for complex JavaScript development and debugging yet. I'll post more info on AJAX later when I cover the AJAX session.

  5. An audience member raised the question "Why does it still take months to develop a simple web application?"
    This led the panel to talk about the scripting frameworks such as Ruby on Rails. An informal poll was taken which revealed that while many of the conference attendees had evaluated Ruby, only 2 had actually deployed it into a production environment. - Why not?

    • Maturity - It's pretty young and is missing some key components

    • Lack of error messages - It's difficult to get good, meaningful error messages when something goes wrong

    • Inflexibility - I don't remember the specific comment here, but I presume that it's not flexible once you've written something

    • Primitive ORM


    Now I know I'll get the Ruby fans all riled up over this. Please don't shoot the messenger! These were the points that came up in the panel discussion!


Overall it was an interesting and lively discussion. I suppose my main take aways are:

  • EJB 2.0 Bad - POJO Good

  • It's probably not a good idea to go crazy with AJAX and Web 2.0 - Trying to shove everything into a browser isn't the best thing

  • Scripting frameworks are great for rapid prototyping, but need to mature before they are ready for wide scale enterprise level adoption