The Util Class Antipattern
What is a Util Class?
A util class is generally a class with all static methods for performing operations on a specific object type.
Why Util Classes Are Bad
Util classes are more of a procedural way of programming. They make the code harder to read and couple you to two classes instead of one. Util classes make you have to find the operations you are looking for instead of being able to just search the object they should be on. Util classes can make it harder to test since you are working with static methods. The operations on a util class should be on the class the util class is supporting.
Designing for object oriented programming, util classes are backwards. Look at it with a different mindset. Think of an object like a person you are talking to. You want to know the person's name, so you ask the person, not some third party. Util classes act as a third party, you have to go find to get a response to a question. For example, you have a User object.
// Java code
final var user = new User();
You want to know what the user's name is.
// Java code
user.name();
If you are going through a util class or a third party to ask the question, it would look like this.
// Java code
UserUtil.name(user);
The first one makes more sense, and there is no hunting down for where you find the third party to ask. It is more confusing, and the code doesn't read as well.
Extension Methods
Extension methods are methods that can be used on a class after that class has been complied. If the User class above was coming from a third party library or framework, when you add that library, we might not be able to extend it, or extending it is going to be messy. Using an extension method, you could add the name() method to the User class and avoid adding a util class.
Util classes are very common in Java and other programming languages that don't support extension methods. Java's String class is final, so it cannot be extended. This requires you to create a StringUtil class. If you are using a programming language that supports extension methods, use them when it makes sense. This is one way to avoid util classes.
Wrappers
Another way to get around util classes if you don't have extension methods is to create a wrapper. There are times where adding a wrapper to the name of the class can give clarity. Depending on what you are wrapping, you want to avoid putting it in the name and try to give it a more meaningful name. It usually only makes sense to add wrapper to the name when you are wrapping a library or framework.
Looking at wrappers in a different way, you can think of them as a domain class or even a class in your language's standard library. Take a class that deals with date and time. Dates and times can be very complex, and there can be several classes and ways to get the same result. By creating your own classes for these types, it can add lots of clarity to the code, improve poorly written APIs (Application Programming Interface), improve tools in your IDE (Integrated Development Environment) such as find usages, and sometimes even the compiler.
The following is an example of creating your own date and time class. This class represents a UTC (Coordinated Universal Time) date/time where we manually apply the offset.
// Java code
final class UtcTimestamp {
private final Calendar calendar;
private UtcTimestamp() {
}
public static UtcTimestamp now() {
// return a UtcTimestamp of the current date/time
}
public String toFormatted(final int utcOffset) {
// The date/time is UTC so we apply an offset.
// Then return it as a formatted string.
}
public String toDuration() {
// returns the duration since it was created.
// Examples: 10 seconds, 2 minutes, 3 days
}
}
This encapsulates the calendar object and allows us to create our own API for our application.
Conclusion
Avoid util classes whenever you can. You should have none to very few. Use extension methods or create your own library depending on the use case you are dealing with.