Diasparsoft Logo Let's write software that people understand.

Home | Contact

Training

JUnit support

Outsourcing

The work that Diasparsoft did for us was outstanding. We are now using the software on a daily basis and their work could well have a dramatic impact on the Reds' organization in the near future.Cincinnati Reds Baseball Club.


Publications

Tips & Tricks

Diasparsoft Toolkit

What is Diaspar?

Interesting Bits RSS

Tuesday, May 23rd

A new weblog at jbrains.info

I would like to announce a new weblog, located at jbrains.info. (I am working to fix the ugly URL.) I will not be adding more entries to this weblog, although the new one will always have a reference to the old one. (Well, for now.)

If you're subscribing by RSS, then please point your feedreader to the new feed. The icon is on our site. When we fix the URL, we'll broadcast that in another weblog entry.

Thank you to all my faithful readers. Now that I have nicer weblog software, I promise to write more.


jbrains on 05.23.06 @ 08:28 PM ET [link]


Sunday, May 21st

The World's Shortest Article on Behavior-Driven Development

Here it is.

What is Behavior-Driven Development (BDD)?

It is Test-Driven Development (TDD) practiced correctly; nothing more.


jbrains on 05.21.06 @ 12:20 PM ET [link]


Monday, May 15th

XP Project Room at TorCamp 2.0

Deb Hartmann suggested we run an XP Project Room at TorCamp 2.0 in downtown Toronto this past weekend, and we did. As usual, Deb turned the event into something far better for the visual learner, including putting up a big task board and excerpts from extremeprogramming.org's articles on XP. As usual, the codebase didn't advance too much, but one pair did try to ship a story. Unfortunately, they misunderstood the meaning of one part of their Customer Test, so I (the Customer) probably won't be able to accept it. I suppose if I'd been more available, we could have avoided the problem.

I'd like to thank everyone who involved themselves in this event, and I look forward to doing it again in Montreal as part of XP Day.


jbrains on 05.15.06 @ 07:58 AM ET [link]


Friday, May 12th

JUnit Recipes penetrates another key market

Dolce, pictured here, has rated JUnit Recipes in the top 3 most comfortable books on which to sleep and in the top 5 most fun books to swipe at. Considering that puts Recipes ahead of Refactoring (hardcover books always suffer in these categories), I'm quite satisfied.


jbrains on 05.12.06 @ 07:49 AM ET [link]


Tuesday, April 11th

Philly SPIN: April 18

Just a little announcement: I am speaking at the Philadelphia SPIN meeting, taking place in Malvern at Siemens' offices. I will be speaking about Extreme Programming and the Theory of Constraints. I've given this talk a few times, but it's never the same twice. If you will be in the area, check it out.


jbrains on 04.11.06 @ 10:10 PM ET [link]


Wednesday, April 5th

JUnit Recipes in Chinese?

I have just learned that a Chinese translation of JUnit Recipes might be in the works. The rights have been secured, and now it's a question of whether they'll go through with it and, if so, when that would be. Either way, it's exciting.

I should note that a reader contacted me directly asking for a Chinese translation, and although it took several weeks to see that request come to fruition, it is possible. If you're looking for a translation into your native language, contact me and we'll see what we can do!


jbrains on 04.05.06 @ 02:38 PM ET [link]


Monday, March 27th

XP Day and my first talk in French

I am back from XP Day France, and I must congratulate Laurent Bossavit and his supporting cast for putting on a good conference. It was 1-1/2 days of good content and a very good turnout.

I also gave my first ever talk in French, entitled "XP: My Greatest Misses, 2000-2006". I would like to thank the audience for listening, even though I'm sure it must have been painful at points. I am proud of myself, and also of Charlie Poole, for having the courage to do it in front of a paying crowd. Well done, Charlie.


jbrains on 03.27.06 @ 09:08 AM ET [link]


Monday, March 13th

An opinion of pair programming and Theory X

It's sad, but true, but opinions like this continue. It does not appear likely that they will change soon. I spotted this in a very good article on the topic of pair programming.

A classic (Theory X) manager observed a programming pair working on a design over a period of time. This manager suggested to their supervisor that one of the two programmers be laid off because only one was doing anything constructive. (The driver always gets the credit.) When the supervisor heard the suggestion, he replied that these programmers were the most productive people in the organization. The manager then asked that the programmers keep their office door closed so others would not get the same idea.

