> It would have been much better to utilize environment variables so the only thing that changed between environments was those variables.
I strongly prefer commandline arguments to environment variables: They're more transparent, easier to reason about ("what's running on this server? `ps`... oh, that process there is running in the staging configuration instead of production"), and it saves useless sudos (/proc/<pid>/environ has mod bits 0400, so if the processes you're investigating are running as separate users (and they probably should be), you can't inspect the actual environment that the process has, so you end up sudo'ing to check the environment out when you should have all the information you need in the process list).
If the environment variables are just interpolated into the run script by the deploy and then all passed to the process as arguments, that works too.
Also depending on how those processes are started (as root, from initd, or by hand from shell etc) environment variables might be stripped or incomplete.
Environment variables are kind of like global variables a bit. They are easy to set but feel a little dirty.
And of course if you use libraries or third party package that rely on them, then you don't have a choice.
Often times environmental variables are used inappropriately and make tracking down issues harder due to loss of transparency.
Plus environmental variables are context specific (e.g. user 1 and user 2 might have different ones, or server 1 and server 2 might, or this specific script may have re-defined one(!)).
A good o' fashioned script with the constants defined at the top, commented, and passed into executables on the command line (so tools like ps or taskman can "see" them) is really easy to debug/alter/monitor.
Java and or Oracle's obsession with environmental variables causes more problems than it solves.
Container runtimes like docker make it much easier to inspect the application environment and arguments. A short `docker inspect <id>` will show you everything that is relevant to the app (environment, arguments, and much more).
One thing not to forget is that env variables are inherited by children, which may be relevant if the app forks.
Environment variables make perfect sense for constants that only, you know, vary with the environment. It's very nice to run the same exact code/artifacts on dev, qa, testing and production.
On the other hand, environment variables are useful for things you specifically don't want showing up in ps. If you've got to supply credentials (passwords, tokens, certificates, etc) or anything else that requires a modicum of security, it's much better to pass those in as environment variables rather than command line arguments.
Environment variables are useful in their own situations. For instance, OpenShift signals the open IP and Port number as environment variables. Which is useful when you have a program with an unknown set of command-line parameters. Either that or when you only need a subset of the available command-line parameters.
TL;DR: Java as a language is not bad. The problem with Java is its bloatware ecosystem. Endemic to the Java world are uninstallability, Rube Goldberg machine code, and such heights of over-engineering that they're easily parodied:
I think the over-engineering is an unintended side effect of Java's most attractive features: incredibly stable standard ABIs, portable byte code, fantastic tooling, and a language that makes byzantine abstractions relatively easy to implement without the instability you get in C++ or the unmaintainability you get in dynamic languages. Sometimes you actually do need very high level complex abstractions, so this makes Java a fantastic language for those cases. But those cases are rare. Java makes it easy to build towers of babel that stand up, so they happen.
Java can be fine if you exercise discipline around complexity. Java coders need YAGNI and KISS tattooed on their inner eyelids more than coders in other languages.
Anything can be parodied by exaggeration. One could provide a github parodying any language:
C: pointers-to-pointers-to-functions, type puns, and quasi-opaque "types" with really_long_identifiers_t everywhere (among many other possibilities, and bonus points for numerous reimplementations of basic data structures tailored specifically for different types without significant performance gains)
C++: see Java, but in C++ form; or alternatively larded with metatemplate programming
perl: write any valid perl, because it parodies itself
python: mishmash classes, functions-as-stateful-objects, and n-levels of decorators everywhere, and toss in some metaclass programming for giggles
And so on.
(Note: my favorite language to program in is currently C++, and I'm well aware of the less desirable traits of the language and codebases that exist.)
> TL;DR: Java as a language is not bad. The problem with Java is its bloatware ecosystem.
That's clearly a DR: one of the major headings is "The Java Language Kinda Sucks".
More accurate summary: Java as a platform is not bad, the problem is that the platform is popular enough that lots of less-than-skilled people are using it, and making lots of less-than-ideal choices about how to use it -- including failing to use the tools available in the ecosystem to streamline the experience (and including, as a subset of that, choosing the wrong one of the languages available on the platform, including choosing the Java language itself when its not the best choice.)
Java as a language not bad, but it's not good either. It's solidly mediocre.
IMO the best thing about Java is the interfaces and libraries. When you want to reuse some else's code, just looking at the public methods and their type signatures makes it basically self-explanatory. This is what I miss most when I'm working with dynamic languages like JS, Ruby and Python.
I think that is both fair and unfair. Fair because what you say is absolutely true. But unfair because if you stick to the non-bloatware libraries, Java is very good, very fast and surprisingly productive. For me, that stack is Guava, Jetty, Jersey, Gson, Guice.
I believe though that you can make poor library choices in any language & framework. With languages that have been around for a while, there are a lot of bad libraries...
My company is doing most of these things (except it's more complex because we're polylingual, and don't use Java for web apps), but Java still sucks.
The reason it sucks has more to do with the language and the culture that has grown up around it, than the mechanics of building and deploying that this article talks about. These mechanics have to be solved for most languages. They're table stakes; mostly just a basic level of usability from which you can start to measure against other things.
If I had to name the single worst thing about Java, it would be the tendency for business code to degenerate into a 1:1:1 ratio of interface:class:public-method. For any significant piece of logic, it ends up living in a class on its own, with its dependencies injected either via constructor parameters or method parameters. Whether the constructor or method is used doesn't really matter, unless the method is to be called many times, in which case the constructor acts as a kind of partial application. And of course the class it lives in needs to be the only implementation of a corresponding interface, which only has a single method, the method in question. All other interesting methods this method calls must in turn be called via single-method interfaces, with these interfaces injected via parameters, one way or another.
The cause of this is a religion around a particular style of testing. The development driven by the need to create tests for everything leads to code that has very little cohesion, very little structure, and most closely resembles 80s procedural code, but with vastly more ceremony. Code is hard to browse and read because the link between method call and implementation is hidden in a runtime indirection via an interface reference. This lack of legibility in turn encourages doing more work in these methods (albeit broken out into private methods), and instead of an OO decomposition of the problem, you end up with a poorly factored procedural decomposition.
The biggest symptom is classes with names that are close anagrams of their primary method. For example: StaleJobsCleaner.cleanStaleJobs, StaleJobsFinder.findStaleJobs, JobDeleter.deleteJob, JobDepedencyFinder.findJobDependencies, etc.
If I had to name the single worst thing about Java, it would be the tendency for business code to degenerate into a 1:1:1 ratio of interface:class:public-method.
I agree. It's ugly and hard to maintain. Most enterprise Java usages of "design patterns" are unnecessary cruft. This is where I step back and say, "what you really want is a function".
The argument I tend to make for functional programming is that it only has two design patterns: noun (immutable data) and verb (referentially transparent function). And even though it's very rare that pure functional programming is used, mutable references (e.g. TVars for STM, reference cells like IORefs) are just "noun-plus" and actions (e.g. m a for some monad m) are just "verb-plus". It's easier (read: possible) to reason about the complex stuff if the simple stuff is done on a sound foundation.
The reason it sucks has more to do with the language and the culture that has grown up around it
I think the culture is a far bigger issue than the language. Java is good when used properly, especially with the Java 8 updates. I don't think it's fair to blame Java for the culture issues. During the 90s and early 2000s, an "enterprise" culture formed using Java. However, that culture used Java because it was the new, popular language at the time. If Go or C# or Scala was released back then and had the same position as Java, that culture would've also produced very bad code in those languages.
Fortunately, the Java culture seems to be changing. There is now a more noticeable division between the old style "enterprise" Java code and newer, modern, and simpler ways of using Java.
These days it's important for a developer to know one static language and one dynamic language well. And that doesn't mean just knowing the syntax. It also includes learning the idioms and best practices in those two languages. The actual combination doesn't matter. It can be Java/JavaScript, C#/Ruby, C++/Python, Haskell/Closure, etc. For example, I focus mostly on Java and JavaScript because I use one for server and the other for front end. My JS knowledge made it easy for me to understand the lambda addition in Java 8. My Java knowledge allows me to understand the advantages of optional typing such as Typescript and Flow.
I've seen Java-only developers struggle with lambda in Java 8 because they've never written functional style code. And I've seen JS-only developers fail to understand how optional typing could be helpful because they've never seen the power of static typing in IDEs.
I used to dabble in languages, but I don't have time for that anymore. I've found that focusing and keeping track of changes in Java and JS are enough for me. JS is changing with ECMAScript 6 and includes good ideas from other dynamic languages such as Python. I'm hoping that Java starts to get some of the best ideas from Haskell and Scala.
Yes, Java is a passable language, even if not something I enjoy. However, the programming culture is a big problem, because of the tendency to overengineer in general and overdesign class hierarchies in particular.
The Android project I work on was started by an experienced Java team and has an interface for almost every class, uses injection and had a customized UI framework that was a nightmare of interfaces. Some of that has been cleaned up meanwhile, but those initial decision are hurting maintainabity and performance even now.
"For any significant piece of logic, it ends up living in a class on its own, with its dependencies injected either via constructor parameters or method parameters."
And I was worried I was the only one who thought this was crazy!
In most python frameworks, like django, when you want to call some service, you import some static class or singleton. It is simple and straightforward. If the framework wants to allow you to swap in different implementation classes, then it will define a singleton or static class with a clear API that then dispatches to the specific implementation class based on your global settings. Or, if you want to override the default implementation on the spot, you can just invoke the implementation class you want directly.
So in django, I just do:
from django.core.cache import cache
cache.get('my_key')
Voila! That's all the code I need, and it works great. I can easily swap in memcached or a file cache or a local memory cache or whatever. It is straightforward and easy to debug. If I am wondering why the wrong implementation service is being used, I can usually step through with a debugger right at the point it is being called and figure out what is going on. If you I am writing tests, I either use different settings or monkey patch the static class in my setup and tear down functions.
In most java frameworks, your classes are supposed to either accept the service via a constructor, or have it injected into your class via Guice or Spring. This adds a whole new level of complication and verbosity, and means things break far away from when you are using them. I know people swear by dependency injection, but I really don't get it, I have never found it to be a better pattern than the django pattern.
That seems excessive to me - at least, I don't see how SOLID principles necessary lead to that outcome even if strictly followed. What is it about those principles that prevent classes/interfaces that have a handful of related methods, like a StaleJobsService or whatever?
For all of the OO patterns, they have a common rule that says to not use them unless they actually solve a problem / code smell.
> The biggest symptom is classes with names that are close anagrams of their primary method. For example: StaleJobsCleaner.cleanStaleJobs, StaleJobsFinder.findStaleJobs, JobDeleter.deleteJob, JobDepedencyFinder.findJobDependencies, etc.
This issue has nothing to do with enterprise style, and everything to do with the fact that that's how "functional" programming is done in Java. What is really wanted is a first-class function `x`, but that doesn't exist. So instead an `Xer` SAM interface is summoned into existence that has that `x`.
Sadly, the unit-test everything mentality leads to a lot of problems in other languages as well. Often times, it provides little to no benefit to anyone while adding complexity to code and changing design for the worse. In a typical application, there are few methods that really benefit from unit tests and even fewer bugs prevented and/or caught by them yet still I see designs being modified to accommodate unit testing while other types of testing that could be useful are generally ignored. Even refactoring, which is the real purpose of unit testing, is generally not much helped by it.
I'm confused about the title of this. I've never heard an argument that went "Java sucks because you are forced to (thing on this list)".
It's always been "Java sucks because it lacks (thing it certainly lacks)" or "Java sucks because it forces you to (thing it certainly forces you to do)", or, closest to this article, "Java sucks because it encourages you to (bad practice, such as those mentioned in this article)". None of these does the article refute.
I've seen places that used Java, and had most of these, and places that used Java and had little of it. I've seen places that used other languages that had all of these, and other places that used those same other languages that had none of it. This seems kind of orthogonal, and as such a bit of a strawman; is it in response to some specific arguments I've just not heard?
Java doesn't suck, not at all. I still find it to be the most productive language for developing systems big and small, mostly because it's well-understood, the pitfalls and traps are well-known, and the community is extensive and supportive, for the most part.
Java got a bad rep because in the late 90's, enterprises hired anyone who had the word "Java" on their resume, with no real assessment of their actual proficiency in the language or programming skills. As a result, there was probably more bad code written in Java than any other language in history (including VB- you just can't write as much bad code in VB as you can in Java if you really (don't) know what you're doing).
Much of this bad code ended up running flaky enterprise systems. So much bad code ended up in closed-source products (like Websphere, and like many JDBC drivers) that were sold to people who didn't really understand technology (but knew Java was sexy!) that Java itself got a bad name.
No, the language isn't perfect. But with all the lessons learned, and with the great developments in Java since Oracle took over (I cannot believe I wrote and believe that now), I contend it's perhaps the single best language for general purpose software in 2014.
The things James talks about in this article are all big problems that have less to do with the language than with the poor development practices that became so endemic to the community as a result of the rush to hire anyone with a pulse to be a Java programmer 15 years ago.
It's hard to imagine someone who wouldn't be turned off by the tone of this article. Kicker is the quote at the end: "If you are in a typical enterprise then maybe you are lucky and already doing most of this." I went looking for sarcasm twice and still couldn't find it.
Java enterprise shops are not using git and JRebel and Play Framework and continuous deployments and 2 week sprints and reactive development refactoring boilerplate into lambdas.
Nor are they "mocking" amazon web services for ease of local developer testing. And a request to your boss to write the next services layer in "Kotlin" is likely to be met with the slap it deserves.
The problem is not necessarily with Java or the JVM as a technology, but rather the "Java shop culture"[1] that often goes along with it. Although I would call it "Enterprise shop culture" instead, since it seems to stem from people who (sometimes unknowingly) perpetuate big company politics and a consultant attitude, even in startups.
I've found "Java shop culture" in non-Java places as well--C#/.NET for example.
> The blocking model limits parallelism, horizontal scalability, and the number of concurrent push connections.
[citation needed]
Seriously, where are the benchmarks? I see lots of claims of threads being slow and heavy (see also every time green threads comes up), yet... they are not. And every benchmark I've seen shows that, gasp, kernals are really fucking good. And library-of-the-week's greenthread kernel is not.
So if you're using NIO instead of blocking IO threads, well, say goodbye to 25-30% of your throughput. But at least you got to feel all clever using unnecessarily complex async programming, so that's worth it, right?
Before down-voting and replying, please, copy and paste examples from the Rosetta Code website, which would prove my statements to be incorrect.
1. Syntactic noise.
2. Verbosity.
These gives us lots of cryptic lines of code, full of design patterns and other kluges. This is also related to the two below:
3. Over-abstraction.
4. Everything must be a member of a class.
These two are simple and straightforward. These few pages long stack traces is a result of these unnecessary method calls.
5. Static typing makes our code safe.
This nonsense results in even more lines of cryptic code ("generics") and even longer stack traces.
I am not talking about XML configs, over-"engineered" components (beans, servlets, etc.)
Here is a lemma: Any algorithm (at least those represented on the Rosetta Code website) could be coded with less lines of code, less words per line, less "special symbols" (with much better readability) and executed with less memory waste (this one excluding scripting languages for obvious reasons) in any other mainstream language. Period.
Sure, Java does not suck. It is stupid us, who are unable to "get it".
Not that I typically defend Java, but I think that (going by your Rosetta Code algorithm comparison test) Java fairs well against a few mainstream languages:
Now, this isn't entirely fair; one of C++'s faults/benefits is that depending on your shop and/or framework/libraries, "idiomatic" C++ can vary greatly. Template heavy C++ tends to look like vomit. C++ that uses Boost will typically be more unpleasant to look at than C++ that uses Qt (imho anyway).
Java really comes into it's own horrible self when you get beyond mere algorithm implementation. A quicksort method in Java will tend to be relatively fine, but for projects larger than that it becomes idiomatic to make your java code a real mess.
I maintain 2 semi-big Play 2 web services (written in Java, not Scala) at work, and I just hate it.
- SBT is super slow compared to maven
- Compiling a play 2 app is slow
- IDE integration is quite bad
After a year, I would definitely not recommend Play 2, or SBT on a Java project.
My choice when using Java today would be Dropwizard, although I haven't deployed anything in production using it, I tested it for a couple hours, and I think it's the best combination of libraries.
One thing I definitely agree on, is to use Docker if possible. We use it for almost everything at work, and it improves our deployment speed, it gives us more flexibility and local/CI testing is now super easy. In case you deploy with Docker, using only environment variables for configuration is great, that way you can control the configuration directly via the docker command line. With Java a good library for this use case is Typesafe's config, which can automatically use environment variables.
SBT is probably the best example of the total immaturity of the Scala community in terms of real-world engineering. Hey, we're building for the JVM, we've got Maven, it's arguably the best solution in any language for a very difficult problem that has stopped entire language ecosystems in their tracks. Let's rewrite it, from scratch, using unproven concepts! And put 'simple' in the title!
Afterwards, we'll call XML ugly and claim to be more 'functional', without even noticing that Maven's pom format is actually a nested s-expression structure that happens to use angle brackets.
In the previous project I worked in, we switched to Dropwizard for a lot of services that now run in production. We were already using Jersey, Guava, etc., but Dropwizard gives some nice extra glue and standardized our configuration and gave us a standardized way to instrument services (via metrics). It can really recommend it for RESTful services.
Also, there is a nice Maven plugin that creates Ubuntu packages from Dropwizard projects:
Your experience around the performance of SBT (and possibly, by extension, Play compilation) runs very much counter to my experience. I have found SBT to be much faster than Maven (thanks largely to the console). There may be something wrong with your project that is causing it to build so slowly. Are you seeing the compilation go very slowly or is it more issues with artifact resolution?
Play 2 really is a different framework than Play 1, which was what brought Play its fame. If you like Play 1, try the Ninja Framework. It has a cheesy name but it has the super fast development cycle that Play 1 used to have.
It is only tangentially related, but I recommend this video from Brian Geotz, a Java language architect. He breaks down the challenges of adding features to the language, in a room full of Clojure devs no less. Worth a watch: https://www.youtube.com/watch?v=2y5Pv4yN0b0
> If your app needs a relational database then use an in-memory db like hsql or cloud services like Heroku Postgres, RDS, Redis Labs, etc. However one risk with most in-memory databases is that they differ from what is used in production. JPA / Hibernate try to hide this but sometimes bugs crop up due to subtle differences. So it is best to mimic the production services for developers even down to the version of the database.
The idea that you can develop locally or test against a different type of database then what you are (or will be) using in production is silly. I don't just think it "sometimes" is a bad idea, I reject it outright. You should always be using the exact same database (type and version).
For cloud deployments most XaaS providers have cheap or free dev tiers. For local development it's easy to use VMs. For any project that requires external resources (Postgres, Redis, RabbitMQ, etc) I have a VM that gets spun up via Vagrant[1]. Just "vagrant up" and all external resources required by the app should be available.
> So first… Use a build tool. It doesn’t matter if you choose Ant + Ivy, Maven, Gradle, or sbt. Just pick one and use it to automatically pull your dependencies from Maven Central or your own Artifactory / Nexus server. With WebJars you can even manage your JavaScript and CSS library dependencies. Then get fancy by automatically denying SCM check-ins that include Jar files.
Though I agree that it's a good idea to have dependencies externalized, it's not always possible. Some libraries (ex: third party JARs) are not available in public Maven repos and not everyone has a private one setup. In those situations it's fine to check in the JAR into the project itself.
I like the approach outlined by Heroku for dealing with unmanaged dependencies[2]. You declare them normally in your pom.xml but also include the path to a local directory (checked into SCM) with the JAR files. Anybody that clones your repo should be able to build the project with no manual steps. Works great!
I think an important lesson for web application development—mentioned in the article—is keeping the server stateless, moving state into the client, and using a real middleware like Redis for the session cache.
I'm a .NET developer and I love C# & Visual Studio but have worked some with Java. Most of his arguments sounded to me like- "Just do complex-sounding long list of steps, it's easy!" Java development seems like a massive pain, and too much time not actually spent on development.
>Clojure: The lack of some OO constructs makes managing a large code base challenging
I would be intrested in what his problem is. The only thing that I can think of is subtyping and Im not sure how subtyping helps managing organisation.
Clojures namespacing is pretty nice, it might be a bit to complicated but it does everything you need.
all of his points except for one are related to the jvm in general, which most people agree doesn't suck, and then when it is time to address java he just says "scala, clojure.. are great" Yes, thats the point. The JVM is well liked, but Java as a language is not, and I don't think he did much to change anyones opinion.
Java itself was once so popular that a completely unrelated programming language, javascript, had java in its name to ride the coat-tails of its popularity.
The culture and behaviors that have grown up around it though make it easy for people to fall into holes. (Both technical and non-technical, e.g. hiring culture)
It's like if a minefield existed via the path of Java and people said "There's no way through this minefield." And another retorts "Of course there is a path! Just go through it carefully, learn the topology, and it's just as fast as sprinting across an open meadow."
One of the few big problems I have with Java is that you can't use anonymous classes as real closures like it intuitively looks like you should be able to.
[+] [-] philsnow|11 years ago|reply
I strongly prefer commandline arguments to environment variables: They're more transparent, easier to reason about ("what's running on this server? `ps`... oh, that process there is running in the staging configuration instead of production"), and it saves useless sudos (/proc/<pid>/environ has mod bits 0400, so if the processes you're investigating are running as separate users (and they probably should be), you can't inspect the actual environment that the process has, so you end up sudo'ing to check the environment out when you should have all the information you need in the process list).
If the environment variables are just interpolated into the run script by the deploy and then all passed to the process as arguments, that works too.
[+] [-] rdtsc|11 years ago|reply
Environment variables are kind of like global variables a bit. They are easy to set but feel a little dirty.
And of course if you use libraries or third party package that rely on them, then you don't have a choice.
[+] [-] Someone1234|11 years ago|reply
Often times environmental variables are used inappropriately and make tracking down issues harder due to loss of transparency.
Plus environmental variables are context specific (e.g. user 1 and user 2 might have different ones, or server 1 and server 2 might, or this specific script may have re-defined one(!)).
A good o' fashioned script with the constants defined at the top, commented, and passed into executables on the command line (so tools like ps or taskman can "see" them) is really easy to debug/alter/monitor.
Java and or Oracle's obsession with environmental variables causes more problems than it solves.
[+] [-] wereHamster|11 years ago|reply
One thing not to forget is that env variables are inherited by children, which may be relevant if the app forks.
[+] [-] bkeroack|11 years ago|reply
See also: http://12factor.net/
[+] [-] curun1r|11 years ago|reply
[+] [-] j_baker|11 years ago|reply
[+] [-] unknown|11 years ago|reply
[deleted]
[+] [-] api|11 years ago|reply
https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...
I think the over-engineering is an unintended side effect of Java's most attractive features: incredibly stable standard ABIs, portable byte code, fantastic tooling, and a language that makes byzantine abstractions relatively easy to implement without the instability you get in C++ or the unmaintainability you get in dynamic languages. Sometimes you actually do need very high level complex abstractions, so this makes Java a fantastic language for those cases. But those cases are rare. Java makes it easy to build towers of babel that stand up, so they happen.
Java can be fine if you exercise discipline around complexity. Java coders need YAGNI and KISS tattooed on their inner eyelids more than coders in other languages.
[+] [-] Iftheshoefits|11 years ago|reply
C: pointers-to-pointers-to-functions, type puns, and quasi-opaque "types" with really_long_identifiers_t everywhere (among many other possibilities, and bonus points for numerous reimplementations of basic data structures tailored specifically for different types without significant performance gains)
C++: see Java, but in C++ form; or alternatively larded with metatemplate programming
perl: write any valid perl, because it parodies itself
python: mishmash classes, functions-as-stateful-objects, and n-levels of decorators everywhere, and toss in some metaclass programming for giggles
And so on.
(Note: my favorite language to program in is currently C++, and I'm well aware of the less desirable traits of the language and codebases that exist.)
[+] [-] dragonwriter|11 years ago|reply
That's clearly a DR: one of the major headings is "The Java Language Kinda Sucks".
More accurate summary: Java as a platform is not bad, the problem is that the platform is popular enough that lots of less-than-skilled people are using it, and making lots of less-than-ideal choices about how to use it -- including failing to use the tools available in the ecosystem to streamline the experience (and including, as a subset of that, choosing the wrong one of the languages available on the platform, including choosing the Java language itself when its not the best choice.)
[+] [-] kyllo|11 years ago|reply
IMO the best thing about Java is the interfaces and libraries. When you want to reuse some else's code, just looking at the public methods and their type signatures makes it basically self-explanatory. This is what I miss most when I'm working with dynamic languages like JS, Ruby and Python.
[+] [-] justinsb|11 years ago|reply
I believe though that you can make poor library choices in any language & framework. With languages that have been around for a while, there are a lot of bad libraries...
[+] [-] barrkel|11 years ago|reply
The reason it sucks has more to do with the language and the culture that has grown up around it, than the mechanics of building and deploying that this article talks about. These mechanics have to be solved for most languages. They're table stakes; mostly just a basic level of usability from which you can start to measure against other things.
If I had to name the single worst thing about Java, it would be the tendency for business code to degenerate into a 1:1:1 ratio of interface:class:public-method. For any significant piece of logic, it ends up living in a class on its own, with its dependencies injected either via constructor parameters or method parameters. Whether the constructor or method is used doesn't really matter, unless the method is to be called many times, in which case the constructor acts as a kind of partial application. And of course the class it lives in needs to be the only implementation of a corresponding interface, which only has a single method, the method in question. All other interesting methods this method calls must in turn be called via single-method interfaces, with these interfaces injected via parameters, one way or another.
The cause of this is a religion around a particular style of testing. The development driven by the need to create tests for everything leads to code that has very little cohesion, very little structure, and most closely resembles 80s procedural code, but with vastly more ceremony. Code is hard to browse and read because the link between method call and implementation is hidden in a runtime indirection via an interface reference. This lack of legibility in turn encourages doing more work in these methods (albeit broken out into private methods), and instead of an OO decomposition of the problem, you end up with a poorly factored procedural decomposition.
The biggest symptom is classes with names that are close anagrams of their primary method. For example: StaleJobsCleaner.cleanStaleJobs, StaleJobsFinder.findStaleJobs, JobDeleter.deleteJob, JobDepedencyFinder.findJobDependencies, etc.
[+] [-] michaelochurch|11 years ago|reply
I agree. It's ugly and hard to maintain. Most enterprise Java usages of "design patterns" are unnecessary cruft. This is where I step back and say, "what you really want is a function".
The argument I tend to make for functional programming is that it only has two design patterns: noun (immutable data) and verb (referentially transparent function). And even though it's very rare that pure functional programming is used, mutable references (e.g. TVars for STM, reference cells like IORefs) are just "noun-plus" and actions (e.g. m a for some monad m) are just "verb-plus". It's easier (read: possible) to reason about the complex stuff if the simple stuff is done on a sound foundation.
[+] [-] cpprototypes|11 years ago|reply
I think the culture is a far bigger issue than the language. Java is good when used properly, especially with the Java 8 updates. I don't think it's fair to blame Java for the culture issues. During the 90s and early 2000s, an "enterprise" culture formed using Java. However, that culture used Java because it was the new, popular language at the time. If Go or C# or Scala was released back then and had the same position as Java, that culture would've also produced very bad code in those languages.
Fortunately, the Java culture seems to be changing. There is now a more noticeable division between the old style "enterprise" Java code and newer, modern, and simpler ways of using Java.
These days it's important for a developer to know one static language and one dynamic language well. And that doesn't mean just knowing the syntax. It also includes learning the idioms and best practices in those two languages. The actual combination doesn't matter. It can be Java/JavaScript, C#/Ruby, C++/Python, Haskell/Closure, etc. For example, I focus mostly on Java and JavaScript because I use one for server and the other for front end. My JS knowledge made it easy for me to understand the lambda addition in Java 8. My Java knowledge allows me to understand the advantages of optional typing such as Typescript and Flow.
I've seen Java-only developers struggle with lambda in Java 8 because they've never written functional style code. And I've seen JS-only developers fail to understand how optional typing could be helpful because they've never seen the power of static typing in IDEs.
I used to dabble in languages, but I don't have time for that anymore. I've found that focusing and keeping track of changes in Java and JS are enough for me. JS is changing with ECMAScript 6 and includes good ideas from other dynamic languages such as Python. I'm hoping that Java starts to get some of the best ideas from Haskell and Scala.
[+] [-] blub|11 years ago|reply
The Android project I work on was started by an experienced Java team and has an interface for almost every class, uses injection and had a customized UI framework that was a nightmare of interfaces. Some of that has been cleaned up meanwhile, but those initial decision are hurting maintainabity and performance even now.
[+] [-] sbochins|11 years ago|reply
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom...
[+] [-] pfitzsimmons|11 years ago|reply
And I was worried I was the only one who thought this was crazy!
In most python frameworks, like django, when you want to call some service, you import some static class or singleton. It is simple and straightforward. If the framework wants to allow you to swap in different implementation classes, then it will define a singleton or static class with a clear API that then dispatches to the specific implementation class based on your global settings. Or, if you want to override the default implementation on the spot, you can just invoke the implementation class you want directly.
So in django, I just do:
Voila! That's all the code I need, and it works great. I can easily swap in memcached or a file cache or a local memory cache or whatever. It is straightforward and easy to debug. If I am wondering why the wrong implementation service is being used, I can usually step through with a debugger right at the point it is being called and figure out what is going on. If you I am writing tests, I either use different settings or monkey patch the static class in my setup and tear down functions.In most java frameworks, your classes are supposed to either accept the service via a constructor, or have it injected into your class via Guice or Spring. This adds a whole new level of complication and verbosity, and means things break far away from when you are using them. I know people swear by dependency injection, but I really don't get it, I have never found it to be a better pattern than the django pattern.
[+] [-] tunesmith|11 years ago|reply
For all of the OO patterns, they have a common rule that says to not use them unless they actually solve a problem / code smell.
[+] [-] jdmichal|11 years ago|reply
This issue has nothing to do with enterprise style, and everything to do with the fact that that's how "functional" programming is done in Java. What is really wanted is a first-class function `x`, but that doesn't exist. So instead an `Xer` SAM interface is summoned into existence that has that `x`.
[+] [-] alasdair_|11 years ago|reply
Most of the enterprise Java code that I have seen uses annotations for dependency injection. This is common in both Spring and JEE.
[+] [-] joesmo|11 years ago|reply
[+] [-] lostcolony|11 years ago|reply
It's always been "Java sucks because it lacks (thing it certainly lacks)" or "Java sucks because it forces you to (thing it certainly forces you to do)", or, closest to this article, "Java sucks because it encourages you to (bad practice, such as those mentioned in this article)". None of these does the article refute.
I've seen places that used Java, and had most of these, and places that used Java and had little of it. I've seen places that used other languages that had all of these, and other places that used those same other languages that had none of it. This seems kind of orthogonal, and as such a bit of a strawman; is it in response to some specific arguments I've just not heard?
[+] [-] michaelvkpdx|11 years ago|reply
Java got a bad rep because in the late 90's, enterprises hired anyone who had the word "Java" on their resume, with no real assessment of their actual proficiency in the language or programming skills. As a result, there was probably more bad code written in Java than any other language in history (including VB- you just can't write as much bad code in VB as you can in Java if you really (don't) know what you're doing).
Much of this bad code ended up running flaky enterprise systems. So much bad code ended up in closed-source products (like Websphere, and like many JDBC drivers) that were sold to people who didn't really understand technology (but knew Java was sexy!) that Java itself got a bad name.
No, the language isn't perfect. But with all the lessons learned, and with the great developments in Java since Oracle took over (I cannot believe I wrote and believe that now), I contend it's perhaps the single best language for general purpose software in 2014.
The things James talks about in this article are all big problems that have less to do with the language than with the poor development practices that became so endemic to the community as a result of the rush to hire anyone with a pulse to be a Java programmer 15 years ago.
[+] [-] tacos|11 years ago|reply
Java enterprise shops are not using git and JRebel and Play Framework and continuous deployments and 2 week sprints and reactive development refactoring boilerplate into lambdas.
Nor are they "mocking" amazon web services for ease of local developer testing. And a request to your boss to write the next services layer in "Kotlin" is likely to be met with the slap it deserves.
[+] [-] bkeroack|11 years ago|reply
I've found "Java shop culture" in non-Java places as well--C#/.NET for example.
1. http://michaelochurch.wordpress.com/2012/04/13/java-shop-pol...
[+] [-] kllrnohj|11 years ago|reply
[citation needed]
Seriously, where are the benchmarks? I see lots of claims of threads being slow and heavy (see also every time green threads comes up), yet... they are not. And every benchmark I've seen shows that, gasp, kernals are really fucking good. And library-of-the-week's greenthread kernel is not.
The author then says you should use NIO. But, well, NIO is slower than blocking IO. A lot slower: http://www.mailinator.com/tymaPaulMultithreaded.pdf
So if you're using NIO instead of blocking IO threads, well, say goodbye to 25-30% of your throughput. But at least you got to feel all clever using unnecessarily complex async programming, so that's worth it, right?
[+] [-] dschiptsov|11 years ago|reply
Before down-voting and replying, please, copy and paste examples from the Rosetta Code website, which would prove my statements to be incorrect.
1. Syntactic noise. 2. Verbosity. These gives us lots of cryptic lines of code, full of design patterns and other kluges. This is also related to the two below: 3. Over-abstraction. 4. Everything must be a member of a class. These two are simple and straightforward. These few pages long stack traces is a result of these unnecessary method calls. 5. Static typing makes our code safe. This nonsense results in even more lines of cryptic code ("generics") and even longer stack traces.
I am not talking about XML configs, over-"engineered" components (beans, servlets, etc.)
Here is a lemma: Any algorithm (at least those represented on the Rosetta Code website) could be coded with less lines of code, less words per line, less "special symbols" (with much better readability) and executed with less memory waste (this one excluding scripting languages for obvious reasons) in any other mainstream language. Period.
Sure, Java does not suck. It is stupid us, who are unable to "get it".
[+] [-] Crito|11 years ago|reply
Rosetta Code's Java Quicksort: http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Jav...
Not great, that first line is a wreck in particular, but not terrible either.
Compare that to this though: http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#C.2...
Really quite ugly looking code.
Now, this isn't entirely fair; one of C++'s faults/benefits is that depending on your shop and/or framework/libraries, "idiomatic" C++ can vary greatly. Template heavy C++ tends to look like vomit. C++ that uses Boost will typically be more unpleasant to look at than C++ that uses Qt (imho anyway).
Java really comes into it's own horrible self when you get beyond mere algorithm implementation. A quicksort method in Java will tend to be relatively fine, but for projects larger than that it becomes idiomatic to make your java code a real mess.
[+] [-] Sphax|11 years ago|reply
My choice when using Java today would be Dropwizard, although I haven't deployed anything in production using it, I tested it for a couple hours, and I think it's the best combination of libraries.
One thing I definitely agree on, is to use Docker if possible. We use it for almost everything at work, and it improves our deployment speed, it gives us more flexibility and local/CI testing is now super easy. In case you deploy with Docker, using only environment variables for configuration is great, that way you can control the configuration directly via the docker command line. With Java a good library for this use case is Typesafe's config, which can automatically use environment variables.
[+] [-] jbooth|11 years ago|reply
Afterwards, we'll call XML ugly and claim to be more 'functional', without even noticing that Maven's pom format is actually a nested s-expression structure that happens to use angle brackets.
[+] [-] microtonal|11 years ago|reply
Also, there is a nice Maven plugin that creates Ubuntu packages from Dropwizard projects:
https://github.com/reines/dropwizard-debpkg-maven-plugin
[+] [-] eeperson|11 years ago|reply
[+] [-] ww520|11 years ago|reply
[+] [-] shadeless|11 years ago|reply
[+] [-] serve_yay|11 years ago|reply
[+] [-] aligajani|11 years ago|reply
[+] [-] sehrope|11 years ago|reply
The idea that you can develop locally or test against a different type of database then what you are (or will be) using in production is silly. I don't just think it "sometimes" is a bad idea, I reject it outright. You should always be using the exact same database (type and version).
For cloud deployments most XaaS providers have cheap or free dev tiers. For local development it's easy to use VMs. For any project that requires external resources (Postgres, Redis, RabbitMQ, etc) I have a VM that gets spun up via Vagrant[1]. Just "vagrant up" and all external resources required by the app should be available.
> So first… Use a build tool. It doesn’t matter if you choose Ant + Ivy, Maven, Gradle, or sbt. Just pick one and use it to automatically pull your dependencies from Maven Central or your own Artifactory / Nexus server. With WebJars you can even manage your JavaScript and CSS library dependencies. Then get fancy by automatically denying SCM check-ins that include Jar files.
Though I agree that it's a good idea to have dependencies externalized, it's not always possible. Some libraries (ex: third party JARs) are not available in public Maven repos and not everyone has a private one setup. In those situations it's fine to check in the JAR into the project itself.
I like the approach outlined by Heroku for dealing with unmanaged dependencies[2]. You declare them normally in your pom.xml but also include the path to a local directory (checked into SCM) with the JAR files. Anybody that clones your repo should be able to build the project with no manual steps. Works great!
[1]: https://www.vagrantup.com/
[2]: https://devcenter.heroku.com/articles/local-maven-dependenci...
[+] [-] applecore|11 years ago|reply
[+] [-] ohitsdom|11 years ago|reply
[+] [-] breischl|11 years ago|reply
My TL;DR summary of that article is "Java doesn't suck, as long as you use enough tools, libraries and workarounds to avoid actually using Java."
[+] [-] nickik|11 years ago|reply
I would be intrested in what his problem is. The only thing that I can think of is subtyping and Im not sure how subtyping helps managing organisation.
Clojures namespacing is pretty nice, it might be a bit to complicated but it does everything you need.
[+] [-] ibebrett|11 years ago|reply
[+] [-] dlwj|11 years ago|reply
The culture and behaviors that have grown up around it though make it easy for people to fall into holes. (Both technical and non-technical, e.g. hiring culture)
It's like if a minefield existed via the path of Java and people said "There's no way through this minefield." And another retorts "Of course there is a path! Just go through it carefully, learn the topology, and it's just as fast as sprinting across an open meadow."
[+] [-] _lce0|11 years ago|reply
[+] [-] jimmaswell|11 years ago|reply