No Getters nor Setters
Note: This post is part of the series Lessons (re)learned.
A lot has been said about the perils of using getters and setters—also known as accessors and mutators—in object-oriented software. To cite a couple, Allen Holub, back in 2003, published "Why getter and setter methods are evil" and Yegor Bugayenko, a decade later, wrote "Getters/Setters. Evil. Period.". However, a lot more has been said—or rather, suggested—encouraging the use of such (anti?)patterns. So much so that I'll refrain from linking here. Suffice to say that pretty much any OO example out there makes use if them.
The terms coupling, cohesion, encapsulation, information hiding, modularity all come up when discussing this topic. And there's a good reason for that: together, they enable malleability e evolvability to software systems. In other words, they help us build software that can be easily changed.
Majority, if not all, cases can be categorized as either a command or a query—also known as Command-Query Separation (CQS). This means that we're either probing the system for information or changing the system state.
In the conversation "Understanding Coupling and Cohesion", led by J. B. Rainsberger, the meaning of coupling and cohesion is explored. Dale Emery points out something interesting:
To couple means to fasten together. And to cohere means to stick together. (…) it seems to me that the difference is in whether the forces that bind the things are inherent in the things themselves or imposed externally.
I found this to be quite insightful. They also reference Glenn Vanderburg's "Cohesion" blog post, in which the author explains cohesion by contrasting it with adhesion, a more common term.
Also, in this same conversation, the late Jim Weirich brings up connascence: a way of categorizing the different types of coupling. A more comprehensive collection of resources about it can be found at connascence.io.
This seems to be one of those habits that form real quick—especially when the great majority of examples out there make use of it—and can be hard to unlearn. So, I try to tame it. Whenever I feel like writing a getter or setter, I stop and ask myself:
- Why do I want to get this data from this object?
- What do I want to do with this data?
- Why do I want to set this data in this object?
- Where do I want to keep this behavior?
- Given the object already holds the data, can I tell it to do something instead?