Friday, May 1, 2009

Book Review: Dreaming in Code

Dreaming in Code has been out for a few years now, and it's received glowing reviews, some of which are linked from its website. This is not one of those reviews: I ended up returning the book to the library after getting barely halfway through. I found it boring, so much so that I preferred reading about the history of paint.

DiC is often compared to Tracy Kidder's Soul of a New Machine. The latter book came out while I was in high school, and I consider it one of the influences that led me into the computer industry. Superficially, the two books are very similar: they're both histories of a high-tech project, written for a non-technical audience. Both chronicle the successes and failures of the project, both profile the people involved. And yet, SoaNM just does it better. Before writing this post, I opened my copy to a random page for insight … and read to the end of the chapter. Nearly thirty years after it was written, and with the knowledge that I've gained in that time, it still held my interest. Why? And why didn't DiC?

The answer, I think, starts in the prologue. Rosenberg writes of his own experiences programming. Kidder takes us onto a sailboat, running before a storm, and introduces us to Tom West. Every book needs a protagonist, and Tom is ours: we learn of his character, and the events of the prologue are a foreshadowing of the rest of the book. Turn to any page, and Tom West is nearby. Rosenberg, by comparison, lacks a protagonist: Mitch Kapor is a visionary on the fringes, and there are a succession of project managers and programmers who never really step up to the role. Perhaps that's why the project failed, but it doesn't make for good reading.

Not only does DiC not have a protagonist, it doesn't have a crisis. The team in SoaNM is working against a deadline, against internal competition, and against their own limitations. A conventional plotline, but it works, and it moves the book forward. By comparison, the team in DiC drifts around, throws out ideas to see if they stick, and then drifts away. I'm sure there was pain and angst in the Chandler offices, but that never makes its way to the page.

Or perhaps it does, but is diluted by the mass of explanatory material that Rosenberg injects into the book. And here we come back to a difference obvious from the prologues: Rosenberg is a part of the computer industry, even if his job has been to write about it. Kidder is a journalism professor, who likely had never used a computer before this book. Both need to present technical material in their books, and in rereading, I'm amazed at just how dense the technology is in SoaNM. But the difference is telling: Rosenberg looks at the material with an insider's eye, while Kidder is an outsider who has to learn before writing. And in so doing, he distills the content, giving enough detail for the novice, but not so much that the knowledgeable reader is bored.

After three weeks with Dreaming in Code, I gave up. The book was due back to the library, and I didn't have a lot of interest in continuing to read it. Based on what I've read about the project elsewhere, that seems appropriate.

Tuesday, April 7, 2009

JSP tag handlers can't have an attribute named “class”

Recently I've been implementing some tag handlers that emit HTML. In them, I want to carry through some of the standard HTML attributes such as id and class. And I've discovered that Tomcat is quite happy to accept the following TLD entry, but at runtime complains that it's unable to find a setter method for the attribute:

<attribute>
  <name>class</name>
  <rtexprvalue>true</rtexprvalue>

  <type>java.lang.String</type>
</attribute>

Sun provides a schema definition for the JSP taglib deployment descriptor, and it defines the type tld-attributeType for attribute declarations. Looking at that type definition, we see this:

<xsd:element name="name"
   type="j2ee:java-identifierType"/>

And jumping to the common definitions schema, here's the definition of java-identifierType:

<xsd:complexType name="java-identifierType">
  <xsd:annotation>
    <xsd:documentation>

        The java-identifierType defines a Java identifier.
        The users of this type should further verify that
        the content does not contain Java reserved keywords.

    </xsd:documentation>
  </xsd:annotation>

  <xsd:simpleContent>
    <xsd:restriction base="j2ee:string">
      <xsd:pattern value="($|_|\p{L})(\p{L}|\p{Nd}|_|$)*"/>
    </xsd:restriction>
  </xsd:simpleContent>

</xsd:complexType>

Did you read the comment? That users of the type should perform keyword validation?!? I couldn't believe it, until I turned to the XML Schema docs and discovered that there's no way to exclude values: the enumeration facet enumerates legal values only.

So, two lessons to draw from this: first, XML schema is not only complex but incomplete, and second, you can't use class as a JSP tag attribute. Or any other Java keyword for that matter. At least not in a servlet container developed by people who have read the schema docs, because this restriction is not mentioned in the JSP specification text.

My solution? The ugly but descriptive htmlClass.

(originally posted on my website 19 Nov 08)

Strings sharing backing arrays

For some reason, I thought this bug was fixed years ago … it was reported in 2001, after all. Yet today I was poking around in the JDK 1.5 source, and what do I find?

return ((beginIndex == 0) && (endIndex == count)) ? this :
    new String(offset + beginIndex, endIndex - beginIndex, value);

This particular string constructor is package-private, and exists solely for making copies of strings with the same backing array:

String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

So why is this important? Let's say that you're extracting two fields from a large file of fixed-length lines of text. The file contains a gigabyte of data, millions of lines, but you figure you're OK because you're only saving 10 characters per line:

while ((line = reader.readLine()) != null)
{
    values.put(line.substring(0, 5), line.substring(17, 23));
}

Will you be surprised by the OutOfMemoryError? It happens because those substring calls don't actually extract characters from the large string. Instead, they create new strings that reference the same character array. Once you put them in the map, that character array becomes ineligible for collection, even though line is. The solution is one of the few cases where you should call a string constructor directly:

while ((line = reader.readLine()) != null)
{
    String s1 = new String(line.substring(0, 5));
    String s2 = new String(line.substring(17, 23));
    values.put(s1, s2);
}

This constructor, which seems to do nothing other than copy the string, actually has a lot of logic inside: if it determines that the source string has a backing array that's larger than it needs, it creates a new backing array. In this example, the new backing arrays allows the array backing line to go out of scope and be collected. No more OutOfMemoryError.

Of course, this leaves the question: when and where should you use this technique? There are, of course, lots of cases where you'll know that you're working with small strings, or will be breaking a large string into pieces and keeping all of the pieces. In these cases, the default behavior makes sense.

But in cases where you don't know what will become of the substring — such as when you're writing a utility method — by all means construct a new string. Object creation, we're told, is extremely fast. Is it worth running out of memory to save a few cycles?