Marty Andrews

artful code

Tuesday, December 14, 2004

Web Services from a Spring Enabled Web-App

I spent some time recently working on an web-application using spring and webwork. (<tangent>this combination created the core of one of the cleanest architectures I've worked with</tangent>). Someone asked how easy it might be to expose some functionality as a web service, so I thought I'd give it a go.

Grabbing a copy of Apache Axis was my first step. It's documentation guided me most of the way, but the only missing bit was how to get at a spring-created bean from an axis-aware class. Here's what I did.

After putting the required libraries (axis-ant.jar, axis.jar, commons-discovery.jar, commons-loggin.jar, jaxrpc.jar, wsdl4j.jar, saaj.jar) on the classpath, I had to declare all of the appropriate axis stuff in my web.xml file.


The next step was to create a class which would be exposed as a web service by Axis:

public class TodoItemWebService {public String getTodoItemDescription(String title) {return "dummy description";}}

To get the service to run, I also had to create a file named server-config.wsdd in the WEB-INF directory of my web application. I figured out what this looked like by going through the Axis tutorial which dynamically registers a service in your app. Statically creating the file works fine though too. Here's what mine looked like:

<?xml version="1.0" encoding="UTF-8"?><deployment xmlns="" xmlns:java=""><handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/><handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/><handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/><service name="items" provider="java:RPC" style="wrapped" use="literal"><operation name="getTodoItemDescription" qname="ns1:getTodoList" returnQName="ns1:getTodoItemDescriptionResult"returnType="xsd:string" soapAction="" xmlns:ns1="" xmlns:xsd=""><parameter qname="ns1:TodoItemTitle" type="xsd:string"/></operation><parameter name="allowedMethods" value="*"/><parameter name="className" value="com.wrytradesman.todolist.web.service.TodoItemWebService"/><parameter name="wsdlTargetNamespace" value=""/></service><transport name="http"><requestFlow><handler type="URLMapper"/><handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/></requestFlow><parameter name="qs:list" value="org.apache.axis.transport.http.QSListHandler"/><parameter name="qs:wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/><parameter name="qs.list" value="org.apache.axis.transport.http.QSListHandler"/><parameter name="qs.method" value="org.apache.axis.transport.http.QSMethodHandler"/><parameter name="qs:method" value="org.apache.axis.transport.http.QSMethodHandler"/><parameter name="qs.wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/></transport><transport name="local"><responseFlow><handler type="LocalResponder"/></responseFlow></transport></deployment>

The service definition in bold is what I had to write to get the service running. All of the surrounding info is setup stuff that is just needed to configure axis. At this stage of the game, I could deploy my web application and hit a url http://localhost//services/items?wsdl to get the WSDL definition for my service. In the space of about 5 minutes, a cow-orker had used that WSDL to create a .NET based client which called the service and got my hard-coded response.

With my web service now up and running, the only remaining problem was to create a "real" implementation that used one of my spring managed objects instead of a hard-coded response. The trick here is to get a reference to the application context first. Everything from that point is easy. The simplest path to that is get a reference to the servlet from the Axis message context, then use the servlet context to get the application context from spring. Then just call your spring bean as per normal. Here's what my final code looks like:

public class TodoItemWebService {public String getTodoItemDescription(String title) {HttpServlet servlet = (HttpServlet) MessageContext.getCurrentContext().getProperty(HTTPConstants.MC_HTTP_SERVLET);ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servlet.getServletContext());Map beans = context.getBeansOfType(TodoListRepository.class, false, false);Iterator iterator = beans.values().iterator();TodoListRepository repository = (TodoListRepository);TodoItem item = repository.getTodoList().getItem(title);return item.getDescription();}}

Thats it. Pretty straight forward really. There's a few corner cases to be covered off, but vertical slice is complete. The whole exercise took less than a days effort, which included learning about how Axis hangs together.

Tuesday, October 5, 2004

PM - make me a deal

I'm a programmer by trade. Its my career of choice. As part of my job as a programmer, I work with Project Managers. Every time I work with a Project Manager, I implicitly make them a promise, and implicitly ask them to make a promise to me.

I'll try to produce code of the finest quality. I'll try to understand the drivers of the project as best I can, and I'll use that information in the best way I know how to help me make decisions about building the software. I'll give you estimates for everything you want me to, and I'll give you feedback about how I'm tracking against those estimates. I promise that I will do all of these things along with whatever else I reasonably can to do my job as a programmer to the best of my ability.