The author defines a Theory X manager, in part, as one who assumes that all workers do not enjoy their work and have no desire to learn or grow, so that provides a clue to this quote. How many Theory X managers have you worked for? Are you working for one now?


jbrains on 03.13.06 @ 10:28 PM ET [link]


Wednesday, February 1st

A public plea about debug statements

If you must debug, rather than writing tests, then please stop putting the values of variables into so-called "angle brackets". Many of us work on web applications and we'd like to read your debug statements in full.

Thanks.


jbrains on 02.01.06 @ 03:07 PM ET [link]


Monday, January 30th

Joda-Time: the killer date/time API for Java?

This looks awesome: JodaTime. I'll let you know how it goes after I've been using it.


jbrains on 01.30.06 @ 03:29 PM ET [link]


Thursday, January 19th

WARNING: NeoOffice/J is not perfect!

I saw this while downloading NeoOffice/J 1.2 beta:

Warning: all NeoOffice development and testing is done by volunteers so there are always some missing features and bugs. So if you expect software to be absolutely perfect before you install it, we recommend that you purchase a commercially supported office suite like Microsoft Office.
I offer this to you without comment.


jbrains on 01.19.06 @ 09:51 AM ET [link]


Reason 187 that Ruby rocks!

How many times have you coded Math.max(a, b), or even worse:

return a > b ? a : b;

I prefer [a, b].max. Just beautiful. Ruby's version works for an array of any size. I'm sure JDK 5.0's does, too, but just JDK 1.4's?


jbrains on 01.19.06 @ 01:57 AM ET [link]


Wednesday, January 11th

Nothin' from nothin' leaves nothin'...

If you're seen or heard Eddie Murphy's Raw, then you know what comes next.

I recently re-read the front page of Gervase Bushe's Appreciate Inquiry page. The essential premise seems to be that we can improve our environment in part by focusing on what we want more of, instead of focusing on the problems and how to fix them. There is, however, a problem I wish we could easily fix.

At Nutrimental Foods, the factory closed its doors for four days and brought together all 750 employees, the company's leadership, and 100 customers to create a new business model. A year later, profits were up over 200 percent and absenteeism dropped 300 percent. AI is now this company's annual way of planning.

Stunning! So if the company had 1000 absentee days the first year, did they have -2000 absentee days the next year?

This ranks up there with equating 3 times as much with "300% more". A little functional numeracy out there would be swell.


jbrains on 01.11.06 @ 01:31 AM ET [link]


Saturday, December 10th

I'm disappointed with FIT

I have just spent the better part of a day trying to start a small project with FIT, working in Ruby. My experience has been especially frustrating, not because my environment was bad, but because after all the work it took to fix my environment, FIT disappointed me in the end.

Just to paint the picture, I had to install XCode 2.2 so I could install readline so I could install postgresql so I could run Rails. After four hours of troubleshooting, Googling and fixing, I was ready to run tests with FIT.

I checked out the latest FIT from CVS, tried to run it, and no love. I ended up finding a defect related to a refactoring gone wrong. Didn't anyone run the tests?!

Finally, I tried to run my test page and FIT was downright rude.

Unable to parse input. Input ignored.
Can't find tag: td
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/parse.rb:97:in `initialize'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/parse.rb:102:in `new'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/parse.rb:102:in `initialize'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/parse.rb:102:in `new'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/parse.rb:102:in `initialize'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/file_runner.rb:46:in `new'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/file_runner.rb:46:in `process'
/Users/jbrains/Library/Ruby/fit/bin/../lib/fit/file_runner.rb:20:in `run'
/Users/jbrains/Library/Ruby/fit/bin/fit.rb:9

Why can't it find my table cells? Apparently because OpenOffice's HTML editor (correctly) used such tags as thead, tbody and th in my table. Prettier that way. Isn't FIT supposed to make things easier for non-programmers?.

Being a "TDD asshat" (I've always loved that since I read it for the first time in some moron's rant), I wrote an integration test that showed, indeed, that FIT wouldn't parse my "fancy" table correctly. After I had a failing integration test, I went to an object test on Parse. I was about to write the test when I read the existing tests.

I just about lost it.

    def test_parse_exception
      begin
        p = Parse.new 'leader<table><tr><th>one</th><th>two</th><th>three</th></tr><tr><td>four</td></tr></table>trailer'
        fail 'Expected ParseException not thrown.'
      rescue ParseException => e
        assert_equal 17, e.error_offset
        assert_equal "Can't find tag: td", e.message
      end
    end

