I've been writing Java code on and off for about nine years now. I started out writing simple Java applications as part of an Open University course and for the past few years I've been employed professionally to write user interface code using Apache Struts for an internal enterprise Java application that weighs in with about one million lines of code.
Increasingly I find myself subscribing to the You Ain't Gonna Need It (YAGNI) philosophy. Maybe it's as a result of learning Ruby on Rails, but nowadays I find that what I call the Big Up-Front Flexibility (BUFF) approach that characterises enterprise Java development rarely justifies the effort, at least in my experience. Which is not to say that you will never need the three things I'm going to write about, but you should carefully consider what value they add and think about pursuing alternatives where practicable. I feel confident stating that I could have done so within the codebase I work on with no short or long-term ill effects.
Reconfiguring XML Configuration Files
XML configuration files are the scourge of enterprise Java. In case you didn't realise, the reason for their prevalence is that they're supposed to let you change how your Java classes are wired together or how the routing works in your Web application without having to recompile or redeploy any code. I think the idea is that when the customer changes their requirements you make a quick edit to your XML glue, restart the application server and before you can say dependency injection pico container you're in business! And you know what? I've never needed to do that, it's simply a use case I've not come across.
However, I have suffered from having to write reams of XML boilerplate just to put the simplest Web application together. It's something of a joke that enterprise Java programmers are "XML programmers" first and Java coders second. No wonder Ruby on Rails was like a breath of fresh air with its Convention over Configuration approach. The lesson here for Java's architecture astronauts is that when building frameworks you should make the defaults cater for the 80% use case, not the 20%.
Too Much Indirection/Over Use Of Constants
Indirection is a powerful fundamental of computer science. It's also beloved of the enterprise Java world, where instead of going from A to B your code has to go from A to a constant in B that refers to an XML element in D that names another XML element in E that refers to a Java class in F!
Struts 1.x is a great example of too much indirection (I can't comment on Struts 2 as I haven't used it and hope I never will). Your MVC controller code executes in an Action class and then returns an ActionForward that represents where to go next. You're encouraged to hold the names of these forwards in a constants class, even though they'll never change so you may as well just use a String.
The value in that constants class of ActionForward names is actually the name of an element in the Struts configuration XML file that maps to the path of a JSP that's the view template for the actual screen the user eventually sees. It's not that simple though, because you're likely using Struts' Tiles companion, which is a plug-in that provides view templating and introduces another XML configuration file into the mix.
Compare and constrast to Ruby on Rails, where by default and convention the controller method renders a view template that has a file name that's the same as the method name and that's it. You can of course override the template to use if you need to. Another example of how Rails got it right by catering for the majority case out of the box.
Something else I've seen encouraged a lot in the Struts books at least is defining another class of constants for the names of attributes stored by Action class code in the HTTP request or session for use by JSPs. Unfortunately this idea soon falls apart because you have to jump through hoops to use those same constants from within the JSP. Nowadays I just use a String and forget about it.
Getters And Setters
This is probably the most controversial and debated idiom of the three. If you've ever used Java then you've written code like this:
public class Account { private long balance; public long getBalance() { return this.balance; } public void setBalance(long balance) { this.balance = balance; } }
The argument goes that rather than making the balance instance variable a public field, you should encapsulate access to it using the getter and setter methods, because if you ever need to change how the balance is calculated or stored then you can go right ahead and change it without affecting any code that uses the Account class.
That's all well and good, but I can tell you now that in nine years I have never, ever needed to change the implementation of a getter or setter method and therefore the balance might as well just be public:
public class Account { public long balance; }
I would estimate that 95.5% of the hundreds of getter and setter pairs that I (or my IDE!) must have written over the years have been simple instance variable reads or assignments as per the Account class example above. So why not just do away with the surrounding methods and save lots of code?
I've never particularly liked Java's getter/setter approach because I think it makes classes dumb, because if you're not careful they can just end up as data structures instead of proper OO classes with state and behaviour. There's even a name for this pattern: the Data Transfer Object (DTO). I understand that they have this pattern in the .NET world too, but at least C# has a proper language construct for a dumb data holder with its struct type, not to mention a less verbose property mechanism than Java's.
One caveat to this revelation is that I've always had control over the client code that uses my classes. If I were writing a framework or API for other people to use then I'd almost certainly use getters and setters, just to give me wiggle room to change the implementation in the future if required. Actually, I'd favour immutability and not have any setters at all if possible, preferring to use constructor arguments instead. The difference with this framework/API scenario is that once an interface is published in the public domain then it should be considered frozen forever. For everything else, just make the instance variable public or protected as appropriate. If you do need to add some logic around it then use your IDE to refactor how the instance variable is used. Eclipse or IntelliJ IDEA can handle this sort of thing with the minimum of fuss.
Comments
There are 5 comments on this post. Comments are closed.
Heresy! (I like it.)
I find myself using little internal classes a lot lately and skipping the setters and getters and constantly looking over my shoulder lest someone find out and expose me for writing Bad Code. I don't recall ever running into the situation that supposedly justifies the writing of all those thousands of getters and setters I've had to write in my programming career.
The same applies to all those constants I've had to create to replace strings that never change. And don't get me started on all the coding details hidden away in config files somewhere. You end up having to wade through massive amounts of infrastructure code to find out where they've hidden the name of that jsp file instead of just using a string in the code.
Thanks geo, nice to know I'm not alone!
While the Java world definitely seems to have a tendency to encourage this sort of over-engineering it's not exclusively a Java trait. I've seen it too in plenty of .NET applications - trying to be so generic up front that you can solve all the problems you might (but never do) meet in the future. The road to hell is paved with good intentions!
I guess you need a happy medium of doing the simplest thing possible but giving some consideration to problems your design might hit in the future without going OTT is what you really want. Unfortunately a lot of people don't know when they've gone OTT or are too 'clever' for their own good!
As for the getter, setter thing that's something I've gone on about for years. People think they're being properly OO by adding getters and setters to everything but if you're never going to change the implementation then there's no point. And if you do, that's when you encapsulate them in getters and setters, not before! Thanks C# for automatic properties.
Wise words, John.
I always liked the property mechanism in Borland Delphi, so it's no surprise to find out about C#'s as the common link is Anders Hejlsberg.
Something else that I didn't really explore in depth about getters and setters is that the OO purists would say that you should be doing something meaningful with that instance variable anyway, rather than simply assigning a value to it or returning it. Perhaps the code that's in Class B that depends on the getter method in Class A is really some behaviour that belongs in Class A.
Yeah I was sold the whole line about reconfiguring XML configuration files. I've never used it either. Struts 2 has a convention plugin which gets around wiring up configuration files.