Before being software developers, we are people - and thus creatures of habits. It’s hard for someone to change one’s own habits, it’s harder for someone to change someone else’s habits - and for some of us, it’s even harder.
This, week, during a code review, I stumbled upon this kind of structure:
public class MyStructure {
private String myProp1;
private String myProp2;
// A bunch of other String properties
public MyStructure(String myProp1, String myProp2 /* All other properties here */) {
this.myProp1 = myProp1;
this.myProp2 = myProp2;
// All other properties set there
}
public String getMyProp1() { ... }
public String getMyProp2() { ... }
// All other getters
public void setMyProp1(String myProp1) { ... }
public void setMyProp2(String myProp2) { ... }
// All other setters
}
Note: it seems like a JavaBean, but it’s not because there’s no no-argument constructor.
Looking at the code, I see that setters are never used in our code, making it a nice use-case for an immutable data structure - and saving a good number of lines of code:
public class MyStructure {
private final String myProp1;
private final String myProp2;
// A bunch of other String properties
public MyStructure(String myProp1, String myProp2 /* All other properties here */) {
this.myProp1 = myProp1;
this.myProp2 = myProp2;
// All other properties set there
}
public String getMyProp1() { ... }
public String getMyProp2() { ... }
// All other getters
}
At this point, one realizes String
are themselves immutable, which leads to the second proposal, which again save more lines of code:
public class MyStructure {
public final String myProp1;
public final String myProp2;
// A bunch of other String properties
public MyStructure(String myProp1, String myProp2 /* All other properties here */) {
this.myProp1 = myProp1;
this.myProp2 = myProp2;
// All other properties set there
}
}
Given that attributes are final and that Java String
are immutable, the class still safe against unwanted changes.
Note that it works only because String
are immutable by definition in Java.
With a Date
property, it wouldn’t work as Date
are mutable.
The same can be done with stateless services, with embedded services that needs to be accessed from children classes. There’s no need to have a getter:
public class MyService {
// Can be accessed from children classes
protected final EmbeddedService anotherService;
public MyService(EmbeddedService anotherService) {
this.anotherService = anotherService;
}
}
Note this approach is 100% compatible with for Dependency Injection, either Spring or CDI.
Now, you cannot imagine the amount of back and forth comments this simple review caused. Why? Because even if that makes sense from a coding point of view, it’s completely different from what we usually do.
In that case, laziness and IDEs don’t serve us well. The latter make it too easy to create accessors. I’m pretty sure if we had to code getters and setters by hand, the above proposals would be more in favor.
This post could easily have been titled "Don’t let habits get the best of you". The lesson here is to regularly challenge how you code, even for simple easy stuff. There might be better alternatives after all.