I do a lot of Java coding and I enjoy it. I admit that there is a lot of typing, often a lot of boilerplate and getting even simple tasks done can involve too much work. Most of the tools that try to fix these problems trade one moment saved for another lost. Maven's XML based configuration file is a good example: Thank you for making my project easier to manage and I won't forget that you made me edit XML to do so.
These are the things that you live with, these are the things you trade for using a language that thinks it's finishing what C++ started; a language that is loved equally by mammoth corporate IT departments, mammoth corporate IT vendors and mammoth corporate IT consultants. What you don't need to tolerate is this tendency to crazily over-engineer even the simplest solutions.
We've all Seen It: The Factory Factory
It's a long-standing joke because we've all seen it and we've all grown to hate it: "The Abstract Factory Pattern," euphemistically referred to as "The Factory Factory". As envisioned by the Gang of Four, this is a handy way to create families of related objects without needing to know much about their concrete implementations. It's a clever idea and when we see it used in a library or if we end up coding something like this ourselves, our reaction should be "Yes, very clever!" So why are we so often complaining?
I think we're having reactions like this because when we look at an API that does this, it's often far too complex; it's overkill. If you're using a library and you are noticing this pattern, as often as not it turns out that the author of said library is doing it wrong: there's a factory that returns a factory that returns one implementation. One factory is a bad sign, that the one factory has only one implementation to build tells us that this pattern isn't applicable. If you are working with a library that uses this pattern and it's not saving you a headache by hiding some obnoxious suite of not quite interchangeable objects, then this pattern is wasting your time and effort for absolutely no reward.
In case that you don't do a lot of Java coding and have no idea what I'm talking about, take a look at this bit of Java code that does just this: one abstract factory extended by two implementation factories. I'd have written example code myself but even that would be too much work. Note how silly and pointless this example is: it needs to be that way because if it were more true-to-life, you'd have a really hard time following it. Here's a more real-life example, notice how boring and co-dependent these classes are; this is the kind of problem this pattern is trying to solve.
I blame Sun, I blame your boss's boss, I blame unimaginative managers everywhere who looked at Sun's example code and thought "Yes! Our code needs to look like this too!" Because it doesn't and 99% of the time it really shouldn't. If you're starting a new project and you decide that the first step is to draw a really big UML diagram and then try to isolate key places to implement this or that design pattern then you, my friend, are also part of the problem.
I Point the Finger at You, I Have Already Pointed it At Myself
It could be that everyone my age, or everyone who had a similar career path, or everyone that read documentation from Sun when they were too young to know how horrible such documentation actually is have all ended up making these same mistakes. I toiled away on a project for four long years that heavily leveraged the now universally despised EJB 2 specification. I myself have drawn out huge UML charts that ended up being printed as a shockingly large sheaf of pages that were then taped to a whiteboard. I personally have to live with the shame of a very clear and vivid memory wherein I circled objects that covered nearly four sheets of this paper and wrote, in my own hand and with a clear-head: "A good candidate for an abstract factory! :)"
Eventually I realized that the emoticon was mocking me. Laughing at my presumptuousness, laughing at my premature optimization. Laughing at my fear of re-factoring.
Premature Optimization and Re-factoring
That's what I was doing, I was trying to solve a problem before I even had it. Before I had even written one line of code, I was trying to decide how the pieces of the puzzle fit together. It was simply too much detail too early on. No one ever gets it right the first time, what made me think that I was so special?
I'm not saying it's not worth it to think ahead and to plan, but be mindful that no one has perfect knowledge of their problem space and just as things that seem simple can turn out to be complicated, sometimes problems that seem really hard end up solving themselves. Maybe that's just how business logic works: you talk to the right person and it turns out that you had it wrong the whole time.
Moderation in All Things
I'm advocating an approach where you're mindful of these design patterns but you keep them in the background. When you have working code that is starting to get messy, or when someone on your team has been banging their head on a problem for way too long, that's when you take out the patterns book. Because at that point you have a pretty good idea of what the problem actually is. You even have a solution that's mostly working and that solution can be re-factored to fit the pattern that seems most appropriate.
You probably won't ever end up with a factory that creates a factory that creates this one object that people only ever use once because that is plainly wrong. But if you ever do code up an abstract factory, when people end up interacting with your API and they whine about the factory factory you can confidently tell them that the alternative is much, much worse and show them how you've actually made their life much easier.