Hacker News new | past | comments | ask | show | jobs | submit login

(Edited to clarify that I think Java was good in the very beginning, less so in the middle, and is good once again)

Java started off as the Golang of the 90s: small, simple, opinionated, statically-typed, in many ways state-of-the-art, and engineered to protect the programmer from doing bad things (either due to ignorance or will). It came with a batteries-included standard library.

Then, in a quirk of fate, it became very popular. Though its library provided clean abstractions, you had to chain several of them together to actually accomplish anything: this is why it was so verbose. Everyone was writing Java, but no one was sharing Java, yet. Before Apache (Jakarta) Commons, no one bothered to make wrappers for basic stuff... just like how we were writing bad JS before jQuery or underscore came out. We were caught between our own experimentation, Sun's desire to take over the desktop, and companies like IBM and Oracle that wanted to ensure they could sell commercial support for big monolithic Java appservers.

When the 'Design Patterns' book came out, someone should've made a framework, but instead we sprinkled AbstractStrategyFactoryBuilders everywhere because that's what the enterprise libraries did... and it read like a bad parody of object-oriented programming, but by now, we've learned our mistake.

Now that bad APIs have fallen out of favor, Java EE is nearly abandoned, Spring brought some sanity but also forced us to consider why we're even thinking about convention over configuration, Java is much, much nicer. In the Maven, Github, CI world, we can -- environment and company policies permitting -- easily pull in libraries and frameworks that allow us to actually get stuff done at the correct level of abstraction.




This is a lot different than I remember. As I remember it, Java was touted as a compile-once run everywhere language. Back then, you had many different flavors of UNIX, with different hardware architectures, and in practice, software was deployed (and supported!) directly on customer servers (web services didn't exist). Plus, this was a time when pretty much all code was written in C. Virtual machines with garbage collection were academic research projects.

Java (until recently) was always a sub-par language. It was difficult to work with and behaved in unexpected ways. Academics hated it because there were much better grammars. Engineers hated it because it was slow and rigid compared to C. Gosling designed it for embedded systems, of all things. But, it aimed to solve a very expensive problem, and lots of hype was directed at it.

(Edit: I should have emphasized that the tooling really sucked more than the language. We had fantastic C compilers and IDEs. And, Java had immature tools. Worse, you had to manually build Jars and package your Jars appropriately. Ant, Maven, Gradle, etc didn't exist.)

Also, the GoF authors didn't write design patterns as a response to Java. They wrote it as a retrospective on large software systems - what worked and what didn't. The 'patterns' were called such because they were observed in many independent projects, each having been reinvented time and again. The patterns proliferated with Java EE architects who pushed patterns as common ways to communicate standard design principles. You have to keep in mind that this was also a big time for 1) RAD, 2) UML, and 3) software factories. Large companies were sold a vision than in a very short period of time all they would need would be an 'enterprise architect' who would 'draw' the software, hit a button, and out would come the complete system.


Java (until recently) was always a sub-par language. It was difficult to work with and behaved in unexpected ways.

Every language has its idiosyncrasies to be sure, but this doesn't really jibe with my recollection. I remember Java being a much better alternative to C++ in many ways, including (and especially) binary object compatibility which made it possible to effectively use libraries. Remember how C++ libraries had to either be pre-compiled for your platform (which the same compiler you were using, etc.) OR be shipped as source.. and given C++'s blazing fast compilation times cough cough, well....

Anyway, in 2001 we were building Java IVR applications on Windows and shipping the jars to AIX machines and running them with no problem. The "write once, run everywhere" thing certainly wasn't 100% true (especially for desktop apps using Swing) but for many applications it really was the case (or close to it).


I'm sure it worked well in many cases. But, in our case, we were developing for Solaris, AIX, HP-UX, and Windows NT. The VMs would behave differently in different environments, and I remember VMs stack dumping on many occasions which became a major support headache. We used to call it 'build once, run nowhere.'


