Saturday, August 31, 2002

Effective Java, C# Essentials, Essential Java Style

This article appears in slightly different form in the July/August 2002 issue of IEEE Micro © 2002 IEEE.

Programming Books

This time I look at books designed to help you program in Java and Microsoft's new language for the .NET framework, C#. When I first wrote about Java (Micro Review June 1996), I said
I think Java will eventually replace C, but I think C++ will persist as its competitor for a long time. That conflict will probably follow the model of the RISC vs CISC wars, so that ten years from now it will be hard to know which is which.
There are still four years to go for that prediction, but whatever happens to C++, it's already hard to tell C# and Java apart. The books I look at this time often sound as if they are quoting each other, almost word for word, whether they deal with C# or Java.

Effective Java by Joshua Bloch (Addison Wesley, New York NY, 2001, 268pp, ISBN 0-201-31005-8, $39.99)

Joshua Bloch is the ideal person to write about using Java effectively. He has a distinguished academic background and works as a software architect at Sun, where he has been since 1996. He designed and implemented the collections framework and the java.math package.

Bloch borrows the title and format of his book from Scott Meyers' Effective C++. When I reviewed Meyers' book (Micro Review, Nov/Dec 1994), I wrote that Meyers should have titled it "C++ Traps, Pitfalls, and Swindles" (an allusion to a chess book by Fred Reinfeld). I wrote
You can look at this book two ways. From one point of view it is an enormously helpful compendium of practical advice on C++ programming. From another angle it is a point-by-point condemnation of C++ as an unusable, unintuitive programming language.
I'm happy to say that only the final two chapters -- on threads and serialization -- of Bloch's book make me feel that way. The behavior of threads appears to be quite unintuitive and to depend on a continually changing memory model. Serialization appears to have insoluble problems, because it conflicts with the modularity and encapsulation that are at the heart of the object oriented model. The remainder of the book, however, leaves me with a decidedly more positive impression of Java and the care with which Sun continually reviews and improves it.

I do not always read every word of books that I review, but I read every word (and every line of code) of this one. I read it sequentially from cover to cover, but you don't need to. Like Meyers' book this one consists of short essays (57 in this case), grouped into 9 topic areas. Bloch wrote the essays independently, so you can just read what interests you. I found all of it fascinating.

Bloch writes about Java programming style, but rather than doing so abstractly, he stands knee-deep in implementation details. He often bases his analysis of a situation on how the Java virtual machine is likely to behave. He also brings in his deep knowledge of and respect for the Java libraries. He points out that it's foolish to waste your time inventing ad hoc solutions to problems, when experts have already solved those problems and made the solutions conveniently available in libraries like java.lang and java.util. This seems too obvious to mention, but many programmers, unfortunately, need to hear this advice.   

Object oriented programming is a good example of the principle that there's no such thing as a free lunch. Bloch's essays entitled "Favor composition over inheritance" and "Design and document for inheritance or else prohibit it" illustrate this point clearly. You promote reuse if you provide a class with the intent that someone in another company working in a different package can extend it (that is, create a subclass) by overriding some of its methods. The costs of doing this -- often overlooked, even by experienced designers -- are reduced modularity and greater vulnerability to errors or malicious attacks. Allowing subclassing reduces modularity because you must document details of your implementation. For example, you must say (and commit never to change) when and why you invoke the overridable methods within your own class -- details that would otherwise remain private. Allowing subclassing increases vulnerability because you must also declare some methods and fields of your class to be protected, that is, available to the subclass. If you were not making the class available for subclassing, you would declare those methods final and the fields private.

The essays just discussed are in Bloch's chapter on classes and interfaces. Many companies sell Java-based software. They design interfaces and provide classes to implement them. How well they do this can mean the difference between a successful product and one that generates more support costs than revenue. If your company sells Java-based software, it's a very good idea to ensure that you are familiar with the issues Bloch discusses.

