Bitter Java 427
Bitter Java: The lessons taught by server-side Java Antipatterns | |
author | Bruce A. Tate (with help from Braden R. Flowers) |
pages | |
publisher | Manning |
rating | 8 |
reviewer | Peter Wayner |
ISBN | 1-930110-43-X |
summary | A collection of bad habits to avoid for server developers using Java. |
Writing and reading technical books is both a pleasure and a chore. Programming computers can be great fun, but doing the job well requires almost impossible amounts of discipline, attention to detail, and pure drive. The machines churn through billions of operations per second and a mistake in just one can send everything tumbling out of control. Most authors tend to gloss over the difficulty by tossing in a spoonful of Mary Poppins because it does little good to grouse. It's just so simple and straight-forward to toss in optimistic words like "simple" and "straight-forward."
Tate's approach is looks a bit different. He wants to follow in the tradition of Frederick Brook's Mythical Man Month and talk about software development with an honest voice. Microsoft executives, Objective C devotees, and assembler lovers will be disappointed because the title is a bit misleading. He's not really bitter about Java in the way that Princess Diana was bitter about the British Royalty, he's just had a few bad experiences and he wants to help us learn from them.
In fact, he's not even writing about Java in the general sense. The book concentrates on the problems that often arise with most popular and complicated applications for the technology like servlets and enterprise Java beans. If you're building a web site based on Java, then you might want to read through this book.
The structure itself is devoted to uncovering antipatterns , a term Tate uses because it plays off the way that Sun offered Java patterns to help programmers use the new tools efficiently. Most of the chapters show the wrong way to build something and then show how to correct it.
Chapter 8, for instance, demonstrates a bulletin board that seems to be well-designed on the surface. The parts of the data structure are broken up into suitable objects and every object comes with a collection of methods that act as gatekeepers for the data inside the object. It all looks elegant, but it performs badly especially on large installations when the objects live on different servers. Suddenly, all of the extra well-meaning object-oriented engineering starts jamming the flow. Wrapping every object with so much glue code is like hiring more workers to speed up a bureaucracy. Tate shows how to aggregate the calls and speed things up dramatically by cutting through the misapplied object-oriented concepts.
If you step back a bit and think about the book from a distance, the right title starts to look like "Bitter Object-Oriented Programming". Most of the problems in the book emerge when seemingly good uses of OOP turn out to be terribly slow when implemented. While all of the problems are practical hurdles awaiting Java programmers, they must have cousins in the world of C++ and the other OOP languages. Splitting things up into many objects is plenty of fun at the beginning, but when the messages start flowing, the code becomes a swamp.
After a few chapters it becomes clear that object-oriented programming is starting to reach practical limits. The theory may be elegant, but programmers can only make it work if they use guidebooks like Tate's. The object-oriented toolkits are too easy to use dangerously. So what is the solution?
This kind of guidebook filled with antipatterns may be the best we can do for now. Tate himself says that the book is filled with "merc talk", the kind of chatter about hair raising experiences he says that mercenaries trade when they're sitting around the fire. This is an apt description. If you're a hired codeslinger creating J2EE applications or servlets, then this is a good book for your shelf.
Peter Wayner's latest two books are Translucent Databases , an exploration of how to create ultra-secure databases, and Disappearing Cryptography: Information Hiding, Steganography and Watermarking , a book about mathematical parlour tricks, sleights-of-hand, and subversive things you can do with bits. You can purchase Bitter Java at bn.com, and you can join Peter in reviewing books by submitting reviews after reading the book review guidelines.
This book is right on the money (Score:1, Informative)
Antipatterns (Score:5, Informative)
Actually, "antipattern" is an accepted term in the pattern commnunity for describing a bad process or design that on the surface looks like a good idea. If a Pattern is a good practice distilled from the experiences of many good develoeprs, then an antipattern is a "gotcha" thathas been distilled from experience common to many good developers. This book describes it, but th ename really has nothing to do with Sun's practice of describing things in terms of patterns.
-Frums
Re:The solution (Score:2, Informative)
Go back to assembly! :-)
Re:Simple, stupid but not efficient (Score:3, Informative)
No, the over-engineering of code with too many layers and overly complicated object heirarchies are much more likely to be the culprit.
Roger Session (COM and DCOM: Microsoft's Vision for Distributed Objects, Wiley, 1998) (OK, this is from the pre-C# days when MS was going to have you do your GUI in VB, your business logic in the MS Java dialect-du-jour) goes on about "object pools", about how you don't create a new taxi cab everytime you need a ride from the airport.
Yes, that is a good example where the Factory pattern along with object recycling is useful.
I always wondered, what is so expensive about object creation anyway, and in C++ with "auto" objects, it is just about free. Java object loading, however, is expensive because unlike C++, they do not use a static VTABLE but have to check character string names against what is in the object. Java object loading is what makes you sit there twiddling your thumbs when an good sized Java app fires up.
You are confusing 'class loading' with 'object creation'. Class loading typically happens once for many object creation events.
Auto objects in C++ come off the stack, whereas Java objects are always allocated from the heap. However, current Java implementations are very fast at object creation, and you never blow stack with Java objects. ;-)
So, to optimize a Java app, one has to leave clean, textbook OO behind and resort to tricks like OO's that "lazy load" classes as they are needed instead of at application start time, like the use of "object pools" to create object instances once and keep reusing them.
Um, that is 'textbook OO'. BTW, 'lazy loading' was around long before Java...it's been used for years in the VB community.
The word on the street is that Java is dog slow unless you optimize,
The word on the street is wrong, then. Modern Java is quite fast on typical 'first blush' code.
it is slow because of class loading,
Class loading mainly effects application startup time. It is a fallacy to confuse 'startup time' with 'execution time'. Many of my apps stay up for days at a time...startup time just isn't an issue.
and the way you optimize is that you use object creation sparingly in your inner loops, even if it makes your code look ugly.
Interestingly, this is also a good way to optimize C++. ;-)
Anti-patterns in 1998 (Score:5, Informative)
If folk are interested in the concept of modelling the "wrong" way to do things then I would also recommend reading Anti Patterns - Refactoring Software, Architectures and Projects in Crisis by William H Brown, Raphael C Malveau, Hays W "Skip" McCormick III & Thoma J Mowbray (ISBN 0-471-19713-0).
This takes a slightly higher level look at the whole management of coding projects (although a lot of the patterns that are desribed are equally applicable to the low-level coding structure) and looks at common fallacies that are used by many teams as the "correct" way to do things. A knowledge of common mis-conceptions that have been proven not to work in the past (except in certain clearly defined "special cases") is invaluable in being able to spot the nascent structures before the get set in stone and the cost of re-factoring the structures becomes higher than the cost of living with them.
Finally if people really want to get into this field I would also recommend Death March: The Complete Software Developer's Guide to Surviving 'Mission Impossible' Profects by Edward Yourdon which, if nothing else, serves as very reassuring purely from the fact that you know that many many other people have to deal with similar situations when project management goes really bad.
Finally as food for thought for those posters who stated above that patterns (and specifically design patterns) are not useful, I'll take the liberty of quoting the preface to Anti Patterns:-
Sample chapters (Score:4, Informative)
Also _Effective Java_ (Score:3, Informative)
It's definitely not a book for beginners; it's more of a style guide for API design in Java. It fills a gap between the very abstract world of patterns and the low-level syntax of the language. For example, it gives a several-page exposition of the contract of equals(), which was eye-opening even to this fairly experienced Java programmer.
And
Re:Development Processes be damned.. (Score:3, Informative)
The book was originally written with SmallTalk in mind. Maybe you should stick to just saying "object-oriented" (I suppose 99% of which are C++ and Java programmers, though VB is finally truly object oriented, so it applies to them too)
Do you know why? Because the "patterns" are meant to overcome language hurdles that dont occur in lisp and strictly functional languages.
Give me just one example so I can begin to take you seriously. There are just different hurdles. First off, let's be clear, lisp is not by any means a "strictly" functional language. Strictly functional means no side effects. At all. Which is fine if you want to wrap everything up into typeful states and pass them around with syntactic sugar ala monads, but guess what, you just implemented a pattern. One that has a bit more mathematical category theory behind it, but it's still a pattern, imposing a structure on your overall design that may or may not fit your needs.
Re:Development Processes be damned.. (Score:1, Informative)
Re:Development Processes be damned.. (Score:1, Informative)
I not a devotee of purely functional languages, but check out this essay [norvig.com] on the role of patterns in Lisp. The author was a research scientist at Sun is presently head of research at Google. If it doesn't convince you, nothing will!
Re:Design patterns and Lisp (Score:1, Informative)
Much like in spanish, where a plural containing at least one male uses the masculine form.
Re:Design patterns and Lisp (Score:1, Informative)
The type is determined by its use and enforced. I wish C/C++ had similar facilities.
Re:Design patterns and Lisp (Score:1, Informative)
I don't miss typed variables at all. You can OPTIONALLY declare the types of variables using (declare
Or you can eschew functions and use methods exclusively. CLOS methods are really "multimethods" -- they dispatch on the types of as many of their arguments as you care to supply types for. Using methods instantly reveals when you've supplied an argument of the wrong type (since no applicable method will exist).
Re:Design patterns and Lisp (Score:3, Informative)
I just fininished reading Modern C++ Design [awprofessional.com] by Andrei Alexandrescu, which explains all sorts of cool hacks you can do with templates in C++. Or to put it in more sober language, how to implement reusable design patterns using C++'s templates and compile-time polymorphism.
It's a great read and really demonstrates just how powerful C++'s templating system is. It shows how to do just what you say - create a general macro from a specific pattern instance - for example making reusable templates to efficiently implement multiple dispatch and the Visitor pattern. And C++'s template specialization happens at compile time, which with a good optimizing compiler gives you performance as good as handwritten code. I haven't used Common Lisp so I can't compare C++ templates to CL macros - but you shouldn't underestimate C++'s macro-ing and code reuse abilities. The syntax is horrible, but there do exist people who don't like Lisp syntax either...
The fact that early C++ implementations were using the cfront preprocessor doesn't really say much about the language - just that it had an unwieldy first implementation. All current C++ compilers really do handle the language natively (g++ for one). You can find all sorts of reasons for saying C++ is unpleasant and ugly, but cfront is not one of them. OTOH, if you were saying that Lisp is more powerful than C because it is much easier to add objects to Lisp than to add them to C: well of course, everyone knew that already.
Re:Design patterns and Lisp (Score:4, Informative)
Lisp does have patterns, but Lisp hackers tend to implement them as macros, automating their application rather than forcing everyone to know and re-enter them to use them. That's the difference between:
// Please forgive any Java errors here
// I don't use this pattern enough to get it right
// without a compiler to check it...
try {
FileInputStream myfile = new FileInputStream(filename);
}
finally {
myfile.close();
}
and
(with-open-file (myfile filename)
)
They do the same thing - guarantee that myfile gets closed no matter what - but the Lisp way requires less typing and is less prone to errors.
Re:C++ templates vs. Lisp macros (Score:3, Informative)
C++ templates share much of the power of Lisp macros, but they are somewhat more restricted in what they can do and express. They play an essential role in writing generic algorithms, which is a great thing. But once you've decided to write your C++ code using templates, you're committed to doing things in the template style. Lisp macros are completely transparent, in the sense that macro code and Lisp code look the same, and fit together.
I concede that the STL folks and Blitz++ folks have done amazing things with the template system. But C++ compilers still have issues with getting the STL to work consistently.
I think the way I would summarize it is that writing Lisp macros is continually improving the language, without narrowing the scope of your options. C++ templates feel to me like building a tower. Sure, each floor is higher than the one before, but soon, the only way to build is up. If you don't like the choices you made building the ground floor, you have to abandon the work built on top, as well.