I'll do all of those things for at least as many hours as I'm contracted to do so per day. In my case thats usually 8 hours per day, which probably means you'll get between 40 and 45 hours a week out of me. I think I can sustain that pace indefinitely, which means that I promise you can count on me to give you predictable output week in, week out.

In return, I ask something of you, Project Manager. Please take the feedback I've given you and use it to compare how the project is tracking with your plan. If its not tracking exactly to plan (and I don't expect it to be), please use the information as best you can to help you update the plan.

In the case where your plan is more optimistic than the project is tracking, Project Manager, please don't react by asking me to work smarter. I've already promised you that I'm working as smart as I can. Please don't react by asking me to work harder. I go home exhausted by working as hard as I promised every day, and I feel burned out if I work harder. I don't believe you when you say it'll be easier once we catch up to your plan, and I can no longer fulfil my promise to you that I will give you reliable performance.

If, Project Manager, you have tried everything you can to change the plan before asking me to work harder, and you're willing to bear the risks that come to the project if I do, then lets talk about it. All I can ask is that you remember our deal, and fulfil your promise to try everything else first.

Friday, July 16, 2004

CI Demo Part 5 - Something to play with

I've uploaded all of the artefacts for the continuous integration demo I've been working on, and put the details for how to run it on the articles section of the site. It includes examples of the things I've been blogging about recently so you can see them used in anger.

Please have a go if you're interested and have some time to spare. I'd love to get some feedback. Oh - and thanks to Mike Williams for all your help.

Tuesday, July 13, 2004

A faster alternative to batchtest with JUnit in Ant

Want faster Ant build times? One of the most common culprits I've seen for slow builds is the use ofbatchtest under the junit task while it has fork="yes" set.

People end up in this state for a variety of reasons. The batchtest example inthe Ant docs has fork="yes" set. So does the example in the cruisecontrol docs. Perhaps they started not forking a VM, but got clashes with XML (or other)libraries, and that was the easiest fix. Whatever the reason, I've seen lots of people do it,and there is a better way.

Lets start with a typical example. Here's what your Ant test target might look like to start offwith:

<target name="test"><junit fork="yes"><classpath refid="test.classpath"/><formatter type="plain" usefile="false"/><batchtest><fileset dir="${test.classes.dir}"><include name="**/*Test.class"/><exclude name="**/acceptance/**/*Test.class"/></fileset></batchtest></junit></target>

The basic approach is to convert this Ant script which runs lots of tests into an Ant scriptthat runs only one test. Several things need to happen though. Firstly, the virtual machinestill needs to be forked, to make sure classpath issues are not re-introduced. Secondly, thetest has to become a suite so that all of the tests will still be run. Finally, some sort offilter mechanism needs to be put into the suite that matches the fileset filtering mechanismin the batchtest

The Ant script now becomes a bit simpler. The batchtest section is gone, anda single test name is in its place: com.thoughtworks.todolist.AllTests.

<target name="test"><junit fork="yes"><classpath refid="test.classpath"/><formatter type="plain" usefile="false"/><test name="com.thoughtworks.todolist.AllTests"/></junit></target>

To get the test suite to work as per batchtest, I use a utility from theJUnit Addons project. Itdynamically builds up a test suite from a directory structure with custom filters toinclude or exclude classes. My test suite looks like this:

package com.thoughtworks.todolist;import junit.framework.Test;import junitx.util.DirectorySuiteBuilder;import junitx.util.SimpleTestFilter;public class AllTests {public static Test suite() throws Exception {DirectorySuiteBuilder builder = new DirectorySuiteBuilder();builder.setFilter(new SimpleTestFilter() {public boolean include(Class clazz) {return super.include(clazz) &&!getPackageName(clazz).equals("com.thoughtworks.todolist.acceptance");}});return builder.suite("build/test/classes");}}

The use of the DirectorySuiteBuilder class replaces the batchtestcomponent of the Ant build script, and the use of the SimpleTestFilter replacesthe need for the nested fileset element.

That's all there is to it. In my simple application that so far has a grand total of 11 unittests, I managed to cut my build time from 4 seconds down to 2 seconds. Phew! Pretty quick huh?Well - maybe in my case it didn't matter so much, but I've seen this cut minutes of builds for"real" projects before. Let me know how it goes for you.

Oh yeah - as an added bonus, you now have a stand-alone JUnit test suite that will always beup to date with all of your unit tests. It has no dependancy on Ant, so you can run it by itselfinside your IDE (or whatever environment you use for JUnit tests).

Monday, July 12, 2004

