The Magic Setter Antipattern
Setters and getter are evil. When the JavaBean definition was created it seemed to be a good idea. But they do a lot of harm to the Java community. Not as many as the null pointer generally, but enough.
The very first thing is that many juniors believe that implementing setters and getter (hey, it is just a few click in Eclispe!) does encapsulation properly. Should I detail why it does not?
The other things is that using setters and getters are against YAGNI. YAGNI stands for You aren’t gonna need it. It means that you should not develop a code that the project does not need now. The emphasis is on the word now. Many programmers tend to develop code that extends the actual functionality and does something more general than actually needed. Even though in principle it could be valuable: in most of the practical cases it is not. The code becomes more complex and on the other hand project never develops to the stage where the generalization the programmer created is needed.
Setters and getter are a clean, simple and very broadly used example of YAGNI. If the setter does nothing else but sets the value of a field and if the getter does nothing else than returns the value of the field then why do we need them at all? Why do not alter the access modifier of the field to the value that the setter and the getter has (probably public
)?
The answer usually is that you may need to implement some more complex functionality either in the getter or in the setter and then you need not change the “interface” the bean provides. The words “you may need to implement” suggests that this is YAGNI. What is more: it is dangerous. Implementing the setters and the getters you implicitly expose the implementation of the class. What does a setter do? Sets the value of a field. For example setBirthDate()
by definition sets the field birthDate
. And this is the way your users, who write the code calling the setter will think about it. You may document in your JavaDoc that setBirthDate()
actually “specifies” a birth date but that is too late. You named the method to be a setter and that is it. Nobody reads JavaDoc. API rulez.
Later, when you change your code and setBirthDate()
does not only sets birth date or does not even do that the users will not be notified. The change is silent and you just changed the interface you implicitely provided for your users. There will be bugs, debug session, new releases and this is good, because this creates workplace (feel the irony, please). If the users were provided direct access to the fields moving the fields from public
to behind the barricades of private
access modifier would cause compile time errors. Perhaps it is only a weird personal taste, but I prefer compile time errors more than bugs. They are easier (read: cheaper) to fix.
Do not worry: you still can modify your API. You can still remove your setters and getters from the set of methods and force fellow programmers to fix their code that implicitly assumed that setters really set and getters get. Please do.
What the actual story was making me write this?
Once upon a time there was an object that could do something. To perform its task you could set either field aaa
or the field bbb
, but never both. The application was developed this way and all was good for more than six years. Some day a young programmer princess came riding on white horse wanting to make the world to be a better place. He wanted to make the before mentioned class safer and modified the setter setAaa()
to null
the field bbb
and the other way around. Unit tests shined. Coverage was 100%. (I should learn not to lie.) He submitted a new release of the library and a few weeks later he finished his internship and went back to school. That time the applications started to use the new version of the library. And they failed miserably because of this small change and rolled back to the old version. We all had hard time and summing up, well, the corporate spent approximately one person year of work caused by the simple change not to mention the amount of hair that programmers tore off from their head.
Why did the programs failed? There was some code that cloned an object containing the fields aaa
and bbb
in a way like this:
BadBean newBadBean = new BadBean(); newBadBean.setAaa(oldBadBean.getAaa()); newBadBean.setBbb(oldBadBean.getBbb());
You see the point. In the new bean the field aaa
was always null
.
Now that you have read this article you will never try to create a clever setter. I know you won’t! You know the saying: Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. Behold!
Reference: | The Magic Setter Antipattern from our JCG partner Peter Verhas at the Java Deep blog. |
This is something that comes up every once in a while. And it never fails to annoy me. Getters & setters on java beans are nice and useful. They *do* help with encapsulation. They can allow you to implement method chaining (a.setA().setB().setC()) if you’re into that sort of of thing. They allow you to use generics. They can be used together with AOP (Aspect Oriented Programming) to add useful things like validation entry points. Unlike popular belief, they don’t slow down your code, and they quite simply look better in Java. Faffing about with struct-like datastructures is very rare in… Read more »
Hello
Well I do not agree that setters and getters are YAGNI. In my oppinion setters and getters are representing some sort of value abstraction and hide the actual value implementation.
Most programmers use them as You wrote
String aaa
String getAAA() and void setAAA(String aaaa)
but lets consider that aaa instead of String could be char[3] where only 3 first characters matter.
In that case You are able to not break the API (leave String) and using gettet and setter control the inner value.
Best regards
Tomasz
Bad implementations of getters/setters this article points out does not make them inherently evil. In general, information hiding is far more important than avoiding getters/setters. Classes should minimize exposure of their internals as much as possible, and that should be the main purpose of getters/setters.