As I type these words Java has just turned 25, and it seems discourteous in the extreme not to mark the occasion. If you are a software engineer of any stripe then you owe Java a tremendous debt of gratitude, for reasons you may not be entirely aware of. If so you are not to blame - as an industry we are terrible at recording our history, and much of the turbulent 90's has faded from the public mind.
So here are some truths about Java that may have passed you by.
Everyone Attacked It
You may think people are critical of Java today, but that's nothing compared to when it was first introduced. Developers of all kinds assailed it from every conceivable angle:
- Visual Basic developers claimed no language could be considered
complete without a built in
MsgBox function to pop up a dialogue
box. This shows how history makes fools of us all.
- Entrenched professionals poured scorn on Java as "C++ without Header
Files or Pointers". This probably did more to promote the language than Sun's entire marketing department.
- Educators called it a 'toy language' because the lack of pointers made
it impossible to create data structures. This reflected a profound lack of understanding about references and garbage collection.
- Academics castigated its lack of originality, mostly for copying the
class based concept of Object Orientation. They saw it (with justification) as just a scaled down Smalltalk.
Of course it is fair to say that the syntax of Java wasn't exactly novel. It mostly codified a lot of existing C/C++ best practices and plastered over the worst warts. Which brings us neatly to the second point.
The Revolution Was The Runtime
This will sound strange to young ears, but back in the day you couldn't program at home the same way you did at work. If you were developing in the 1990s then you were likely using a commercial version of UNIX (Solaris in my case) with a proprietary compiler and paid for libraries (Rogue Wave Threads.h++ was a personal favourite). Even when libraries were publicly available you had to pray build files existed for your own OS and compiler.
The situation was not completely bleak. Linux and the GNU toolchain were already available - although anyone who tried to install Linux on a PC in the 90's might take issue with the precise meaning of 'available'. But if you were a trainee developer you could not experiment at home with the programming environment you had at work.
This is something we take for granted today, and it came to pass because of the 'Write Once Run Everywhere' promise of the Java Virtual Machine. A team could release a library as an Open Source project and it would 'just work' on other platforms. This created a massive ecosystem of tools like JUnit, Ant and Spring that invigorated the Java community and incrementally pushed vendors away from the closed source model. Even Microsoft was finally forced to admit that Open Source was a force for good.
The Runtime Was Flawed
Of course that's not to say the runtime was perfect. The relatively modest objectives of the Java team in the early years produced pain points that festered over time. Specifically:
- The notion of a library was never formally specified. We could
group our types into packages, and then compress them in JAR's. But how
many packages per JAR? Was each JAR a library? Which libraries should
be loaded first? Could libraries be reloaded? What the dickens was a
Component on the JVM? One answer to this was OSGi from IBM, which Sun
disapproved of. Leading to the whole sorry saga of the Search For The One
True Module System - the repercussions of which still echo every time
you grapple with Gradle or Maven.
- The importance of Generics was not sufficiently appreciated
Because of this the work to add it to the language began very late. This produced a bunch of compromises, the most serious of which is the lack of reification. To prove what a problem this is you only need to print and then weigh the Java Generics FAQ.
- They forgot about user interfaces and event handling. Anyone doing
GUI development in the late 90s knew how painful it was to handle events. Microsoft surely did, and took advantage of this to 'innovate' by adding bound method references (aka. Delegates) to J++. Which in turn became the proving ground for C#. It's always baffled me that the Java team dug in their heels on this issue for so long.
Despite the above Java shrugged off the challenges from alternatives like C# and Ruby and remained dominant till very recently. In the past few years the ubiquity of Python and the compelling case for Serverless are the first things I've seen that really put the future of the JVM in doubt. Which brings us to our final point.
Java Succeeds By Being Boring
Java, like many companies, has succeeded by taking a single idea and remaining true to it - even when the novelty is long gone. The big idea was to iterate over the C language family and enhance developer productivity through platform independence, simplified memory management and dynamic binding. This has made it the Golden Child of Enterprise Computing for decades.
Along the way the Java team learned (in part from the mistakes of others) that what big business values most is continuity and certainty. So they have resisted calls to break backward compatibility and only added features with the utmost of caution. Like it or loathe it, this has ensured it's success.
Of course in a modern polyglot world Java looks increasingly long in the tooth, but as this superb talk from KotlinConf 2019 shows, it's working hard to keep up with its progeny. Essentially Java succeeds by being the Ford Transit Van of our industry - no one wants one in their drive but we couldn't survive a week without them.
The story of Java so far has been a play in three acts. In the first act it is the plucky up and comer that is hated by the establishment and changes the world for the better. In the second act it becomes the new orthodoxy that others struggle to overcome, and in that way continues to benefit us all.
In the third (and final?) act Java finds itself the grey haired monarch on the throne. Still with very real power but increasingly bypassed from the major decisions. Of course, waiting for Java to die is a fools game, and it has weathered innumerable crises in the past. But, as with real world potentates, that's only true until it's not, and the end is only obvious in retrospect.