Decorating Test Suites with Jetty

On previous web-based projects that I've worked on, the build script assumed that a web-container was running that it could deploy the application to for functional tests. In the continuous integration demo that I was working on recently, Mike showed me a cool technique that he had found to eliminate the dependancy.

He's beaten me to it though, and already written about how to decorate test suites with Jetty.

Thursday, July 8, 2004

Maintainability in Ant build scripts

I've worked on dozens of projects that used Ant build scripts, with team sizes ranging from just me to tens of developers. Big projects tend to have big Ant scripts, and they can be a maintenance nightmare. I've developed a structural style for scripts that I find easier to maintain and explain on larger projects.

Take the following Ant script as a typical example.

<project name="foo" basedir="." default="test"><target name="init" description="Prepare directories for build">...</target><target name="compile" depends="init" description="Compiles code">...</target><target name="test" depends="compile" description="Tests code">...</target></project>

The script has only three targets in it. All targets have a description, and two of them have a dependancy on another target. Those descriptions and dependancies are scattered throughout the file. It is possible to discover the descriptions of targets publicly available by running ant -projecthelp, and the dependancies will be seen when the script runs, but neither are easily viewable at a glance. This is especially true when your Ant script has grown to hundreds of lines and tens of targets.

Here's the same script modified to follow my different convention

<project name="foo" basedir="." default="test"><target name="-init">...</target><target name="-compile">...</target><target name="-test">...</target><!-- Private targets used only for dependancies --><target name="--init"    depends="-init"/><target name="--compile" depends="-init,-compile"/><target name="--test"    depends="--compile,-test"><!-- Public targets with description --><target name="init"    depends="--init"    description="Prepare directories for build"><target name="compile" depends="--compile" description="Compiles code"><target name="test"    depends="--test"    description="Tests code"></project>

Most of the targets in this script are now "private" targets. Basically - anything that starts with a hyphen can't be run on the command line by Ant, as it thinks you are passing a parameter to the Ant script rather than specifying a target. None of these private targets have any dependancies or descriptions.

All dependancies between targets can be seen at a glance in one section. They are again all listed on private targets, but these ones do no work other than describing dependancies.

All descriptions can be seen at a glance in one section. They are listed on public targets, and delegate to a single other private target which handles the dependancies for it.

Thats all there is to it really. The purist in me doesn't like it, because the test target really does depend on the compile target, so thats where it should be listed. My pragmatic side almost always wins though, and I've seen enough confusion in Ant scripts to adopt this pattern for all my new builds.

CI Demo Part 4 - A new start

So I've finally found a bit of spare time to do some work on that continuous integration demo again. Mike Williams has been helping me out a bit, and we've made some good progress.

The app is pretty simple - it's a To-Do list. We built it using a slightly different set of technologies than I'd originally anticipated. They were:

  • Subversion
  • Java
  • Ant
  • JUnit
  • JCoverage
  • Simian
  • Jetty
  • JWebUnit
  • Cruise Control
  • WebWork
  • Velocity

There are a few noticeable differences from my original list here. Subversion was used for simplicity of setup on Windows. I anticipate that most people will set this up on Wintel boxes, and CVS caused a bit of frustration. Webwork I started trying it just to see what it was like, and became a fan so kept using it. Velocity is in the same boat.

No FIT (or FIT-like) tests are included yet. Thats on my To-Do to-do list (pun intended). I'm also not uploading it all yet, as I need to clean a couple of bits up. I will however describe some of the key features in other blog entries.

Wednesday, June 2, 2004

Code Coverage by EMMA

I've had some pain in recent times trying to get code coverage reports working on my project. Some of it has been shared with Steve and Jon who have both been helpful, but unfortunately I could never quite get what I wanted to work.

The source of my pain comes from the complexity of my build process. I have two web applications being built, and they each use some code from a shared code base. Lets call the web-apps foo and bar, and the shared code base baz. Both foo and bar have some unit tests and some in-container tests. baz has only unit tests, but just to add a bit more complexity, we use a byte-code enhancing tool on some of its classes to help with our app.

Ok - now for me to get a test coverage report for foo as a whole, I have to get coverage results from foo's unit tests, foo's in-container tests and baz's unit tests. Then I have to merge them all together and generate a report. The same model has to be repeated with bar

When I started, there was two main Java code-coverage tools on the market - Clover and JCoverage. They both work in very similar ways. First, they enhance the byte-code of your classes. Then you run your unit tests, which causes a file with coverage information to be written to disk. Finally, you run a report tool which reads that information and generates a nice report for you.

