Java Developers, please stop using getters/setters (in your Domain Objects)!

March 2011

Every time I see developers at work or inspect code from them it strikes me how many getters and setters are used in domain objects (this post is not about value objects/data transfer objects; these are just fancy data structures in language that does not allow them).

Your code?

Most developers just write or generate getters/setters without even thinking about it (remember I am taking about domain objects here, again no problem for data-carrying objects). Recall from your Object-oriented training/reading that OO is all about behaviour and that state (data) is the result of this behaviour (iow you first find the methods and then perhaps define the necessary fields to support that behaviour)

Let's take a look at an example:

public class Member{
    private String username;
    private String email;
    private boolean active;
    // more state ...

    public String getUsername(){ ...}
    public String setUsername(String s){ ...}

    public String getEmail(){ ...}
    public String setEmail(String s){ ...}

    public String isActive(){ ...}
    public String setActive(boolean s){ ...}

    //Actual methods ...
    public Loan addLoan(Book book) {...}
    public void returnBook(Loan loan) {...}
    //etc

    //equals() and hasCode() base on username
}

Looks familiar? Now the question is, why are these getters and setters there (yes, you are right they were probably generated by using this terrible feature of your IDE)?

Setters

Let's start with those "setters" (not even an English word, closes comes the "bird dogs", such as the English Setter). Do the methods setEmail, setActive and setUsername really make sense if you put your OO hat on? Recall object state changes due to behaviour, what is the behaviour that changes the state of these fields (and how were they found in the first place, if you don't take OO's behaviour-first route!!??!)

Actually there is probably behaviour that requires the state of the object to change. You introduced a setter with a reason. There is another object calling it! The behaviour is in that "caller" object should be inside this Member object! Recall "cohesion"?

Perhaps the code below (only looking at these setters) makes more sense:

public class Member{
  private String username;
  private String email;
  private boolean active;
  // more state ...

  //Actual methods ...
  public void activateMembership(){
        this.active=true;
  }

  public void changeEmailAddress(String newEmail){
        // perhaps some business rules?
  this.email = newEmail;
  }

  public Loan addLoan(Book book) {...}
  public void returnBook(Loan loan) {...}
  //etc

}

If you think we just throwing letters around and naming the same thing different, then you are wrong. It is all about OO principles and how you should thing when you develop using OO. Notice also that there is no setUsername (which unfortunately is often the situation as a registered member)

Getters

Often the same for these getters. it should not be automatism to have getters for the state of an object. Let's take for example the isActive. This method should be born from an actual requirement in one of your iterations, leave it out until that moment comes! Perhaps in all the iterations so far, the active flag is only used internally by the object in order to enforce the business rule that only active members can borrow books and make reservations.

There are probably two reasons to have getters:

  • Access outside architectural OO boundaries (for example to show on the UI to present to a user)
  • When another object in fact needs to raw state (first look if the responsibilities lie correct!)

But JPA...

I hear somebody saying "But what about all these frameworks like JPA and Hibernate" (if you were thinking "Spring", then keep in mind that Spring Framework is not a framework around domain objects, but around PUFO's (Pure Fubricated Objects).

No problem, in fact using "properties" in JPA/Hibernate does not make a lot of sense (hmm i'm using that word quite often). These ORM frameworks need to persist the state of an object; the state of an object are captured in its fields, not methods. Therefore you always better use the JPA annotations on the fields as opposed to the property methods!

But JSF...

"But what if i want to use my domain objects in my view, such as JSF?"...hmmm that makes my architectural hairs in my neck stand up, but let's say you follow that approach (I'm an advocate/evangelist of Service and Component based Application Architectures, were domain objects are never exposed beyond the boundaries of component that owns them).

Yes in this situation you need to butcher and ruin your Object Oriented design and use getters and setters (but these kind of things always happen if you don't follow a correct architecture, code starts producing a terrible stench). The problem here is actually Java's approach to properties. If at the early start of Java, they listened more to Borland they would have had properties as a first class programming concept (like is the case in C#).

TLDR: stop using getters/setters in domain objects! If you still need them (e.g, exposing them to your view), then either change your software architecture or get nose clips and air freshener in the office to protect you from your code's odor.