Loading...

Never Design A Class That Knows How It's Used

Clean Code
June 18, 2019
3 minutes to read
Share this post:

When you design a class you should never design it in a way that the class itself knows how it is used from the outside. Breaking this principle will make it difficult for other developers providing other implementations. I recently stumbled upon an implementation of different entities where the implementation had to provide a unique id for itself. Why this is causing problems and how you better design such a situation I’ll explain in this post.

Let’s introduce an example of the problem that I want to talk about. There is an interface called Entity that specifies a method getId() that needs to provide a unique id.

public interface Entity {
	
  /**
   * @return an id that is unique over all {@link Entity} implementations in the application. 
   */
  String getId();
}

We also have an implementation called House of this interface:

public class House implements Entity {
	
  private Address address;
  
  @Override
  public String getId() {
    return address.toString();
  }
} 

Another implementation might be a PostCard:

public class PostCard implements Entity {
	
  private Address from;
  
  private Address to;
  
  @Override
  public String getId(){
    return from.toString() + to.toString();
  }  
}

You can already imagine the problem that’s present here. We can easily have a violation of the contract of an Entity. As soon as one of the addresses of the PostCard is empty we can end up with a House that returns the same id and this is against the contract of an Entity. So without knowing all implementations of the Entity you can never be sure if you actually provide a unique Id or not. This problem gets worse, the more implementations you have.

Another problem is that you are never able to write a unit test that can actually test the requirement that the id is unique over the whole application.

The underlying problem here is that we put the responsibility to provide unique ids to the wrong layer in our application. The only instance that can control, and ensure, that we have unique ids is the class that creates the entities in our application. And if we don’t have such a class yet than we need to provide a factory for that.

public class House implements Entity {
  private String id;
  private Address address;
  
  House(String id, Address address) {
    this.id = id;
    this.address = address;
  }
  
  (...)
}


public class EntityFactory {
  
  private IdGenerator idGenerator;
  
  public House createHouse(Address address) {
    return new House(idGenerator.next(), address);
  }

}

We can easily test that idGenerator.next() always provides a unique id. And with restricted visibility of the constructor we can ensure that you can’t create a House otherwise.

Have you heard of Marcus' Backend Newsletter?

New ideas. Every week!
Top