Are you kidding me? FIT intentionally disallows tags like th?!

With the greatest love and respect to everyone involved, am I really the first person on this planet to write FIT test tables with an HTML editor that generates table headers?

I just don't have the energy to add support to Ruby FIT for this right now. I recognize that we're all volunteers and that I shouldn't be upset over this, but surely someone else has run into this problem. It just floors me that I might be the first.

Very disappointing. Not the way I wanted to end this programming session.


jbrains on 12.10.05 @ 10:10 PM ET [link]


Friday, December 2nd

Painting the floor

As I go through receipts to get ready for my fiscal year end, I stumble upon a receipt from December 2004. On the back of this receipt, I had scribbled some notes about my experience painting the floor in our house in Manitoba. I'd like to share those with you now.

  • We didn't attempt the project without at least minimal competence. We made sure we had a couple of people with experience painting a floor.
  • My wife and I painted as apprentices to her parents, who knew what to do.
  • We tried pouring TSP on most of the floor to remove the old paint, then paint, but found out quickly that we weren't using the TSP properly. This resulted in chaos.
  • We reset with an incremental plan: we stripped one small section of the floor, let it dry, painted it, then left for the night. This confirmed what we'd learned about stripping the floor with TSP, gave us a quick win and made the rest of the project successful.

Everything I needed to know about painting floors I learned on software projects.


jbrains on 12.02.05 @ 07:57 PM ET [link]


Wednesday, November 16th

Why I don't care about 100% code coverage

On the JUnit Yahoo! group, someone asked me:

I am on the other side of the shore and believe in Code coverage and so very interested in knowing why you feel that 100% code coverage isn't a requirement for code check in? Can you please share your thoughts?

Sure: 100% line/branch coverage is impossible to achieve. Even if it were possible, it's not worth the effort. Example:

JDBC driver throws SQLException, which is checked. In my code, I have to do this:
try {
    useJdbcDriver();
}
catch (SQLException e) {
    // What to do here?
}

Well, my default checked exception handler is this:

try {
    useJdbcDriver();
}
catch (SQLException wrapped) {
    throw new RuntimeException(
        "Something went wrong when I used the database", wrapped);
}

There are two problems with this:

  1. It takes an obscene amount of effort to simulate (or recreate) the conditions under which the JDBC driver throws an SQLException.

    The vast, vast majority of the time, I don't handle those exceptions anyway, but rather pass them up the chain. To avoid coupling myself to my caller, I turn the checked exception into an unchecked one.

  2. Java forces me to duplicate that exception handler everywhere throughout my code, although I could get a little better with
        ExceptionHandler.shush(
            "Something went wrong when I used the database", shushed);
    
    Still, I have to duplicate that everywhere, but I certainly don't need to test it everywhere I use it. The only thing that changes is the explanation message, and I never write code that depends on that text in any meaningful way.

Both of these make it unusually expensive to test-drive this code, compared to the benefit I get from test-driving it. As a result, I have judged that it's not worth the effort, so I don't do it.


jbrains on 11.16.05 @ 09:43 PM ET [link]


Tuesday, October 25th

All right... so it wasn't a FitNesse bug

Today I was writing a FitNesse test and ran into a problem I couldn't explain. This is a simplified version of the table I wrote.

com.mycompany.MyRowFixture
id date name?
762 never Doesn't so much matter