The other parts of this book are just as valuable. Bloch consistently returns to the themes of usability, robustness, and flexibility. He also addresses efficiency (for example, pointing out the costs of string concatenation), but warns that optimizations often cost more than they save. He also points out that the design of the public interfaces can sometimes have a much greater effect on performance than tinkering with implementations. First write a good, modular program. Then measure performance with profiling tools to find out where the bottlenecks are. Tinker with the few small places that might have a big effect. Then measure again, because optimizations don't always have the effect you think they will have.

Every bit of this book is essential for Java designers. Reading this book before you start delivering products can easily repay its cost thousands of times.

C# Essentials, 2ed by Ben Albahari, Peter Drayton & Brad Merrill (O'Reilly, Sebastopol CA, 2002, 202pp, ISBN 0-596-00315-3,, $24.95)

The C# language is Microsoft's answer to Java. Java programmers should have no trouble learning to program in it. Rather than running on a Java virtual machine, C# runs on the .NET runtime environment, which is called the common language runtime (CLR). All languages on the .NET platform compile into CLR modules and can interoperate with each other, including seamlessly using each other's objects and classes.

This book provides an excellent overview of the basic language and its features. Like Java, however, C# relies on an extensive library. For C# the library is the .NET framework class library (FCL). This book provides only the sketchiest overview of the FCL. As it has for Java, O'Reilly will probably produce a large stack of books on the C# library and environment. Until then, you'll have to work with the overview documentation that Microsoft provides with the .NET framework and its software development kit (SDK).

One interesting feature of the FCL is its support for regular expressions. This is a natural outgrowth of Microsoft's support for XML. If you're going to be working with a lot of plain text files, which is what XML files are at heart, you need powerful tools for manipulating them. Regular expressions provide such a tool. The book provides a nice summary of the FCL support for regular expressions, which parallels that of the Perl language.

The book is short. It does not pretend to be more than a concise summary of the language and its relationship to its environment. Nonetheless, it contains lots of useful information. The writing is clear and concise, and the material is well organized. If you're starting to program in C#, this is a good book to have handy.

Essential Java Style - Patterns for Implementation by Jeff Langr (Prentice-Hall, Upper Saddle River NJ, 2000, 300pp, ISBN 0-13-085086-1,, $39.99)

This is a helpful book on the nuts and bolts of writing good Java code. At the same time it is an annoyingly curmudgeonly work. Langr continually rails against decisions that the designers of Java made a long time ago. Nobody can do anything to change those decisions now, so this carping is of little use to his readers.

Langr's subtitle plays on the idea of design patterns, a widely accepted way to describe and name designs for programming subsystems. Langr, however, does not write about architecture at that level. His patterns deal with designing and coding individual modules.

Langr blends valuable content with a clear, easily comprehensible, and visually effective presentation framework. He presents close to a hundred patterns, grouped into six groups, or categories. Each pattern answers a specific "How do I . . .?" question, making the book task oriented -- a rare but much appreciated characteristic of a programming book. Langr presents the patterns in a visual style reminiscent of good API documentation. Each pattern's entry begins with the pattern's name followed by a boxed table containing the question the pattern answers, a summary of how it does so, and references to related patterns. Langr follows the table with a few explanatory paragraphs and annotated code examples.

Langr gives his patterns names, rather than numbers, so that people can remember them more easily. This is a good idea, but names and numbers are not mutually exclusive. By numbering his patterns as well, he can make it easier for programmers to navigate to the information they are looking for. I hope he adopts this practice in future editions.

Langr comes from a Smalltalk background. Many of the underlying ideas come from Kent Beck's Smalltalk Best Practice Patterns (Prentice Hall, 1996). Few Java programmers are likely to have read that book, so this adaptation for Java will bring the patterns to a much larger audience.

In addition to the chapters that describe the patterns, Langr provides two other valuable discussions. The first is a long annotated example that illustrates many of the patterns. The second is a collection of hints for achieving good performance. Langr purposely avoids discussions of performance in most of his patterns. In this section he addresses a few Java-specific optimizations. Because implementations change, these hints may not apply to later versions of Java, but many probably will.

The book is a little dated, because it refers to Sun's JDK 1.1 and 1.2. Most of the information is still valuable, but a new edition would enable Langr to incorporate recent improvements and to remove obsolete warnings and workarounds. Even so, this book is well worth reading.