But, in our case, we were developing for Solaris, AIX, HP-UX, and Windows NT. The VMs would behave differently in different environments, and I remember VMs stack dumping on many occasions which became a major support headache. We used to call it 'build once, run nowhere.'

Interesting. The only thing I really remember people complaining about a lot was thread scheduling. Java always let you set a thread priority and a lot of people tried to use that to make things behave in very specific ways, but - if I recall correctly - it was the case that that behavior was always allowed to be platform independent and couldn't be relied on to create a consistent cross-platform experience. Outside of that, it seemed like UI issues with Swing (or, I guess, AWT) were the main things people ran into trouble with.

What time frame was all of this for you? Wondering if it was just the very early days of Java before some of the problems were resolved.


Also, Java only provided the lowest common denominator. A piece of software I worked on back then needed to start a long 2hr process, but only if there was more than 2GB of free disk space (which was not a trivial requirement circa 2000). But Java did not have a way to query free disk space at the time because IIRC it was missing on one of the platforms (and then it wouldn't be "run everywhere"). So instead it would run, and if insufficient disk space would just fail.

Java was always "write once, debug everywhere"


> Academics hated it because there were much better grammars.

Surely not at my university.

By 1998 it had already replaced C as the language for distributed computing classes.

C with SUN RPC or PVWM was just too clunky to keep on using and was used just as introduction to distributed computing.

Same with compiler design classes.

The ECOOP'99 was full of Java related presentations with the keynote of Jim Waldo about Jini, something that would just come in handy in our modern IoT days.

> We had fantastic C compilers and IDEs. And, Java had immature tools.

On which OS?

Visual Age, JBuilder, Zortech all were quite similar to their C and C++ siblings.

> The patterns proliferated with Java

Nah, they were already quite common in C++ with CORBA and COM/DCOM projects.

EDIT: typo to => too


Sure, universities embraced it in the late 90s because it was easier to teach to undergrads, and CS programs were becoming cash cows. But, the researchers that I knew certainly weren't using it for their own Computer Science research (aside from VMs and heterogeneous environments).

Yeah, Jini was cool! And Tuple spaces, etc. There were some cool things being built on Java, but few people were embracing it as a silver bullet.


I feel you haven't taken a look at Java in the enterprise in a long time.

Spring is considered to be an overloaded bloated mess and Java EE has become lean and mean with plenty of very capable specifications and implementations (JPA, CDI, etc...).

And FYI, the Design Patterns book came out before Java (1994 vs/ 1995) so I think you have your timelines confused. The early editions of Design Patterns didn't contain a single line of Java, they were mostly C++ (and some Smalltalk).

Java is twenty years old, and for such an old geezer, it's adapted remarkably well (and between Java 8 and Kotlin picking momentum, its legacy seems to be well assured).


I was trying to express a lot of ideas in a small space, and I have edited it since, but it's still not as clear as I'd like. You and I agree, but I have struggled to get this point across.

Spring is a bloated mess, but when it first came out it was lean new framework and a relief from EJBv1 and EJBv2. In response, EJBv3 was much better, but in the meantime Spring became the new normal, and grew into some strange swiss army chainsaw glue with now-deprecated awful xml configuration replaced by the horror of not-quite-code-but-compiled-into-the-classfile @Annotations!

The 'new Spring' is Spring Boot, which was a response to this then-obscure framework called Dropwizard which showed that all you had to do was pick a handful of very good libraries get work done. Guava, Jersey, Jackson, Jetty; some decent ORM, and you're good to go. Some of these are backed by new Java specs like JAX-RS and JPA that are legitimately pretty good.

I think the biggest problem Java still has in the hearts and minds of people outside the 'enterprise' is not because of Java, but because of the complexities that only manifest in environments where your code isn't 100% greenfield every time.

Dependency Injection isn't something you realize you need until you realize you need it -- and then you realize you need it Really Badly.

Externalized XML config files declaring reusable beans isn't something you think you need until your client is asking how they can reconfigure something in the shipped software when they can't just recompile it to what they need.


> the horror of not-quite-code-but-compiled-into-the-classfile @Annotations!

I really don't get the hate to annotations.

They have saved me lots of hours since 2009 and at close to zero cost. What's not to like?


Since they're compiled into the code, it means you can't change them without recompiling, so they're not actually configuration. But they're not actually code either, so they can't be subclassed or inherited, don't support generics, and have other quirks [1]. Furthermore, they are a sort of explicit notation to make you feel like you're getting 'convention' over 'configuration', but if it were truly convention you wouldn't need them in the first place.

For example, to teach my class how to serialize itself into JSON, I can compile com.fasterxml.jackson annotations into it, but by doing so I've made a particular JSON library a dependency of myproject-datatypes. I'd rather my myproject-controller or some other layer of my application take care of how the data looks over JSON. Luckily Jackson supports an entirely different way [2] of teaching it how to map a class, but not all libraries are so nice.

That is not to say annotations don't have their place. They're good declarative structures, but in my opinion they are used in places where they shouldn't be. This blog post [3] from 2009 accurately describes how I feel about annotations.

[1] http://www.cowtowncoder.com/blog/archives/2009/02/entry_216....

[2] https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInA...

[2] http://naildrivin5.com/blog/2009/03/11/java-annotations-java...


Annotations are data about the code. The fact that you can't change them without recompiling the code is a feature, not a bug.

If you want that kind of flexibility, use external files (e.g. XML) but now the two can get out of sync, which is what is commonly referred to as XML hell.

The rule of thumb is simple: whenever you need to add information about something in your source (class, method, field, package), use an annotation. If you need to add information about something that is not source code (port, host, various sizes, etc...) then use an external file. In particular, if you specify a reference to Java code in your XML, you should use an annotation instead.


> to teach my class how to serialize itself into JSON, I can compile com.fasterxml.jackson annotations into it, but by doing so I've made a particular JSON library a dependency of myproject-datatypes

Right, because at the moment, there is no standard cross-library convention for that. One day, there will be, as there is for serializing to XML:

http://docs.oracle.com/javaee/7/api/javax/xml/bind/annotatio...


What about gson?


It's not a standard, just another implementation.


Thanks for taking time! My views below:

> Since they're compiled into the code, it means you can't change them without recompiling, so they're not actually configuration.

Neither xml was configuration. I cannot remember ever changing xml for deployment. Actually in many ways the whole build jar/war process feels a lot like compiling in Javaland and while I'll happily pick jars or wars apart for troubleshooting deploying the result in production would break multiple guidelines at most places I guess (hope).

> Furthermore, they are a sort of explicit notation to make you feel like you're getting 'convention' over 'configuration', but if it were truly convention you wouldn't need them in the first place.

Partially agree but then again every other framework I have seen demands you do something: put x classes in y folder, subclass another class or implement an interface or something.

Compared to magical directory layout annotations are less well, magic, more explicit.

Compared to subclassing it is more flexible (although I remember enjoying Propel with Symfony 1.)

Compared to marker interfaces? Not sure.

That said once you accept them there is plenty of things you don't have to specify but can override if you want/need to.

Edit: As for your third reference it is out of sync itself:

> The same goes for EJB. I have a class named FooStatelessBean. How about we assume it's a stateless session bean, and it's interface is defined by its public methods? It can then provide FooRemote and FooLocal for me, and I don't need to configure anything or keep three classes in sync

I only use three annotations on such ones: @Named at the class telling the DI framework to pick it up for injection using its name as the name (although I can override it right there and then if I need to.) @Stateless tells it to make a suitable bunch of them and that it is OK to give any of them out to anyone at runtime and @PersistenceContext (at an instance variable) tells me that I want a reference to the ORM layer.

I could easily create a combined annotation for @Named and @Stateless, even naming it @Stateless and just importing my @Stateless instead of the standard (across all Java EE implementations) one.

I guess I could also create a superclass that does all this and subclass it but some day I'll leave the project and another one will have to maintain it.

Could we have picked this out from the name? Yep. Would it be magical? Yep, more so than annotations. Would it tie my hands with regards to naming classes? Yep.


> which was a response to this then-obscure framework called Dropwizard

I sat in with an AMA in NYC with Dave Syer. He said it was inspired by a project he was co-opted to which used Rails.

Not the actual architecture of Rails, mind you, but the "just works", out-of-the-box, no-configuration experience.

Disclosure: I work for Pivotal. So do many of Spring's core committers. There's a lot of feedback from Labs and Cloud R&D into Spring, but they're still a largely self-directed team.


Trying to upvote this because it's good info! But, but, I have one better :)

Spring Boot 1.0 GA Released [1] blog post, says, and links to a Spring Issue SPR-9888:

"It's been 18 months since the original request [2] to "improve containerless web application architectures", that gave birth to Spring Boot, was raised."

The body of the original issue [2] says, midway down:

"I think that Spring's web application architecture can be significantly simplified if it were to provided tools and a reference architecture that leveraged the Spring component and configuration model from top to bottom. Embedding and unifying the configuration of those common web container services within a Spring Container bootstrapped from a simple main() method.

Though there are many frameworks and platforms today that no longer require a container I think inspiration can be drawn most from DropWizard (http://dropwizard.codahale.com/).

Another project I've seen inspired by DropWizard but leveraging Spring is HalfPipe (https://github.com/32degrees/halfpipe). Though I don't think HalfPipe goes far enough. I think to truly provide simplification the entire architecture, wherever reasonable, must be embedded within the Spring container rather than without. Though it does have several other interesting ideas."

[1] https://spring.io/blog/2014/04/01/spring-boot-1-0-ga-release...

[2] https://jira.spring.io/browse/SPR-9888


It could absolutely be both. Dave Syer is not the only person who drove Spring Boot. Phil Webb is the main day-to-day driver, from what I can tell. He's definitely been active in soliciting feedback from Labs Pivots.


> The 'new Spring' is Spring Boot, which was a response to this then-obscure framework called Dropwizard

This is correct, but what pisses me off is that the Spring folks clearly copied Dropwizard, then failed to even mention Dropwizard in their various docs, blogs, talks, etc, which you're thinking is fine. But they DO mention other (less useful) projects as supposed alternatives for Spring Boot, essentially, pretending as if Dropwizard doens't even exist when clearly it's the reason that Spring Boot exists! Shameful.

Spring hails Boot as the new way of doing things, but it's still by no means a clean break for the rest of the Spring ecosystem where programming by XML (or annotations) is still king and the APIs are still a horrible, overcomplicated mess. There's no undoing that.


Each tech it's use.

Annotations are great for class metadata - JPA or beans binding or servlets and filter paths.

Externalizing binding was the kind of nice thing that almost never quite worked right. XML (or YAML because sysads are people too) for configurable parts is ok, but if you need to mix and match services it was never ever needed. The binding API allowed that years before spring style of depencency injection brought madness into the enterprise world and in a extremely better and clean way, using the facilities of the language instead of creating ugly reflective glue that kind of worked


Agreed, I think you and I have very similar views on the JVM/JaveEE/Spring situation.


Spring Boot is very good. I can't imagine writing enterprise Java code without it anymore.


You might want to try out http://bootique.io, it's even better in many aspects


> I feel you haven't taken a look at Java in the enterprise in a long time. > > Spring is considered to be an overloaded bloated mess and Java EE has become lean and mean

I agree with those descriptions, but we have very different experiences of Java in the enterpris. In the companies i work with, EE still means older specifications, and Spring, for all its flaws, comes in as a breath of fresh air.


I'd argue much of that time has passed now. I used to write J2EE code. Now we have frameworks like lagom and dropwizard which make life exponentially better. I'd suggest taking another look.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: