OOP Anti-Patterns: Utility or Helper Classes

I can bet a good amount of money that at least once every week you have to write this tiny little method that is used across several classes but does not fit either one of them. The head first thought is to put that code into that big junky Utils class like a homeless child. Almost every project has at least a whole package of utility and helper classes, because everyone needs a junkyard for their unwanted code, for those pieces that obviously does not fit in their beautiful garden of objects. While working on your own, you can easily get away with a bunch of utils you created for your own sake. The big mess happens when you start creating utility classes while working in a team. The moment you create that Utils (aka Commons aka Helpers) class you give that big green light for everyone in your team to start sending their junk methods into it. That class quickly becomes a graveyard for unwanted code. You do not want any graveyards around your working place. They could be quite depressing at times. Whenever you are about to create that first Utils class, you should stop and think about it. Talk to a colleague. Go get a beer together. Talk some more. Look from a different perspective to your business logic. I bet you will come with a good name and a good home for your method. I can assure you a hundred times - that’s not a time wasted!

Why do we write utility classes?

  1. Lack of business domain knowledge
  2. Laziness
  3. Both
  4. Fear that we are bad programmers if we do not complete tasks quickly
  5. Fear that the product owner will finger-point at us for running later than the initial estimations causing the burndown line to stand two inches above the ideal line thus making his beloved burndown chart imperfect
  6. Fear that at least one of our managers will frown upon us for having no idea how we can “loose” paying time to think about the name of a stupid method

I sense great fear in you, Skywalker.

Why are utility classes so evil?

  1. They tend to become quite large quite quickly
  2. They group functions that are not related at all
  3. They are just a pile of stuff that do not belong there
  4. They are all static globals
  5. They break basic principles of OO design
    • They have many reasons to change (break Single Responsibility Principle)
    • They cannot be extended (break Open Closed principle)
    • They cannot be injected (break Dependency Inversion principle)
    • They are far from SOLID
  6. The moment you create one is the moment everyone starts sending there more and more code that is hard to fit elsewhere
  7. They do not pass the squint test

But the whole Java world does that. How bad can it be?

People tend to avoid duplication and follow the DRY principle by extracting common code that is used everywhere into utility classes. That falls more into the procedural programming world where developers follow the notion of functional decomposition. However, in object-oriented design, utility classes are a terrible practice. They are a clear sign that someone has failed to find a good name and a good place for that piece of functionality inside the beautiful tree of objects. The methods inside are not even remotely related. That class has many reasons to change. The most bugs appear in the code you change the most. Helpers simply do not belong in a object-oriented world. I refuse to believe that there is no other way. I refuse to believe that they cannot be replaced by proper objects or well-named classes.

How to solve the “There Is No Other Way” puzzle?

  1. Fill the lexical gap (learn the “words” of your business domain)
  2. Call it what it is (naming is the hardest thing in programming, I know, but still give it another try)
  3. Talk to a teammate, talk to your product owner (solve the problem as a team)
  4. Explain what that piece of code does in bare words, explain it to your child (look for the simplest words)
  5. Create a simple abstraction with a clear responsibility and good naming

Let’s walk through an example

A typical Java utility class holding thousands of lines:

1:    public class Utils {

        ...

587:    public static int perimeter(int length, int width) {
588:      return (2 * (length + width));
589:    }

        ...

1603: }

This utility method calculates the perimeter of a rectangle. It takes the length and width of a rectangle and returns the perimeter. Simple enough. But then comes the next guy who needs to calculate the area of a rectangle. He greps the code, finds your approach and concludes: “So that’s how we do things in here”. Then confidently adds one more utility method to that already huge utility class. That is the worst about utility classes. They very quickly become junkyards for unwanted code.

But troubles don’t come alone

Apart from being a utility method stuck in the middle of a huge utility class, I already sniff two other code smells. First is Primitive Obsession. That is relying way too much on the primitives the language is providing. Instead of having a Rectangle object we have represented that concept with integers. Second is Data Clump. Everywhere we need the notion of a Rectangle in our code, the length and width will always come together. That is a typical side effect of utility functions. As you don’t have an object for that behavior, it comes quite natural that you won’t have also an object to hide the data behind as a state. You end up passing it around as data clumps.

But why are these code smells bad? What is wrong with that code?

Imagine you see this [10, 20] in your code or in your debugger output. You will be like “WTF is that?”. Is it 10 dollars and 20 cents? Is it 10:20 AM? It just makes code unreadable and tracking down bugs harder. It is a bad way to craft your code.

You have dependency on the order. For example, you expect length first and width second, but your utility method gets called the other way around. Which will be fine in our very simple example, but cause hard to find issues in more complex cases.

You will need to create a number of global utility functions to deal with the specifics of your abstraction represented by primitives, in our case the rectangle. You won’t have any idea where to put those functions so you end up expanding on that utility junkyard. First come validations. You need to ensure that those two integers are valid before you work with them, for example: check for negative values. Now your whole team needs to remember to call these global validation functions before working with these numbers. At this point you are creating a good amount of technical debt and your whole team has to jump through hoops in order to work with rectangles.

As in all software development, the worst comes when you need to change that code. For example, imagine now you have to add another attribute to the rectangle, like color. If you end up applying that change to under a thousand places in your code base, then you are one lucky dude.

How to cure primitive obsessions?

In general you should be avoiding primitive obsessions by encapsulating data into higher-order objects. You should create an abstraction around your concept to give semantic meaning to your data. One simple way to achieve that is by extracting a Value Object. It is used to refactor both the Primitive Obsession and the Data Clump code smells. Now when you need to add more behavior, such as area method, you know where to put it. You won’t just throw it onto your utility junkyard.

The object-oriented approach:

public class Rectangle {
  private int length;
  private int width;

  public Rectangle(int length, int width) {
    this.length = length;
    this.width = width;
  }

  public int perimeter() {
    return (2 * (this.length + this.width));
  }
}

We have created a simple abstraction around our rectangle concept. We have isolated the data inside and exposed the perimeter behavior to the outside world. The object is immutable as the values passed in the constructor can never be changed. It only returns information about its data. When the next guys comes with a requirement for area, it will be very easy to add that method to this abstraction. You can easily add validations in the constructor. Everybody on your team will use that object intuitively. We have now another good citizen in our beautiful garden of objects.

Takeaway

Every SOLID piece of code does one thing. Call it what it is. Use a descriptive simple name. Use a simple abstraction to hide data and expose behavior.