Bitter 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.
After years of listening to manager preach about "repeatable processes" and "the replaceable engineer" it's about time someone focused on skillsets. Appropriate and judicious use of OO concepts, design patterns does not a cookie cutter make.. Component design kludged up with so much glue that software engineers these days are nothing more than component assemblers.
Development prowess and productivity is determined by how well your code works, not how many widgets you can crank out and connect together in "internet time". It's knowing how things work, and if they'll work together well or not. It's knowing when it's better to write the damn thing yourself, instead of spending 2-3x more time and resources gluing off the shelf components together..
I'm heading off to buy the book, if not just for the reason to support the author courageous enough to go against the grain and give this topic a voice.
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.
And Al Gore invented the internet. Or was that Bill G again?
"Keep it simple, stupid." - anonymous
"Limit temporary object creation." - any smart Java programmer
Java does a pretty good job of providing much more functionality for a little more overhead. There are areas in the Java libs which seem over-engineered and slower and bigger than they should be (Swing!). Don't throw out the baby with the bath water, though...Java is good and the crufty parts will evolve into something better.
Galileo: "The Earth revolves around the Sun!"
Score: -1 100% Flamebait
Well, that's a really intelligent question - very entertaining as well. In a post that actually relates to the book, I think that Tate does a nice job in this book of really showing proper object oriented programming. So often OOP gets used as such a buzzword that if you, as a programmer, don't embrace and beat it into the ground, you're somehow seen as substandard or writing poor code. There are tools for every job. That's why people need to get a better grasp on OOP and understand when it should and shouldn't be used. One thing that this review did not mention is Tate's crisp writing style. He writes with a slightly conversational tone but one that won't become annoying by the 50th page or so. This is a very good book and I suggest you pick it up if you believe that OOP is the cure for all of society's ills.
Hello fellow coders,
I'm a first year programming student at a local community college school and I've just finished my Visual Basic classes. This term I'll be moving onto Java. However I've noticed some issues with Java that I'd like to discuss with the rest of the programming community. Please do not think of me as being technically ignorant. In addition to VB, I am very skilled at HTML programming, one of the most challenging languages out there!
Java is based on a concept known as Object Oriented Programming. In this style of programming (also known as OOPS in the coding community) a programmer builds "objects" or "glasses" out of his code, and then manipulates these "glasses". Since I'm assuming that you, dear reader, are as skilled at programming as I am, I'll skip further explanation of these "glasses".
Please allow me to make a brief aside here and discuss the origins Java for a moment. My research shows that this language is one of the oldest languages in existance, pre-dating even assembly! It was created in the early 70s when AT&T began looking for a new language to write BSD, its Unix Operation System (later on, other companies would "borrow" the BSD source code to build both Solaris and Linux!)
Back to the topic on hand, I feel that Java - despite its flaws - has been a very valuable tool to the world of computers. Unfortunately its starting to show its age, and I feel that it should be retired as C++, Python and Perl seem to have been. Recently I've become aquainted with another language that's quite recently been developed. Its one that promises to greatly simplify programming. This new language is called COBOL.
Although syntactically borrowing a great deal from its predecessor Ruby, C greatly simplifies things (thus its name, which hints at its simpler nature by striping off the klunky double-pluses.) Its biggest strength is that it abandons an OOPS-style of programming. No more awkward "objects" or "glasses". Instead C uses what are called structs. Vaguely similiar to a Java "glass", a struct does away with anachonisms like inheiritance, namespaces and the whole private/public/protected/friend access issues of its variables and routines. By freeing the programmer from the requirement to juggle all these issues, the coder can focus on implementing his algorithm and rapidly developing his application.
While C lacks the speed and robustness of Java, I think these are petty issues. Given the speed of modern computers, the relative sluggishness of C shouldn't be an issue. Robustness and stability will occur as C becomes more pervasive amongst the programming community and it becomes more fine-tuned. Eventually C should have stablity rivalling that of Java.
I'm hoping to see C adopted as the de facto standard of programming. Based on what I've learned of this language, the future seems very bright indeed for C! Eventually, many years from now, perhaps we'll even see an operating system coded in this langauage.
Thank you for your time. Your feedback is greatly appreciated.
It is sometimes very scary when things are so, ahem, much marketed. In many places, there seems to be more emphasis on the tools and techniques used than what the product is supposed to do.
For example, "We clinched the deal because we promised to use the J2EE/EJB framework" -- as opposed to, "Our product is good, and the guys liked our technical expertise and design." This is a "sort of" true story!
S
Of course, there is no magic bullet to make software suck less, but I would strongly encourage all developers to at least look at what FP offers.
Advertising cross-platform code as being one of the major benefits of java was a mistake by Sun. They should have realized that a language written for a generic VM is cross-platform only if the implementations of that VM and the system interfaces it uses on each platform are 100% compatible. That's a challenge even if all the implementations are written by Sun! Considering that they are not, and that some of those implementations were written by people with a somewhat vested interest in ensuring that cross-platform operation never comes to pass, it should have been obvious that it would never come off without a hitch.
Making "Write Once, Run Anywhere" a Java mantra was a huge mistake. It should have been more like "Write once, tweak a little, maybe it'll run... But it's easier than porting C code!" A more modest claim would have been much better.
The enemies of Democracy are
they speed up the development of a system
or
they speed up the execution of a system
This is, of course, one of the fundamental trade-offs that us computer programmers make all the time. The important part is choosing a pattern that is appropriate for the system. For example, the flyweight pattern is used to limit/reuse objects in a system. It is appropriate to use this pattern when top execution speed is necessary, but the price is the complexity of implementation.
The facade pattern, OTOH, is designed to make life simpler for programmers, potentially at the cost of execution speed.
It sounds to me like this guy has trouble picking the appropriate patterns from the start.
std::disclaimer<std::legalese> sig=new std::disclaimer; sig->dump(); delete sig;
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
I can see it now:
Chapter 1
The joys of 0
Chapter 2
The joys of 1
Chapter 3
0 meets 1
--It's Pimptastic!--
Danny (who plays gamelan and is interested in Indonesia).
I have written over 900 book reviews
The best Java book that I have seen so far is "Thinking in Java" by Bruce Eckel. Here is why.
While Mr. Eckel's book does covers the syntax of the language (java in this case) et. al, it also cover the meaning of the language and most of all, it covers how to think in the language (hence: the title).
Almost any developer can pickup a language and become knowledgeable with it by working on one or two projects. However, being *proficient* at your domain, and understanding coding-principles of the language for your domain, and understanding the business of being a programmer is much more difficult goal to achieve -- only time, experience, and dedication will ever get you there. It is this quality that I look for first, the knowledge of a language comes third.
Here is a link that I point people at to high-light my point: Chicken Soup for Your Modeling Soul -- I specially like item 21: "A fool with a tool is still a fool".
Karma stuck at 50? Add 2-5 inches.. err.. 2-5x Karmas Count to your pen1es.. err.. Karma all naturally and private
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++. ;-)
Galileo: "The Earth revolves around the Sun!"
Score: -1 100% Flamebait
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:-
The only Good System is a Sound System
There are some sample chapters available on the book's website
It's not that every Lisp program has a different design, any more than every machine has the same design; however, in Lisp, there tend to be fewer obstacles to expressing a particular program design in the language. There are a wide range of reasons for that.
One is the pervasive nature of intrinsic typing. Variables are not typed, values are. Object-oriented methods, of course, explicitly mention classes, but non-OO code does not need to explicitly type variables, except to improve performance. The flexibility of many built-in Lisp operators helps deal with multiple types transparently. For instance, length of array, length of a string, and length of a list all use the same function: LENGTH.
Another source of flexibility is Lisp macros, which can use the full power of the Lisp programming language to rearrange and process Lisp macro calls into Lisp code. If there is some design pattern that Lisp does not natively support, you can use Lisp macros to create a Lisp "dialect" that cleanly expresses the design.
Paul Graham, in his books, demonstrates, for instance, that if Lisp did not already have CLOS to express object-oriented concepts, that in about a hundred lines of pretty clean Lisp macrology, you can add single-dispatch methods to the language, and it looks just like "real" Lisp, and mixes with the base language transparently.
It took Stroustrup a large effort (cfront) to add objects and methods to C, and it requires explicitly invoking a compiler program to do the translation, with name-mangling and everything else. In Lisp, you would write Lisp macros to do the same thing, and you would still be working in true Lisp. You can also add macros on macros: cfront is basically a monolith, but Lisp macros can work together; you can continuously "build up" from the language foundation, and the various layers can be overlapped.
Any time you find yourself repeating a pattern, it suggests a Lisp macro. If you have an example of the pattern already written, it is pretty much cut-and-paste to create the general macro from the specific pattern instance.
That kind of flexibility, which allows the programmer to mold the language to fit his (and his tasks) needs, is really what makes Lisp great to work with.
It's something like the difference between working with Legos and clay. If you're missing a Lego part to serve a particular function, you're pretty much stuck, unless you want to injection-mold your own custom blocks. Therefore, Lego models tend to use "design patterns" where the standard blocks or parts fit together a certain way that solves a certain class of problems. Lego models, although they can be amazing achievements, all tend to look like Lego models.
With clay, however, the medium is fluid. You can mold it to just about any shape you want. Sculptures usually look like their subject, not like clay.
Another really superb book is Effective Java, written by Josh Bloch, who is responsible for the Java Collections API.
... it's superbly written. Bloch's prose is crisp, clear, and gets right to the point. It is, in fact, my favorite book devoted to a single language since K&R.
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
OO and functional are not opposing concepts. Also, you may have missed the subtle point, but Lisp is not a strictly functional language, although it is obviously function-oriented.
Lisp has a full-blown object system called CLOS (Common Lisp Object System), which frankly blows C++'s object system out of the water, in terms of flexibility, power, and syntactic cleanliness, just for starters. Lisp programmers aren't scared of OO. It's C++ programmers who are scared of Lisp, although why anyone would be less scared of C++ is a mystery to me.
OO doesn't magically mean "easy to maintain." It may mean "easy to find drones who think they learned the language from a book in 21 days, so they put in on their resume" which I think was your real point.
To address the original issue, functional designs tend to be much more "factored" than procedural designs, because things are designed to use functional abstraction rather than interactions between different bits of code and variables. This tends to make them much more robust and maintainable.
...bitter about people who decide that one language is all they need to learn and leave the rest of us having to know mediocre programming languages because that's the only way you get a job?
...bitter about people who keep buying into marketspeak?
...bitter about people who keep developing the same old language, but put some makeup on it so for it to seem different?
...bitter about methodologies, because they're set in stone?
...bitter about requirements, because they're set in water?
...bitter about business because you're just a "resource" to them?
...bitter about business programming because it's dull, insignificant, and someone should have already figured out a way to generate all this stupid code since it's been repeated some many times over?
Heh, whatever, I need to sleep.
I'm truly not worthy. You have elegantly and accurately captured the spirit of Bitter Java. I spent a whole lot of time as a Java architect and consultant, and noticed a whole lot of repeated mistakes. Bitter Java is about capturing those mistakes and wrapping them up, so that others can avoid them. I've got a weakness for kayaking, and that comes through (a little too strongly?) in the book. One of my favorite pictures is of a friend leaning against a sign after driving all night, and yawning. We snapped the shot, and then pointed out the words on the sign: "Seven people have drowned here." Of course, after wetting his pants, Eric was about to get in his kayak and run the falls. That's a perfect antipattern. Literary form; concise; points out a negative behavior (playing under the falls), and the decidedly negative consequence. That's Bitter Java. Of course, you've also got to point out how to avoid the negative consequence, and thus the emphasis on refactoring in Bitter Java. I definitely cannot claim credit for creating antipatterns. (Thanks to the reviewer who compared me to Al Gore...priceless.) In fact, one of the authors of the best-selling Antipatterns book, Skip McCormick III, wrote a glowing forward for Bitter Java. Thanks, Skip.
The hardest thing to get across to a Java/C++/VB zealot is that assembly is the most powerful language available. There is no computing algorithm, or programming paradigm that can't be expressed in assembly. I routinely write classes in assembly, and use runtime polymorphism - in fact, correct multiple inheritance is more easily implemented in asm than C++! (fewer lines, no assinine casting...) However, this doesn't mean that assembly language is the cure all for every programming problem. Some problems lend themselves to assembly (like device drivers, OS code), others to C++ (games, applications), and others to Java (web programs). What's hard is convincing people that if they understood the underlying computer science, they could write the code in the language which best suited the particular application, rather than being stuck writing in Java, or whatever HLL is popular at the time.
Incidentally, I like assembly because of the freedom and power it provides. But I still write in Java or C++ when the needs of the project dictate. Real computer science transcends the language used, as languages come and go. Soon, Java will be outdated, and those who only learned to program in Java will find their knowledge useless.
What matters is not whether you know langauge X, but rather that you know the fundamental algorithms of computer science and can translate them into any language. If you can break down a task into algorithms, then you can pick the language best suited for those algorithms, and translate the algorithms into code in a trivial amount of time, regardless of which language you use. What too many people miss is the fact that if you can't break a problem down into its fundamental algorithms, or translate those algorithms into an arbitrary language, your days as a programmer will be few, irrespective of how well you know a particular language.
The society for a thought-free internet welcomes you.
I have to say it... There are no concrete examples; only abstract super class examples.
They that can give up essential liberty to obtain a little temporary safety deserve neither safety nor liberty.
Ben
I suspect you and I have different definitions of OO. The problem is that damn near everyone has a slightly different definition of OO. Go read this article by Johathan Rees, then come back and tell us what you mean by a "real OO system", and why you can't do it properly in CLOS.
To a Lisp hacker, XML is S-expressions in drag.
I just fininished reading Modern C++ Design 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.
-- Ed Avis ed@membled.com
I think there seem to be fewer patterns in Lisp, because Lisp needs them less. Lispers tend to dismiss patterns because of presentations like this one by Peter Norvig, in which he shows that roughly two-thirds of the patterns in the Gang of Four book deal with techniques that are unnecessary in Common Lisp.
// Mess with file...
;; Mess with file...
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.
To a Lisp hacker, XML is S-expressions in drag.
Lisp macros are also compile-time. And, because the transformations they perform end up producing "ordinary" Lisp code, all Lisp compilers get them correct. Also, since the macro language is the same as the base language, it is well-defined. In fact, a substantial portion of a Lisp compiler is likely to be written using Lisp macros.
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.