I wrapped java.util.Date in a new class FitDate that handles my keyword "never". (Here, "never" corresponds to a date far in the future, which wasn't my design choice, but it is what it is.) I implemented parse, equals and toString, ran the test, and although the system was sending back the right object (with key 762 and never), the row didn't match. I had no idea what the problem was: I had implemented custom data types in FitNesse dozens of times.

Perhaps there's a defect in FitNesse related to how RowFixture handles rows whose key include custom data types. Naturally, I had to write some tests.

First, I verified what I knew about how RowFixture works.

    public void testSimplestKey() throws Exception {
        RowFixture fixture = new RowFixture() {
            public Object[] query() throws Exception {
                return new Object[] { new PrimeData(2) };
            }

            public Class getTargetClass() {
                return PrimeData.class;
            }
        };

        Parse table = new Parse("<table>"
                + "<tr><td>The Name Doesn't Matter</td></tr>"
                + "<tr><td>prime</td></tr>" + "<tr><td>2</td></tr>"
                + "</table>");

        fixture.doTable(table);

        assertTrue("Surplus: " + fixture.surplus.toString(), fixture.surplus
                .isEmpty());
        assertTrue("Missing: " + fixture.missing.toString(), fixture.missing
                .isEmpty());
        assertEquals(new Counts(1, 0, 0, 0), fixture.counts);
    }

Since that worked, I tried the same thing with a target class whose key is a custom data type.

    public void testOnlySingleColumnKey() throws Exception {
        RowFixture fixture = new RowFixture() {
            public Object[] query() throws Exception {
                return new Object[] { SingleColumnKey.with(IntWrapper
                        .valued(762)) };
            }

            public Class getTargetClass() {
                return SingleColumnKey.class;
            }
        };

        Parse table = new Parse("<table>"
                + "<tr><td>The Name Doesn't Matter</td></tr>"
                + "<tr><td>key</td></tr>" + "<tr><td>762</td></tr>"
                + "</table>");

        fixture.doTable(table);

        assertTrue(fixture.surplus.toString(), fixture.surplus.isEmpty());
        assertTrue(fixture.missing.toString(), fixture.missing.isEmpty());
        assertEquals(new Counts(1, 0, 0, 0), fixture.counts);
    }

    static class SingleColumnKey {
        public IntWrapper key;

        public static SingleColumnKey with(IntWrapper intWrapper) {
            SingleColumnKey singleColumnKey = new SingleColumnKey();
            singleColumnKey.key = intWrapper;
            return singleColumnKey;
        }

        public boolean equals(Object other) {
            if (other instanceof SingleColumnKey) {
                SingleColumnKey that = (SingleColumnKey) other;
                return this.key.equals(that.key);
            }
            else {
                return false;
            }
        }

        public String toString() {
            return "SingleColumnKey with " + key;
        }
    }

    static class IntWrapper {
        public int value;

        public static IntWrapper valued(int value) {
            IntWrapper result = new IntWrapper();
            result.value = value;
            return result;
        }

        public static IntWrapper parse(String text) {
            return IntWrapper.valued(Integer.parseInt(text));
        }

        public boolean equals(Object other) {
            if (other instanceof IntWrapper) {
                IntWrapper that = (IntWrapper) other;
                return this.value == that.value;
            }
            else {
                return false;
            }
        }

        public String toString() {
            return String.valueOf(value);
        }
    }

This test failed! I couldn't figure it out. I'm ashamed to admit that I submitted to stepping through RowFixture with the debugger. (Hold your cards and letters; I feel bad enough.) I found out that when RowFixture computed the keys in common between the expected results (in the table) and the actual results (returned by query()), it was treating the two keys as different, even though they are equal according to equals().

Then it hit me. The defect wasn't in RowFixture... I didn't implement hashCode(). That was likely the problem. I wrote this test to verify that.

    public void testDifferenceBetweenCustomTypeWithAndWithoutHashCode()
            throws Exception {

        RowFixture fixture = new RowFixture() {
            public Object[] query() throws Exception {
                return null;
            }

            public Class getTargetClass() {
                return null;
            }

        };

        class TargetClass {
            public boolean equals(Object other) {
                return true;
            }
        }

        assertEquals(2, fixture.union(Collections.singleton(new TargetClass()),
                Collections.singleton(new TargetClass())).size());

        class TargetClassWithHashCode {
            public boolean equals(Object other) {
                return true;
            }

            public int hashCode() {
                return 0;
            }
        }

        assertEquals(1, fixture.union(
                Collections.singleton(new TargetClassWithHashCode()),
                Collections.singleton(new TargetClassWithHashCode())).size());
    }

When I implement hashCode(), equal keys are treated equally, as I'd expect. When I corrected my second test by implementing IntWrapper.hashCode() correctly, that test passed.

The lesson: when implementing a custom data type in FitNesse, take time to implement hashCode(), even if it's as stupid as return 0;. You'll spend a few seconds per custom data type to avoid re-learning this lesson however often you might need to re-learn it. I'm sure I'll forget again some time.


jbrains on 10.25.05 @ 11:04 PM ET [link]


Monday, October 24th

The Irony of Urgency

On the extremeprogramming Yahoo! group there has recently been an interesting discussion about urgency. Specifically, what does it mean to work "with a sense of urgency"? IBM touts this as a key trait of a True Blue IBMer: working with a sense of urgency. Is it really desirable? Is there something other than urgency that managers truly want that they don't consciously realize? In reviewing recent conversations with developers in their natural habitat, I have found a delicious irony about urgency.

The more urgency demanded of developers, the more time they spend complaining about the situation. In other words, the very act of demanding developers work with a sense of urgency often leads them to spend less time working (effectively or otherwise) on the project, because they need more time to commiserate with one another about how difficult work is with this overhanging demand for urgency.

Kent Beck has written that he likes to program as though he has all the time in the world. I have to admit that I have done my best work when I have been able to do that. When I spend the time to do it well (not "get it right", since that might take forever), I go faster. You can tell when someone is suffering from the myth of urgency, because he emphasizes doing it over doing it well.


jbrains on 10.24.05 @ 07:42 PM ET [link]


Sunday, September 25th

XP Day DC 2005 was a success!

I would like to thank everyone who participated in, helped to organize and supported XP Day DC 2005 on Saturday. I enjoyed meeting people from the DC-area Agile community and our co-hosts Digital Focus were tremendous. It looks like I'll be able to co-write a paper for Agile 2006 and we're definitely going to do XP Day again... perhaps in a city near you! Stay tuned to xpday.info.


jbrains on 09.25.05 @ 11:39 AM ET [link]


Saturday, September 17th

Some authors have all the luck...

Apparently I'm just unlucky lately. Yesterday, I lost a power supply and our Academy of Learning needed a motherboard and two hard disks. Now, I find out the reason you can't get copies of JUnit Recipes right now...

The book was reprinted on 9/2 but 6 of the boxes were damaged in shipping making the books unsellable. So, one of our distributors was unable to fulfill backorders. That said, a whole new shipment arrived at the distributors today so JUnit Recipes should be going out post haste.

So if you were trying to order the book, you will be able to do so soon.


jbrains on 09.17.05 @ 10:30 AM ET [link]


XP Day DC 2005

If you haven't already booked your spot for XP Day DC 2005, book now! We'll be at the offices of Digital Focus on Saturday, September 24 with special guests Bill Wake and Sanjiv Augustine.

Also, be on the lookout for XP Day North America events in 2006!


jbrains on 09.17.05 @ 09:27 AM ET [link]


Monday, September 5th

Our flood

Well, it's nothing like what's happening in the Gulf states, but we had a flood here in mid-August resulting from a rare tornado touching down in Stratford, ON; not far from Toronto. The resulting downpour gave us four inches of water throughout our basement apartment, resulting in heavy losses in books and papers. Fortunately, all equipment appears to work, with the exception of one waterlogged USB drive power supply. Today I am getting my office back in condition. Why today? I have been on the road for three weeks at a client site, so my brave wife had to go through all this alone. I thank her deeply for handling the flood itself, getting help from neighbors, beginning to clean up, calling the insurance company... all those things I know she generally strongly dislikes doing.

So if I have been unresponsive to e-mail or phone calls in the last few weeks, that's why. I apologize for that. In the coming couple of days we should be back to nominal, if not normal.


jbrains on 09.05.05 @ 02:12 PM ET [link]


Wednesday, August 31st

Scrum Training in Toronto, September 12-13

Our colleague and fellow Canadian Francois Beauregard is offering a Scrum Master course in Toronto, running September 12 and 13. I recommend this for anyone looking to learn how to run a Scrum team well. Visit here to register, or just to learn more.

PS: Francois, I apologize for removing the cedille from your name, but it was breaking RSS feed readers!


jbrains on 08.31.05 @ 01:04 PM ET [link]


Thursday, August 25th

Java: It's a sad day....

I just read this at Angelika Langer's FAQ on Generics in Java.

The Java Language Specification even states that it is possible that future versions of the Java programming language will disallow the use of raw types.

That is, "be prepared to be forced to use generic types, whether you like them or not."

Well, a friend of mine recently saw his "Quit Clock" (think "Doomsday Clock") hit 12 midnight. I think my "Quit Clock" as a Java programmer has started running.... Shame, that.


jbrains on 08.25.05 @ 09:36 PM ET [link]


Wednesday, August 10th

JUnit Recipes is being reprinted...

For those of you who've been asking about JUnit Recipes or having difficulty obtaining it, Manning has told me that they are reprinting it as we speak. I don't know when it will be ready to ship again, but look for online booksellers to start being able to ship in reasonable timeframes again.

If you really need a copy, go here and buy directly from the publisher. You can get the PDF version for USD 25.00 or both PDF and print for USD 50.00 (you can download the PDF immediately and you'll get the print copy when it's ready to ship).


jbrains on 08.10.05 @ 04:31 PM ET [link]


Friday, August 5th

Bad UI design: Canada Post

I've just registered with Canada Post's "Online Business Centre", and it was a harrowing experience, to say the least, all because of an invalid postal code.

First, I tried every format I could imagine for Canadian postal codes: R7N2V4, r7n2v4, R7N-2V4, R7N 2V4, r7n 2v4, ... every permutation of case, punctuation and spacing I thought was reasonable. None worked. Now I really need to pay this bill today, and I don't want to waste time at a bank in line (not to mention the annoying fee for paying a bill at the teller), so I called Canada Post and they told me that they had a different postal code on file. (One address is our location; one is our post office box.) Armed with better information, I hung up and tried registering again.

Well, R7N1M8 didn't work, and neither did r7n1m8 or r7n 1m8. Finally, R7N 1M8 was the winning combination. (It felt, after all, like opening a safe.) I am now registered and have the privilege of paying Canada Post their $207.

Why on Earth would a simple web form force me to get both case and spacing right on something as simple as a postal code?! Web form designers everywhere, stop doing that!


jbrains on 08.05.05 @ 01:19 PM ET [link]


Saturday, July 30th

Gordon Pask Award for Contributions to Agile Practice

I am proud to announce that Jim Shore and I were awarded the first two Gordon Pask awards for our contributions to Agile practice. I know Jim best for his tremendous background work (or so it seems -- he's not the kind of spotlight hog that I can be) in uniting the Fit community and aligning the various versions of the product. Jim is certainly the sort of person I would want to work with before I hang up my keyboard.

The Agile Alliance has recognized me for my traffic on the various Yahoo! groups (junit, testdrivendevelopment and extremeprogramming), for JUnit Recipes, for organizing XP Day North America and overseeing the tutorials at Agile 2005. I thanked the audience Thursday night, but I'd like to thank everyone in the Agile community for giving me space to try to help. I'm glad to have been of some service.

Brian Marick describes the award here.


jbrains on 07.30.05 @ 04:47 PM ET [link]


Tuesday, July 26th

Slides from Agile 2005: Intro to Test-Driven Development

You can download the slides from my Agile 2005 presentation Intro to Test-Driven Development by going to the Speaking Engagements section of this site. Thank you to all those who attended. I hope you found it useful and I'll be around to answer questions until Friday morning. After that, you can always ask questions at the various Yahoo! groups including testdrivendevelopment and junit.


jbrains on 07.26.05 @ 09:58 AM ET [link]


Second print run for _JUnit Recipes_?

If you don't yet have a copy of JUnit Recipes and are having trouble ordering it, my publisher is currently deciding whether to print more copies. If you'd like to voice your opinion, or you're looking to buy in volume (say, for a course you're teaching), try e-mailing the business manager. Thanks so much for your interest in the book!


jbrains on 07.26.05 @ 02:06 AM ET [link]


Saturday, July 23rd

See you in Denver!

I'll be at Agile 2005 this week, speaking twice and generally making sure tutorials come off without a hitch. If you're planning to attend, look out for me and say, "Hello!" Better yet, come to my tutorial Test-Driven J2EE. If you have a copy of JUnit Recipes you'd like signed, I'll be happy to do that, too.

See you then!


jbrains on 07.23.05 @ 11:56 AM ET [link]


Thursday, July 21st

Join us at XP Day DC!

XP Day DC 2005 will be held at the offices of Digital Focus in Herndon, Virginia, USA on September 24, 2005. For more information, visit this site. Register and join us today!


jbrains on 07.21.05 @ 03:32 PM ET [link]


Monday, June 6th

Article: Injecting Testability into Your Designs

Check out the Publications section for my latest article as printed in the April 2005 edition of Better Software Magazine.


jbrains on 06.06.05 @ 01:57 PM ET [link]


Monday, May 23rd

My wish is their command

I whine constantly that people should just take the great advice I give them and run their projects that way. Usually, I'm half-joking. Apparently, someone is doing just that.

It's about time!


jbrains on 05.23.05 @ 11:26 PM ET [link]