Let the pain begin... JCoverage started out ok. It enhanced my classes by just being told where to find the class files on disk. The unit tests ran ok for foo and baz, as did the in-container tests. But the merge blew up. I dunno why, but it did.

Next stop is Clover. I didn't get very far at all this time. Clover enhances class files in your Ant build by hooking into the compile task and making changes as the byte code is originally created. The problem is, our own byte-code enhancing tool gets confused when it looks at Clover-enhanced classes. So I was stuck before I even began.

We had planned some time just this week to try to resolve some of these problems, but before we began I stumbled across a reference to EMMA. Its only just been released, but is making some strong claims about competing with Clover in its descriptions. The documentation looked fairly complete, so I gave it a go.

Everything just works. Fantastic! The byte-code enhancing is similar to JCoverage (just point it at your classes). The merge tool had no problems dealing with results from three different runs, and in fact I don't even need to use it. The report target can deal with multiple input files. Merging is really just for compressing results into a single file. The report is not as sexy as JCoverage or Clover, but I only really needed the numbers anyway.

So next time you're looking for some coverage results, give EMMA a go. It oozed goodness for me...

Tuesday, May 25, 2004

Angry Fruit Salad

Intellij IDEA's default color scheme is ok, but I've never been a fan of white backgrounds for code editors. I find the glare to be too bright after a whole day cutting code. Instead, I prefer a deep blue background with light colors for text and keywords.

A friend from work came up with a scheme similar to the style I like (he has a black background though). Jon Eaves coined the term "Angry Fruit Salad" for its look. I like it so much I felt compelled to share it with you.

Java code looks a bit like this:

XML looks a bit like this:

Like it? If you want to use it, feel free to download Angry Fruit Salad. Just drop it into the "colors" directory under you IntelliJ IDEA installation and you're away...

Saturday, May 22, 2004

Unconsciously Competent Pair Programming

On a recent trip to London, I spent some time chatting to Dan North about Neuro-Linguistic Programming. As context for the discussion, Dan described the four states of the conscious competence learning model. Those states were:

  • Unconscious Incompetence
  • Conscious Incompetence
  • Conscious Competence
  • Unconscious Competence

The idea behind this is that to learn and master a new skill you will go through these stages until you achieve Unconsious Competence and therefore perform it instinctively.

In another unrelated (or at least I thought so at first) discussion whilst working on my current project, I had a chat with some colleagues about how we could improve the pairing programming skills of our team. We spent some time coming up with some patterns that we would like to see occur during pairing sessions on our project. Some come from the pair programming book by Laurie Williams, and others are things that we have come up with from our experience.

Here's a summarised list (I'm probably not doing this justice, as I'm not going to explaing what they all mean - thats fodder for another blog) of the things we came up with:

  • Keyboard shuffle
  • Take a break
  • What's yours is mine
  • Humble pie
  • Partner swap
  • Confident idea <--> Hear someone out
  • Talk <--> Listen
  • Compromise <--> Stand firm
  • IDE Standard

So now that we had a bunch of stuff we wanted to teach the team, we had to figure out how we were going to do it. This was the point where I linked in the stuff that Dan had talked about, and we decided we needed to go through the conscious phases described above. In other words, a couple of us will try to coach the team by example, and we will verbalise (and therefore bring into people conscious thought) the patterns as we do them.

"I've been typing for a while now, so lets do a Keyboard shuflle so you can have a go"

Will it work? Dunno yet. We're giving it a go. Stay tuned...

Monday, May 17, 2004

New routine. New blog.

Forgive me father for I have sinned. Its been just over two months since my last blog entry...

So in that time, I've basically uprooted my life to some extent (hence the lack of blogging). I've made the move from Sydney back to Melbourne (woot!). My time has been spent packing, moving and unpacking at the other end. I'm still commuting to Sydney for work every week, but that will end soon.

The major problem for my blogging habit during that time is that:

  • a) I haven't had broadband internet access during that time.
  • b) My routine has been completely broken.

Anyway - I'm back! I haven't solved either of those problems completely yet, but most of the moving pain is over, so I'm hoping to get back on the horse.

Sunday, March 7, 2004

I've had registered for a while now, and given that my last two blogs were about BVC's, I decided I might take the time to set it up. Now I'm on the search for more content.

If you've got a BVC that you use on your project, and you can send it to me without breaching any confidentiality of your project, I'd love to put it up on the site. All you need to do is email me a picture of your chart with a description. I'll put it up on the site with your name so we can all share in each others BVC wisdom.

