Get and Set sucks!
In this post (provocative title :-)) I want to talk a little bit about the habit of (ab)using the (get and set) accessors in Object Oriented languages.
I’ll try, step by step, from the OO definition through the end define why it is bad and what we can do to avoid this.
Well, there’re tons of definitions so I won’t try to give mine but something has to be clear: An OO program is a software organized around objects. An object is just an Abstract Data Type which expose methods as “interface” and hidden implementation details” (data structures, other private methods, helper objects collaborators, etc). I like to say that an OO software is a “conversation” between objects.
So we already mentioned the first principle of a good (OO) design: Information hiding. It is based on the assumption that an object shout (actually must) hidden the how from what. In this case the interface that the object expose (what, in the form of public methods) and its internals (how in the form of members, data structures, relation with other objects, etc ..). This first point clearly indicate that any time we add a get as public method we expose its internals (directly or indirectly)! That is why in principle accessors are evil!!
The OO Promise
The cool idea of the object orientation is that an application is a collection of objects communicating each other, as we said before. It promises that a programmer should be able to change the type of an object with another one and the software should still work (that is why the second most important principle is the Liskov Substitution Principle).
//<example 1, Ok> BankAccount + IBalance withdraw +deposit (IBalance)
And the “evil” one:
//<example 2, Bad> BankAccount +setBalance (int balance) +int getBalance
The second example above is exactly the error you see most frequently.
Keep in mind that all of 4 the methods (2 from the first example and 2 from the second example) internally manage the “balance” property.
There’re two main difference, here:
The first bank account class contains business related methods, let’s call this class “Business Object”.
The second class expose set and get methods which returns the “how” the BankAccount class.
What’s the real difference here then? It is that the first BankAccount class methods returns (and takes in input) an interface IBalance which contains real behavior like:
//<example 3, Ok> IBalance +print +...
Designing your software by responsibility means identifying your business related objects and giving them “real words” responsibilities (methods). So instead of returning a “balance” object member just return a Balance object with well defined responsibilities (and not data!!).
Another big difference is that we expose a concrete type (integer) in the example 2: what if the balance type change (primitive obsession)?
So far I’ve proposed to have objects with well defined responsibilities (a business expert of bank system should be able to read and comment on methods exposed by the BO), fine! But you might have cases of class that “just hold data” in this case these classes are called Value Object (VO). The first examples of VOs I have in mind are the Java wrapper type: Integer, Float, etc … These type just hold a data and expose that data (e.g.: the Integer wrapper type is “bounded” to the int primitive type and expose it).
BTW, Where are the accessors in the Design Patterns?!?
One indicator that should ring the bell of the quality of the code is that in the design patterns (def: elegant solution for a recurrent problem) there are (almost) no accessors … Why? Well, same reason. If you design your code carefully, keeping in mind the domain “business” you shouldn’t have any accessors at all.
Then, no ‘get’ and ‘set’? What to do then?
It is not black and white as usual it depends case by case but I’d like to highlight few things:
Avoid to return internal structures; Just return an object with clear and well defined responsibility instead (e.g.: IBalance example). Why not giving to the IBalance the possibility to print the balance itself (e.g.: IBlanace.print)?
A “revised” version of the visitor pattern may be used to “link” the IBalance with a UI dialog for example.
Last proposal: If you feel the IBalance is a Value Object then just treat it as Value Object.
CRC (https://en.wikipedia.org/wiki/Class-responsibility-collaboration_card) can help you to highlight the main (business) classes of a sw part with its responsibilities. CRC card is a nice technique invented by Ward Cunningham.
There are few exception to what we said, “JavaBean” (https://en.wikipedia.org/wiki/JavaBeans).
In my opinion Get and Set accessors are a clear sign of (design) technical debt a team should keep in mind … time to put a refactoring story on your backlog guys!
This site uses Akismet to reduce spam. Learn how your comment data is processed.