company-logo

Bean of the Devil: Why Getters, Setters and Such are Evil

I felt like I’d already gotten this rant out of my system, but every time I come across the object oriented wreckage that the Java Bean and it’s decendents have wrought, I get all heated up. The problem is, simply stated, that the getters and setters that get used for things like system boundaries — Hibernate for persistence, Spring for dependency injection, Java Beans for UI components — end up being misused for things that break basic OO principles.

How do these pernicious little getters and setters undermine OO? Let me count the ways.

  1. Encapsulation: the detailed implementation of an object is hidden from the rest of the system. Yes, yes, 99.99999% of all getters and setters are just fronting a private field and that’s bad enough, but this is more about the getters, pulling data out of the object and doing things with it outside the object. They leak out, bit by bit, until you repeat yourself all over the place with slightly different manipulations of the data. Before you know it, you are looking at a siloed procedural applications that spurred the invention of OO in the first place.
  2. Polymorphism: one type can substituted for another. If your implementation is out there flapping in the breeze, it’s hard to swap types. Even if you do, the application of polymorphism is usually pretty weak. Leaking implementation into the collaborating classes really ties your hands.
  3. High Cohesion: responsibilities of an object are strongly related and focused. If you pull information out of objects and deal with it in the collaborating objects, the cohesion is going to be progressively more diffuse.
  4. Low Coupling: low dependencies between classes, low impact of changes in a class on other classes and high reuse potential. This is a killer. Again, you have your implementation info spread all over the countryside like in a procedural application. You change the implementation and you are in for a mega refactoring.
  5. Information Expert: the responsibility goes to the object with all the relevant information. When you leak data into the collaborating classes, how can you identify the information expert?

There’s more, of course, but the worst part is that in a system with getters and setters, the rot gets worse the longer the system is under development. A little enhancement can be done so easily by pulling an integer here, a string there and doing a little dance in a method without arranging the collaboration of necessary classes. You need to refactor and refactor to stem the tide. It is a problem of your own making that costs you time and budget.

So, think twice before you expose everything with getters and setters. I would argue that they be the exception and not the rule. A rare sprinking to season the system boundaries.

  1. Antoine Leclair Reply

    I’m not sure to get your point. You are saying getters/setters are bad in general?

    Or are you saying they simply should not be used to expose all the internals of a class?

  2. Dietrich Kappe Reply

    @Antoine

    They can be used in certain contexts, but only as part of an interface whose use is restricted.

  3. chang Reply

    I agree with none of what you just said. I think you’re completely wrong.

  4. MoffDub Reply

    Ah, the timeless “Getters and Setters Are Evil” topic. I have devoted many a blog post to this: http://moffdub.wordpress.com/tag/getters-and-setters-are-evil/

    Anyway, here’s the conclusion I most recently came to on this. The catch phrase shouldn’t be “getters and setters are evil”, but rather “revealing internal implementation details and enabling procedural-style programming is evil.”

    If you are practicing something like domain-driven design, then I see nothing particularly evil about having getters for the fields of a domain object, as long as you encapsulate those values into an object. Also, these fields need to be domain-relevant fields, which they all should be if you are really keeping the domain model clean.

    For instance, instead of having the Customer object’s getID() return and int or a long or whatever it is, return a CustomerID object. Any logic you need to perform with it, like comparison, should be methods of CustomerID.

    Similarly, when you need the actual value for the UI or persistence, say CustomerID.asString(). This way, if the internal implementation of CustomerID changes from int to long, no other class is affected.

    Some other words on this: you should also probably return copies of such objects for these getters, unless you can absolutely guarantee that the objects returned are immutable. If not, then changing the returned object can muck with the containing object’s implementation in a way inconsistent with its API.

    Another thing is I think setters for every fields ARE in fact evil. If you have getters for every field, and setters for every field, you have devolved, as you pointed out, to procedural programming. Setters are fine if they make sense for the object (i.e. the requirement is that customers can move to a new address, so Customer.setAddress(“123 Main Street”) ). The setters for fields that are only set once need to be one-time only… in other words, use a constructor.

  5. Dietrich Kappe Reply

    @chang

    Can you be more specific? You love the getters and setters?

  6. Getter.getAlternatives() Reply

    This is an interesting post. I see 1-5 as reasons to use getters and setters. Certainly, getters and setters should be only used when a design intends that the specific internal be viewed/replaced by users of the object.

    What alternative to getters and setters do you recommend? Non-private member variables (laughing)?

    @MoffDub – very insightful post. Too bad it’s a lot of work to do this. I would recommend only doing this for client/module/library APIs that will be called by an unknown set of users.

  7. Dietrich Kappe Reply

    @Getter.getAlternatives()

    First, in languages that support interfaces, put all of the getter/setter methods in an interface, then only use that interface in system boundary contexts.

    Second, practice good OO. Don’t pass primitive types (other than booleans) around as parameters and return values.

    Third, for those cases where you do need implementation details, such as computing aggregate values from a collection of objects, make sure the circle of collaborating objects that have this tight coupling is specific and small. The moment it gets larger, you have a refactor on your hands.

  8. James Law Reply

    FYI, neither hibernate nor spring require get/set pairs. Not sure if you’re suggesting that, but I’m amazed at the # of people who believe this is the case. Check out fowlers post on getter/setter eradicator.
    http://martinfowler.com/bliki/GetterEradicator.html

  9. Dietrich Kappe Reply

    @James

    You’re correct. I was thinking back to early versions of Hibernate and Spring where this was necessary. In point of fact, you can dispense with getters and setters for the most part, making their use even less forgivable. They are, as far as I’m concerned, a code smell akin to stuffing everything into one main() method.

  10. Hao Wooi Lim Reply

    I had to agree with you. Coming from a functional programming world, I kinda prefer the idea that states are nothing more than constructs for optimization and that if you must have states, then it can only be modifiable or readable through the class’s methods. Allowing private member to be modifiable through public setter is just as evil as a public member, period.

Leave a Reply

*

captcha *