Saturday, March 6, 2004

BVC - Who have you paired with?

At one of our regular retrospectives a few iterations back, the team decided that we had a bad habit of not rotating our pairs enough. More specifically, we tended to pair with the same few people for all of our tasks. That meant we could improve the sharing our knowledge to other team member.

Perryn Fowler was charged with trying to rectify the situation, and he drew this chart up on a whiteboard shortly afterwards:

The idea here is that you put a mark in the square that intersects your initials and your pairs. We didn't enforce any rules other than that. Instead, we just let people come to the realisation that they were filling in some squares a lot, and others not so much.

Monday, March 1, 2004

BVC - Iteration plan whiteboard

I'm a fan of Big Visible Charts. Ron Jeffries recently reminded me that I've been meaning to blog for a while about one I use to help manage my iterations. Its the whiteboard that I use to draw up the iteration plan and track progression through stories. Here's what it looks like:

I've removed the story names to protect the innocent, but you can see a few things at a quick glance.

  • Each story card has a name and number.
  • People have signed up for stories to work on them.
  • Relative sizes of stories are immediately obvious.
  • Total size of the iteration can be seen (in this case we scheduled 44 points worth).
  • Progress on stories can be seen by the shaded areas.
  • The current status of our FIT tests can be seen.

This is enormously interesting to anyone involved with the team when they go past. Issues are sometimes noted on the board (see the "stalled" note). Anyone interested in a particular story can tell if it is done or not. I can get an early indication if we are not going to complete all the cards, or if we need to schedule more. All in all, this is the most widely and actively used tracking tool on the project.

Saturday, February 21, 2004

Blatant company promotion

The ad below ran last week in the IT section of Tuesday's "The Australian". I don't know if its socially acceptable to place occasional ads for your company in a blog, but I'm doing it anyway...

As a place to work, ThoughtWorks pretty much rocks. The people are top notch, our projects are technically really interesting, and we get to do agile development (which I reckon is just bloody great).

Come join us. You'll be glad you did.

Thoughtworks Ad

Tuesday, February 17, 2004

CI Demo Part 3 - Maven Build

At the Sydney Geek Night this week, I spent spent some time with Mike Cannon-Brookes putting a Maven build on my template application. Ok, I just sat back and watched while Mike did his thing, but in any case, I learned a bit about Maven.

The biggest eye-opener for me was the slashing and burning Mike did on the default script. The conversation kind of went like this:

Mike: "Ok, so lets grab this sample script off the documentation as a starting point. This section here is pointless, so we'll get rid of that. You don't need this bit here either. We'll throw away this crap as well..."

Me: "Whats the deal with all these reports here?"

Mike: "Oh yeah - most of those are irrelevant, so we'll get rid of these ones"

Within a few minutes, we had a working build up. It took a while to run the first few goals, because it downloaded a bunch of jars get started. Once it was done though, it did almost the same thing as my Ant build but with much less time spent on development.

Some instinctive reactions to my first Maven build:

  • My Maven build file is about 30 lines long versus about 130 lines for my Ant build file. Nice...
  • When I look at my Maven build file, I can't tell what things I can run on my build. Not so nice...
  • My Ant build uses a patched jcoverage.jar file. So far it seems like it might take more moving parts to get Maven to do that.
  • My Ant build takes about 7 seconds. My Maven build takes about 15 seconds (but that includes site generation).

I like the setup enough to keep looking into it, but I'm no convert yet...

Sunday, February 15, 2004

CI Demo Part 2 - Template Application

I've started down the road to building my continuous integration demo by setting up a template application with some of the basic tools listed previously.

There's no real code to speak of yet, just a HelloWorld class and an associated test, but most of the surrounding tools are set up in a directory structure that I like. You can download the application template if you like to see how it works. Its about 2MB in size, as the tools for all jars are included. You'll need Ant 1.6 to build it.

There's a couple of interesting things about the build which I don't see all of the time. Firstly, I separate the application source and test code. Not so dramatic, but I don't see everyone do it. I also compile each source tree to their own classes directory, which enables application source to later be bundled into the distribution without tests. The technique is also a sanity check that application source does not depend on test source.

This was my first attempt at using Ant 1.6, and I've had a go at creating some macros for compilation and testing respectively. So far I like it. My build file is certainly cleaner for the effort.

The remaining tools were simian, checkstyle and jcoverage. I haven't done anything too fancy with them, and I haven't completely tweaked the checkstyle config to my liking yet. In any case - they're in and working. The version of JCoverage includes the patch for simple bean-like properties produced by Jon Eaves.

