The Trouble with Manager Objects
The first time I look at a legacy project, I scan for warning signs. I’ve covered singletons, excessive observers, and today I'll talk about "Manager" classes.
I have to reiterate these are guidelines, not rules, and among guidelines, this one isn't critical. A Manager
here and there warrants an audit when it's time to refactor. But if you’ve got dozens of classes like LoginManager
, CacheManager
, and DataManager
, you’ve probably got architectural problems.
The Symptoms
Managers can be a symptom of poorly-defined responsibilities. When you think about it, the word "Manager" means nothing. In object oriented programming, every class is a manager. Cocoa Touch could have UIApplicationManager
, UIViewManager
, and even a humble NSStringManager
.
Like the real world, the worst manager
s start with good intentions. Say your AvatarUploadController
is over 3,000 lines long, and most of it deals with validating image dimensions, resizing it, uploading it, checking for network errors, and so on. If you cut and paste code into another class and call it AvatarManager
, it's progress.
Now take a step back and ask why "massive view controllers" are a problem. It's Separation of Concerns. Every component should be responsible for a single slice of functionality. Small view controllers are good, but I can live with a massive view controller so long it only handles view controller stuff, like setting up view hierarchies and responding to adaptivity changes. When your controller handles networking, this scope creep leads to trouble.
Extracting tons of business logic into an AvatarManager
solves the immediate problem. If we're talking fifty lines of code, maybe that's enough. But if you're dealing with thousands of lines of business logic, wrapping it in a Manager
is a half-measure. You cleaned up the mud in the living room by sweeping it into the kitchen.
On the other hand, managers can be a symptom of faux object oriented design. Consider Foundation's FileManager
, which is really just a collection of file functions. In textbook OO design, rather than call removeItem(at:url)
, you might instance a File
object with a URL, and then call its file.remove()
method.
That's not to say a real object oriented design is better, but FileManager
does a disservice paying lip service to OO. By using a singleton, FileManager.default
, there's a risk someone (probably a random third-party library) assigning to its delegate
property, and messing up file operations for the whole app. Is this really better than a loose collection of file functions?
How to Fix It
I can already see junior engineers clicking the “Refactor” button, ready to swap Manager
with Broker
, Coordinator
, Utility
and so on. That's the problem with rules: jank finds a way.
When you audit a Manager
class, ask, "What is this component responsible for?" If you have trouble answering that, ask, "Can I break it down?" In the avatar upload example, I'd split it into a NetworkAPI, and ImageConverter
.
Managers aren’t a big red flag because it’s an easy noun to fall back, even when you know what you’re doing. If a senior engineer sits at a screen for too long thinking of a name, their "you’re being too clever" sense kicks in. You don’t want to be that amateur who waxes on about aesthetics while shipping nothing.
Even Apple frameworks use the noun, like Core Location’s CLLocationManager
. Let's audit that class.
What are its responsibilities? It tracks changes to the user's location. Does it take on too many responsibilities? I don't think so. I'd be worried if it included unrelated stuff like reverse-geocoding.
Ok, can we rename the class to clarify things, and fight responsibility creep? I’d go with CLLocationObserver
, or CLLocationTracker
. Nice!
Except Apple would be nuts to rename CLLocationManager
this late in the game. Too much legacy code depends on it, and even if you built code-migrators to help, it’s hard to justify wasting time on this when you could be delivering features to users.
But if you’re building something to last, or building any sort of dependency, it's worth spending an extra few minutes to name things right the first time.