Core Spring Training course, day 1

Today was the first day of the Core Spring training class. So far so good. The instructor is Keith Donald, primary author of the Spring Web Flow module. He certainly seems to know the framework inside and out. Colin Sampaleanu, one of the developers who works on the core code of the framework, stopped by a couple times, but it was really Keith’s show.

The first day covered the big-picture stuff: what Spring is, how it works, what services it provides, etc. The focus was mostly on Spring’s inversion-of-control concept; Keith covered every IOC service the framework provides, with sample code to demonstrate each one. This was mostly information I’d gleaned from reading the documentation and “Spring in Action,” but he went into greater detail on several topics that I hadn’t explored in much depth before, such as using the Resource API to abstract out access to files/URLs/JAR file contents so the code doesn’t have to worry about where its resource lives.

He also went into minute detail on the Spring configuration format, including all the stuff you can do to minimize the amount of metadata you need to explicitly specify there. Applying some or all of those shortcuts makes the code appear to glue itself together by magic — nowhere do you specify that class A needs a helper object of class B, but poof, there it is the first time class A needs it. That can have downsides, of course (as one of my friends likes to say, “Anything that can be done for you can be done to you”) but used properly it makes Spring-enabled applications look much simpler and less cluttered than they have any right to be.

Many of the examples focused on code cleanliness and on Spring’s philosophy that business classes should contain as little code as possible that doesn’t actually implement business logic. So instead of something like

class Foo
{
    public int getFooCount(int fooType)
    {
       Connection conn = null;
       PreparedStatement stmt = null;
       ResultSet rs = null;
       try {
          conn = DBManager.getConnection();
          stmt = conn.prepareStatement(
             "select count(*) from foo " +
             "where foo_type_id = ?");
          stmt.setInt(1, fooType);
          rs = stmt.executeQuery();
          rs.next();
          return rs.getInt(1);
       }
       catch (SQLException e) {
          LogEvent.error(e, "Oops!");
          return 0;
       }
       finally {
          DBManager.close(conn, stmt, rs);
       }
    }
}

(21 lines of code in that method, and only 2-4 of them are about what the method is actually supposed to *do*.) A better alternative is the following method in a Spring-managed class:

class Foo
    extends org.springframework.jdbc.core.support.JdbcDaoSupport
{
    public int getFooCount(int fooType)
    {
       return jdbcTemplate.queryForInt(
          "select count(*) from foo " +
          "where foo_type_id = ?",
          new Object[] { new Integer(fooType) });
    }
}

The jdbcTemplate object is supplied by the parent abstract class; it handles getting and freeing the connection using a standard DataSource or whatever other connection pooling mechanism you’ve configured (it is trivially easy to use a custom-built one.) Exception logging is abstracted out into an AOP advice class since you probably have exactly the same “catch” logic in a zillion different places in the code; why not implement it just once and reuse it?

He also went over testing, both integration testing and using EasyMock to do mock-object-based unit testing.

Spring’s integration test support makes it easier to do end-to-end testing of use cases and verify that the right thing happened to the database at the end. Basically you subclass a Spring helper class instead of TestCase, and it will automatically wrap each test case in a transaction that gets rolled back at the end of the test. That keeps your database in a consistent state across tests and you never have to worry about cluttering your tests with cleanup code.

That made me wonder about database initialization, so I asked where that fit in. Rather than the typical DBUnit usage of each test class, and potentially each test method in each test class, populating an empty database with just the test data it needs, Keith favors using a single set of test data shared across all the integration or database-centric tests. Since Spring’s JUnit helper will roll back each test’s transaction, you don’t have to worry about different test classes polluting each other’s starting data. The advantage is that your tests run faster since they don’t have to constantly set up and tear down their test data; you also don’t have to duplicate a bunch of boilerplate configuration (test user IDs, etc.) in each test’s DBUnit configuration.

In the case of pure unit testing, where you’re using mock objects to test a class in isolation, Spring currently doesn’t really provide much useful support. But looking at the example test classes he was showing us, I came up with what I think is an interesting idea for combining Spring and JUnit and EasyMock to make mock testing more convenient. I will have a go at prototyping that, I think.

There was only one lab session today, a simple introductory problem that had us all writing a simple Spring config file to configure and wire together a small set of simple classes. Now that the basic theory is in place, days 2-4 are supposed to be much more lab-intensive. I’m looking forward to it — actually writing a bunch of Spring code with an expert right there to tell me when I’m overlooking a better use of the framework will be a great learning experience.

Critiques: Not really any of significance. I guess my top one would be that there was a little too much of a “sales pitch” feel in the first half of the day — we were all there because we think Spring is worth spending a couple thousand dollars and several days on, so I don’t think we needed further convincing. But given that most of the sales pitch was pretty substantive (”feature X of the framework is great because it means you can do Y”) it wasn’t all that bothersome.

Leave a Reply