Never say "Never"
I don't think it's necessarily bad, it's only bad if you do it badly and abuse it.
We All Need Tools and Utilities
For starters, we all use some libraries that are sometimes deemed as almost ubiquitous and must-haves. For instance, in the Java world, Google Guava or some of Apache Commons (Apache Commons Lang, Apache Commons Collections, etc...).
So there clearly is a need for these.
Avoid Hard-Word, Duplication, and Introducing Bugs
If you think about these are pretty much just a very big bunch of these
Util classes you describe, except someone went through great lengths to get them (relatively) right, and they've been time-tested and heavily eye-balled by others.
So I'd say the first rule of thumb when feeling the itch to write a
Util class is to check that
Util class actually doesn't already exist.
The only counter-argument I've seen for that is when you want to limit your dependencies because:
- you want to limit the memory footprint of your dependencies,
- or you want to tightly control what developers are allowed to use (happens in obsessive large teams, or when a particular framework is known for having the odd super-crappy class to absolutely avoid somewhere).
But both of these can be tackled by re-packaging the lib using ProGuard or an equivalent, or taking it apart yourself (for Maven users, the maven-shade-plugin offers some filtering patterns to integrate this as part of your build).
So, if it's in a lib and matches your use case, and no benchmarks tells you otherwise, use it. If it varies a bit from what you, extend it (if possible) or extend it, or in the last resort re-write it.
However, so far in this answer I called them
Utils like you. Don't name them that.
Give them meaningful names. Take Google Guava as a (very, very) good example of what to do, and just imagine that the
com.google.guava namespace is actually your
Call your package
util, at worst, but not the classes. If deals with
String objects and manipulation of string constructs, call it
StringUtils (sorry, Apache Commons Lang - I still like and use you!). If it does something specific, choose a specific class name (like
If you have to resort to writing these utilities, make sure to unit-test them. The good thing about utilities is that they usually are rather self-contained components, which take specific inputs and return specific outputs. That's the concept. So there's no excuse to not unit-test them.
Also, unit-testing will allow you to define and document their API's contract. If tests break, either you changed something the wrong way, or it means you are trying to change your API's contract (or that your original tests were crap - learn from it, and don't do it again).
The design decision's you'll take for these APIs will follow you a long-time, possibly. So, while not spending hours on writing a
Splitter-clone, do be careful about how you approach the issue.
Ask yourself a few questions:
- Does your utility method warrant a class on its own, or is a static method good enough, if it makes sense for it to be part of a group of similarly useful methods?
- Do you need factory methods to create objects and make your APIs more readable?
- Speaking of readability, do you need a Fluent API, builders, etc...?
You want these utils to cover a large breadth of use-cases, to be robust, stable, well-documented, following the principle of least surprise, and to be self-contained. Ideally, each sub-package of your utils, or your whole util package at least, shall be exportable to a bundle for easy re-use.
As usual, learn from giants here:
- Sift through these, then analyze and compare, and go back to them often to do it again (note that I am not making any judgment about whether these are absolutely or partially good or bad, the emphasis is on the analyze and compare bit):
- Watch Josh Bloch's How to Design a Good API and Why it Matters (slides).
- Read and watch some additional Bloch material:
- Read API Design Matters.
Yes, many of these have an emphasis on collections and data-structures, but don't tell me that's not where or what for you're usually likely to implement most of your utils, directly or indirectly.