I'm sure you have come across a project with a lot of code generated from getters and setters, so to speak. Developers are used to using their IDE to generate accessors and mutators without understanding the how and why.
What if I told you Morpheus never said "What if I told you?"
I know you saw that meme a thousand times, but have you heard him say it in the movie?
You didn't because it didn't happen.
People keep repeating these "quotes" so we assume they are true.
In this article, I will explain the role of each of these generated codes and show you why it is a bad practice to use setters, and why you should avoid using setters at all costs.
Cargo cult programming
This phenomenon afflicts human behaviors. Since the software is developed by humans (GitHub Copilot), we come across it in software development. It's called cargo cult programming, and Wikipedia defines it as:
It is a style of computer programming characterized by the ritual inclusion of code or program structures that serve no real purpose.
Cargo cult programming is symptomatic of a programmer not understanding either a bug they were attempting to solve or the apparent solution.
One behavior that is spread among developers is the creation of getters and setters.
Another way of seeing objects
One useful way to see an object is the term Domain-Centric Object because this gives developers and non-developers a common language when discussing in the project.
Let’s say we have an Account
class with the setter method below:
public void setActive(boolean status){
this.active = status;
}
This method changes the status of the object in question. But I’m not certain that in the real world you can't tell to someone "hey he sets the account active status to true", pretty weird, isn’t it?
Even if you ask the author of that code, he/she will respond that it’s an activation function. So to refactor that in the domain-specific word, in the way that our method tells explicitly what it does, it will be something like this.
public void activate(){
this.active = true;
}
public void desactivate(){
this.active = false;
}
Keep in mind that having the setter method allowed the outside world to set the internal state of the Account object, whereas now, the Account object is responsible for managing its internal state.
Anemic vs Rich Domain Model
By having tons of setter methods in your entity, you end up with what’s called the Anemic domain model.
class Account {
public void setDescription(String description)
//...
public void setOwner(String owner)
//...
public void setType(String type)
//...
}
By doing this, your object is more like a data structure than an object.
If you want to refactor this to have a Rich Domain Model, it will look like this:
class Account {
private String description;
private String owner;
private String type;
public constructor(String description, String owner, String type) {
this.description = description;
this.owner = owner;
this.type = type;
}
public void describe(String description)
//...
public void updateOwner(String owner)
//...
public void updateType(String type)
//...
}
Now our Account class is protecting its internal state by defining its properties at the instantiating of the object and only exposing behaviours to the outside world
The misconception of Getters
Recall from your memory a situation where you need to reveal some personal information about yourself, such as being in a classroom.
When your professor asks you for your information, do they say "Get me your age"
or "Get me your name"
? His/Her don't.
When we use the word get in real life, it usually isn't a question, but an imperative that has some implied side effect. Say you want a pencil, so you tell your friend "Hey, get me a pencil from the table".
The side effect of him getting you a pencil is that the table will have one less pencil afterward. This will happen every time you call him to get you a pencil.
So, it would be nice if the table would follow our programming conventions of "getters" not changing the internal state of the object, but they don't.
I am OK to continue using getter, but it’s still fancy in my head, and we definitively no need to use it, maybe I will talk to my colleagues to refactor some naming conventions in our project.
Object Corruption: Stop using setters
Setters-pattern is the one most popular in lots of programming languages. Engineers have been using it for such a long time that this approach has become obvious.
The entry code snippets below are for Java, but those rules can be applied to any other language. I’m convinced that you have already seen code like this at least once in your life.
class Employee {
private int age;
private String firstName;
private String email;
// getters and setters...
}
Employee employee = new Employee();
employee.setAge(99);
employee.setFirstName("John");
employee.setEmail("johndoe@nobody.com");
This approach seems pleasant at first glance, but let’s think about it twice. Firstly, we instantiate an empty object which has nothing inside it. After that, we assign the required values step by step.
What if we forgot to assign the email or the age?
That means future executions would handle an incomplete object. More than that, setters' presence means that the object is mutable and can be modified by anyone at any time, anywhere in the code.
I’m sure you realize now how it’s pretty annoying 😟.
A better alternative: Constructors
A better way is to use a constructor, by setting all the properties final. It means values can be assigned only once within the constructor scope.
class Employee {
private final int age;
private final String firstName;
public Person(int age, String firstName) {
this.age = age;
this.firstName = firstName;
}
// getters...
}
Employee employee = new Employee(34, "Jake");
When you deal with multiples parameters constructors (more than 3), it’s helpful to use the builder pattern. This approach is significantly easier to understand, but it is also easy to forget about some arguments, so be careful when you build your object with it.
I hope you enjoyed reading this, and I'm curious to hear if this tutorial helped you. Please let me know your thoughts below in the comments. Don't forget to subscribe to my newsletter to avoid missing my upcoming blog posts.
You can also find me here LinkedIn • Twitter • GitHub or Medium
Wrap up
I try my best to convince you that setters are not a good practice in terms of clean code/clean design, they don't be worth it.
But in some rare cases, you would surely end up using them, as If you arrive at a project which already has its architecture defined by other developers.