Utility classes are evil

Why we use them?

  • Utility or helper classes are classes containing only public static methods.
  • They are stateless and need not be instantiated.
  • Their methods can be reused across the whole application.
  • They are easy to implement and use.
public final class UtilityClass {
     // Private constructor to prevent instantiation
     private UtilityClass() {
         throw new UnsupportedOperationException();
     }
     public static int sum(int x, int y) {     
       return x + y; 
     } 
     public static int average(int x, int y) {     
       return (x + y)/2; 
     }
 }

The problem:

  • Classes become tightly coupled to the util classes they use.
  • Util classes cannot be mocked.
  • Classes using util classes cannot be test in isolation. The util class method must also be tested.
  • Util classes cannot be proxied(dynamic proxy) therefore we cannot use tools like spring AOP on them.
  • Utility classes can quickly grow in size and become a dumpster containing static methods.
  • Util classes often group functions that are not related at all (low cohesion).
  • Often Utility classes can contain a huge amount of dead methods or codes.
  • Utility classes do not follow object-oriented paradigm, instead they are mostly procedural.
  • Util classes containing Business logic.

An example of the problems:

Imagine we have to unit test the method “calculateSum” below:

@Component 
public class MyBean {
   public int calculateSum(int x, int y) {
     int bonus = 2 * x;
     int resut = bonus + UtilityClass.sum(x, y); 
     return result;
   }
}
  • Now how are we going to unit test calculateSum() of MyBean by mocking UtilityClass.sum(x, y). This is clearly unfeasible.
  • We cannot isolate MyBean.calculateSum(x, y), we have to test it fully together with UtilityClass.sum(x, y).
  • MyBean is tightly coupled to UtilityClass.

3 Comments

Add Yours →

@Component
public class MyBean {

private Function sumFunction = UtilityClass::sum;

public int calculateSum(int x, int y) {
int bonus = 2 * x;
int resut = bonus + sumFunction.apply(x, y);
return result;
}
}

Bum – problem with testing and coupling solved. Is it still evil?

Leave a Reply