I know I’m in trouble when the developers all start explaining how they skipped out of a two day training session after the lunch break on the first day. Once again they volunteered to attend a training session that was a lot more “death by powerpoint” then a true training session.
I often refer to these kind of situations as random training. It’s such a common anti-pattern that when you see these developers in vendor classes they explain in their introduction to the class that they’re not sure why they’re here since they’ve coded Oracle Forms all their life and they’ve never coded in Java before. What’s happened is their manager probably had one of the following thoughts:
- There’s a training plan in my employee’s goals for this year so this will let me check off that box.
- We had training credits we need to burn.
- I heard Oracle is moving to Java and so our DBAs need to get up to speed.
- We have a pilot java project starting in 6 months, so I’ll send Sue to get her ready now.
- We brought in a custom course on site and we need to pack it with any IT employees to fill up the class and really get our money’s worth.
- After a week of classroom training our junior developers will be ready to leap into cutting edge development on our new technology.
- I know Sue wanted to go to an industry conference, but that costs travel money and this class was local and on a big discount.
My personal philosophy is management should try to provide at least a week of classroom training or a week at a high end conference per year. That and buy stacks of technical books for anyone willing to train up on a new area.
General details about JUnit 4 are starting to leak out and you can find more of the discussion at Cedric Beust’s blog. He’s one of the people behind TestNG which is an alternative java based unit testing framework that built on perceived problems in JUnit including things like the brittleness of having to build suites and adds supports for annotations.
While I applaud the TestNG folks and others for enhancing unit testing in Java, I never considered for long switching to TestNG despite looking into it a few months back. There is the notion of momentum and JUnit has tremendous momentum including books, heavy tool support, and mindshare. TestNG has support for Eclipse and being an IntelliJ user this just doesn’t do me a lot of good. I also have to learn a new way to doing thinks, new ant tasks, and there’s no good books to point to. So that means every developer I expose this to I’ll have to train up or expect them to spend time digesting the tool. There cost of switching is just too great. And the cost of waiting to see which wins out in the open source market place is just a lot easier.
I’m looking at pretty much the same situation with Subversion versus CVS, but there I expect to be able to migrate to Subversion within 12 months. Subversion from what little research I’ve done just builds on CVS. So when the tool support comes in I’ll take the time to spin everyone up on Subversion. And if I’m wrong CVS is still really workable in an environment where are largest project has 6 developers on it.
As one trying to implement TDD or at least rigorous unit testing in a real world web development shop I am constantly confronted with the issue of how to unit test our Struts applications.
I’ve built a fair number of Struts applications myself over the past few years. I started down the Struts MVC path because I don’t like reinventing my own frameworks and it was 2002, the first Struts books were appearing and it was already becoming the default way to write new Java applications. It certainly felt a whole lot better than banging out a JSP front end hooked to servlets that did raw JDBC to the database.
I remember diving through the Programming Jakarta Struts book from O’Reilly, trying to understand the theoretical underpinnings and just best how to implement the framework. I remember reading in the books relatively simple examples how one should create their own model layer and that Struts didn’t really provide one. My compatriots at the professional services firm I worked for at the time nicknamed me ‘The Professor’ for my academic need to understand the theory behind these frameworks. I thought the basic idea was wonderful, but when the rubber met the road as usual we ran into issues. Eventually the design evolved into your now traditional Struts app with Actions, FormBeans, Value Objects like Person, and Services which were really thin DAOs. It met the requirements for the client which is the final evaluation for any project so despite a lack of any real unit tests beyond the Service layer that were dependent on the database it really didn’t have much in the way of unit tests.
So your options when you start to really examine them are something like:
- HttpUnit or derivatives like JWebUnit
- Give up and just test the business logic
I’ve gone through all of these and they lead me to a similar conclusion.
StrutsTestCase is a pretty reasonable mock framework for testing Struts applications and faking the Response, Request, ActionMapping, and ActionForm objects for every execute method. That said I’ve had a lot of issues just getting it setup in many cases, but that may be from unfamiliarity. Anyway it does a fairly decent job of letting you setup and test Struts actions where many times the business logic is embedded.
HttpUnit or more friendly derivatives like JWebUnit allow you to test the ever so hard to test JSPs that are generally put together with Tiles in a Struts project meaning they’re hard to test any other way. While this can be very valuable testing it really isn’t unit testing, it’s functional testing or acceptance testing and it’s dependent on the container being up and running to do the tests. On top of that the feedback loop is longer because HTTP even to and from a localhost instance just takes some time. In the end they can be very valuable tests, but they’re really something you want your automated build tool like CruiseControl to run with every build, not something you’re going to run a lot in the midst of coding.
Cactus allows you to run the tests inside the container by literally firing it up. I’ve had a few experiences getting Cactus actually running in the container and my general rule has been its not worth the effort. You can of course run StrutsTestCase this way as well, but I much prefer the MockStrutsTestCase approach since with unit testing I’m trying to take out my dependencies and test small sections of code, typically individual methods. Again it’s just not that satisfying to use Cactus to setup tests and the feedback cycle is quite a bit slower.
Then you can always give up and just unit test the business logic. It sounds good, but then it generally turns out a lot of the business logic is in the Actions and really the only other logic is in the DAOs. So you can unit test the DAOs, but then your dependent on the database again even if your using something like DbUnit for setting up and tearing down records for the tests.
OK, so there’s solutions for all of these you’re saying if you’re a relatively sophisticated java developer. I think that’s right. Really there should be almost no business logic in your actions at all, that should all be handled by a service or business delegate. These are just POJOs so you’re able to use JUnit to your hearts content to do real unit tests. You can pull out the database dependencies by implementing Factories to produce the DAO objects and then passing back a mock DAO implementation for testing maybe based on some system property. Then you can use StrutsTestCase to check that a ActionForm’s validate method works or an Actions execute method works. Then to complete things you write some JWebUnit tests for end to end front end tests and a suite of tests using the real DAOs so you can make sure you get the right stuff out of the database. The last two you only run with the automated build since they take longer. The other tests are true unit tests without significant dependencies so you should be able to run the whole suite in a few seconds for most projects.
Great, until the real world shows up. The truth is the vast majority of Struts apps I’ve seen write most of the business logic into the Actions. Many of the books out there pretty much show this as the way to do things from their examples, even though they mention the more sophisticated approach. To make things worse the DAOs are almost always instantiated and used in the Action’s execute method. Then top this off with the fact that a significant number of Struts projects then leave a lot of java code even in the JSPs instead of relying on JSTL or the struts tag libraries.
In my particular situation I’m mentoring up a fairly large group of developers who come from a ColdFusion, Delphi, or mainframe background so once they learn the basic Struts MVC paradigm they’re off and running. I’m still working on ways to instill unit testing, but I’m stretched thin and in an Agile world where you can’t do everything and the applications aren’t that large instilling the value of unit testing isn’t that easy especially if it involves designing their applications to be testable instead of relying on deploying the app into something like Tomcat and then manually checking the pages every few minutes. And when they go out to Google to figure something out the examples rarely mention why putting all the business logic in the Actions is probably a bad thing. After a first round of first time Struts projects I have some ideas of how I’m going to try to instill TDD even in the Struts world.
It’s a pretty simple formula:
- Run training sessions on basic JUnit functionality and how to write a test before code and the benefits.
- Trying to assign my relatively few experienced J2EE developers to each new project
- Running more specific training sessions on JWebUnit, StrutsTestCase, and how to use factories and a POJO service layer to separate the Actions from the DAOs.
- Move all of our projects into running CruiseControl with a target that invokes JCoverage or Clover and fails if we don’t achieve at least 50% test coverage of the codebase. I’m pretty sure I’ll have to adjust things here, since some code like JavaBeans are hardly worth testing.
- Evaluate and adjust
I’m just hoping that 6 months from now that we’re starting to roll out our first TDD projects, have to see how it goes.
I’ve spent the last couple days in between meetings and fighting fires trying to review two Struts projects my teams are working on. I keep trying to add tests only to find that it’s much harder to add any sort of meaningful test than it should be. These are not big applications and they’re being done by developers on learning curves who aren’t too OO familiar so the bulk of the code and logic is in JSPs or Struts Actions. Unfortunately that means they’re immediatly hard to test. So far these are the things I keep running into:
- The easiest tests are functional end-to-end tests using something like JWebUnit, but brittle and they take too long to run to do more than a few.
- StutsTestCase just doesn’t provide to much besides firing off an action from the mapping file and seeing if it creates the expected results. Generally it just feels to trivial.
- JSPs are just a pain to parse and have to be rendered anyway especially since tiles and the like are in use. And generally what does parsing a JSP really tell you. You end up in the GuruTestsCode pattern real fast.
- You can write tests around the DAO layer, but generally you’re just testing against the live database, again too slow.
- There are always some validation Utility classes, that at least are easily testable
I’m going to circle the wagons tomorrow and bang some ideas off my top developers, but I’m beginning to think without rethinking the design for testability that unit tests don’t work to well in this environment.
Managing techies, geeks, rocket scientists, and software engineers is hard work and more of an art than a science. Still given the current techie focus on <a href=http://www.awprofessional.com/series/series.asp?st=44117>patterns</a> or more importantly <a href=http://c2.com/cgi/wiki?AntiPatternsCatalog>anti-patterns</a> I’m prepared to share my delicately researched opinions on the anti-patterns of technical management. And I’m willing to ignore that fact that the bulk of my management experience is with techies and not other segments of society or the fact that I went to a die hard engineering school where I was informed more than once, “It’s not a UNIVERSITY, it’s an Institute of Technology.” My experience is universal darn it.
Over the next few months I plan to examine the many anti-patterns of technical management, many of which I’ve been guilty of invoking. I’ll look at anti-patterns from “Coding Manager” to “Business Requirements are for Business Analysts”.
For those of you who’ve been following my personal cancer battle, I’ve labeled myself a survivor again as I’m completely cured at this point. Thus I’m back to ranting about techie topics instead of how oncology doctors have trouble dealing in percentages when explaining your long term survival rates.