Saturday, May 31, 2008

The making of JCiP; avoiding errors in code listings

At JavaOne this month, my publisher at Pearson, Greg Doench, hosted a panel/BOF entitled "Writing the Next Great Java Book." Not surprisingly, when you get four authors in a room, you get seven opinions about what's important in writing a book!

One thing that we (mostly Tim, actually) did for JCiP was set up an infrastructure for the book, similar to what you'd do for a software project. Version control, issue tracking, one-step build script, continuous build -- all of these things offer the same benefits to book projects as they do for software.

One critical aspect of the build is the handling of program listings. It is incredibly tempting to cut and paste examples from the IDE into whatever source format you're writing in (Word, Frame, LaTeX, DocBook), but this is a recipe for disaster -- errors will invariably creep in as you try and make small tweaks (such as changing variable names) outside the IDE. And code examples with errors really undermine the reader's confidence (or worse, they copy the incorrect example into their code.) So, we wanted to make sure that every code example compiled (and ideally, was tested.)

Our approach was to check the code into Subversion with the rest of the book artifacts, ensure that the build process compiled the code and ran the unit tests, and then automatically extract the examples from the code in a format into which they could be directly included by the build. Some systems (LaTeX, DocBook) make this sort of inclusion easier than others.

We marked the examples up with comments for formatting (bold, italic) and also with "snip here" comments that excluded the irrelevant portions of the code from the listings that actually went into the book. The attached perl script (phragmite.pl), written by Tim Peierls (based on an approach designed by Ken Arnold), takes as input a set of input files and produces a set of LaTeX files representing the extracted listings.

As an example, here is the Counter listing from Listing 4.1 of JCiP:
// !! Counter Simple thread-safe counter using the Java monitor pattern
// vv Counter
@ThreadSafe
public final class Counter {
/*[*/@GuardedBy("this")/*]*/ private long value = 0;
public /*[*/synchronized/*]*/ long getValue() {
return value;
}
public /*[*/synchronized/*]*/ long increment() {
if (value == Long.MAX_VALUE)
throw new IllegalStateException("counter overflow");
return ++value;
}
}
// ^^ Counter

The first line identifies the type of the code fragment (!! for a "good example", ?? for a "bad example" which would get decorated with a Mr. Yuk), the name of the fragment (Counter), and the listing caption. The lines with the ^^ and vv mean "snip from here to here", and a listing can be made of multiple such fragments. The /*[*/ and /*]*/ comments mean "bold". The following ANT target ran the script:
  <target name="listings">
<exec dir="${bin.dir}" executable="perl">
<arg value="${phragmite.pl}"/>
<arg value="${listings.dir}"/>
<arg value="${fragments.dir}/*.java"/>
<arg value="${fragments.dir}/jcip/*.java"/>
</exec>
</target>

In the book's LaTeX source, we use the following LaTeX macro to pull the listing in:

\newcommand{\JavaListing}[1]{\input{listings/#1}%

5 comments:

  1. I've created a tool for OpenOffice called IFCX Wings that enables code within an ODF Text document to be evaluated in place and the results automatically inserted/updated in the document. The current version supports JSR-223 and there are tested and read-to-go engines for Groovy, Ruby, Python, Scala, Java, OCaml, Haskell, and others. Support for non-Java VM languages is also planned.

    Check it out at .

    ReplyDelete
  2. That link is http://www.ifcx.org/ .

    ReplyDelete
  3. [...] than bad code examples. I mean, you’re meant to be an expert, right? Brian outlined how to avoid errors in code on his [...]

    ReplyDelete
  4. This is just what I'm looking for. I got the phragmite.pl script to run just fine through ant. Where can I find the LaTeX package that contains the definition of GoodExample, etc? Or can I write my own with some dependency on a listing package of some kind?

    ReplyDelete
  5. Yes, you can write your own. The GoodExample/BadExample are listing environments that decorate the listing with or without the Mr Yuk icon. I can try and dig up the source if you need (its not very complicated), but I don't have it handy at the moment.

    ReplyDelete