Thats it so far. My next step is to expand it to be a simple web-app with a FIT test. Then I'll wrap cruise control around it and start building actual features ;)

Saturday, February 14, 2004

Demonstrating continuous integration

I'm currently working together with Jason Yip to collect all of the information we can about Continuous Integration. I figured it would be nice to demonstrate some of our knowledge about continuous integration techniques with a practical application.

The plan is pretty simple really. I'll build a simple web app and continuously integrate it. Some of the tools I intend to use are:

  • CVS
  • Java
  • Ant
  • JUnit
  • JCoverage
  • Simian
  • Tomcat
  • JWebUnit
  • FIT
  • FatCow
  • Cruise Control

I chose these tools for a couple of reasons. Firstly, they represent a failry typical Java-based web application. Secondly, they're all free. Anyone can get these tools at no cost and build their own continuously integrated app.

Ok - now that I've published my plans to the world, I'd better quit procrastinating and get stuck into it...

Monday, February 2, 2004

My CSS adventure

I spent some time on the weekend learning about cascading style sheets and applying my new skills to my own website. The look is not that different, but lots of stuff has changed.The most dramatic change on the site was the banner and navigation. My original version had about 75 lines of HTML code. This included a couple of tables with lots of rows, background colour manipulation and some text style changes as well. Yhe new version is about 15 lines of HTML code with no tables, colours or style definition (everything is now in the stylesheet). Check out the listamatic for some other ideas on navigation menus with CSS.Coming second in terms of major change was the menu items on the right-hand side of the blog. They use to all be tables as well, but now each section is just text wrapped in a div tag to get the effect.The rest of the stuff was mainly making sure I was using "natural" HTML code (ie. paragraphs and headings etc). Then styles were just declared for those elements.I like the result. It seems visually more structured to me with much less code. I changed the whole site (except the wiki) in about a day, and it seems much more maintainable to me too.

Sunday, January 25, 2004

The grass is greener.

I just changed from using Greymatter to using Movable Type for my blog engine. Why? Mainly because my friend Jon raved about some features he was using that I didn't have. I'm looking forward to being able to edit blog entries offline and receiving trackback pings. If anyone bothers to read my stuff that is...

Do animated gif's suck?

A client I'm working for recently asked for some basic animation on a web page as an indication of activity. One of the developers on the team created an animated gif of a barber-pole for him. I groaned inwardly when I found out, but then went home to try it myself...I'm the first to admit that I'm not very good when it comes to creating graphics, and this was no exception. The resulting image is the anagram animation at the top of the page. To build it, I created each of the frames in powerpoint and saved the slide pack as a series of gif images. Then I imported each of them into a gif animation tool frame by frame and set the timing on each. I had to tweak the image size down quite a bit, and finally I crunched it to get the file size as small as I could.I like the result, but I'm not sure that I like putting it on my web-site. Does it suck? I'm reminded of an IBM ad that ran in Australia where developers argue about using a spinning logo or a flaming logo. The business representative suggests that they could instead actually build some functionality like automation of supply-chain ordering. Confusion kicks in quickly.What do you think? It's only on the blog section of my site so far. If popular demand agrees that its sucky, I'll move it off to a far corner where people interested in those things can find it.

Saturday, January 10, 2004

mock objects rock! Mock Objects suck!

Developers using Mock Objects aren't getting better designed code. They're following the trend of the community to use Mock Object projects without understanding the mock philosophy (sic). Using mock objects is a design technique, but Mock Objects only provide a testing technique. If people use mock objects instead of Mock Objects, their designs will improve.In case you haven't noticed yet, I think there's two things here that need to be considered separately - "Mock Objects" and "mock objects"."Mock Objects" (with capitals) are tools that try to automagically fake API's of 3rd party libraries which get used in Java programs. They are used as a *testing* technique. I think they are bad."mock objects" (without capitals) are just a way for developers to stub implementations of parts of their own code (not 3rd party libraries). Developers write the mocks themselves rather than having it generated. They are used as a *design* technique. I think they are good.The reason I like "mock objects" is that you use them in conjunction with TDD to drive the design of your code. The code getting mocked is at least one layer in from the 3rd party libraries, so you end up with better abstractions in your code and a much cleaner design.The reason I don't like "Mock Objects", is that you end up with complex mock behaviour (mainly because of complex 3rd party API's). It's also easy to get a bit lazy because your design is not being driven anymore.