What’s in a name? Isn’t this stuff supposed to be a hard problem anyway? What is a DownloadController
, and how is it different from a DownloadQueue
?
I love this quote by Graham Lee so much:
Anything that isn’t evidently data or evidently graphics gets put into the amorphous “controller” collection, which eventually sucks your entire codebase into its innards like a black hole collapsing under its own weight.
Charged with bridging between models and views, view controllers grow to become untenable nightmares quickly. It’s become valuable to question what the word “controller” even means to us.
What’s a gesture recognizer? It gets attached to views, suggesting that maybe it belongs in the view layer, but it’s definitely not a view. However, in Smalltalk (the first object-oriented lanugage), user input is classically a controller concern. Which of the two is it? The answer is simple. A gesture recognizer is just that: a gesture recognizer.
Not all objects have to be models, views, and controllers. Some objects are data sources, gateways, routers, and interactions; others still are players, presenters, and operations.
Models and views are easy; they are Things. Representing them in your brain in not a challenge. Controllers are much more amorphous. With models and views, shared behavior in them can be moved up to a superclass, and specific behavior can be moved down to a subclass. All of the models in your app could descend from one class; say, MTLModel
. Views could do the same (and in fact, must, if you expect them to play nicely with UIKit). View controllers also have lots of shared behavior and benefit from a supertype. What would a hypothetically-named SKController
superclass even do? With responsibilities so broad, what would that interface declaration even be? It would probably be empty.
@interface SKController : NSObject
@end
What useful thing is this object doing? What shared behavior can we give it? And if there’s nothing sensible in SKController
, why call things controllers at all? They’re also all objects. It would be just as appropriate to append the word “Object” to every class name.
The harm caused by the “Controller” suffix is subtle, too. When you call something a Controller, it absolves you of the need to separate your concerns. Nothing is out of scope, since its purpose is to control things. Your code quickly devolves into a procedure, reaching deep into other objects to query their state and manipulate them from afar. Boundless, it begins absorbing responsibilities.
The scope of a policy object is very narrow, and it quickly becomes obvious when it starts acting outside of that scope. It has very clearly defined boundaries, and it’s perfectly testable. It is everything a MusicLibraryController
is not.
A MusicLibraryController
can be decomposed into a MusicLibrary
with LibraryItems
, a Player
, and a PlayQueue
. We’ve granted a specific role to each component. A new developer needs to know only the names of classes to intuit how they work together. She can do this without reading a single line of code. That’s incredibly powerful.
Naming is hard, but calling things “controller” is easy. (“Manager” is a cop-out too. Sorry.) Spend a little time and think about what role your new object plays in your architecture. Give it an expressive name based on its purpose. If a meaningful name is hard to pin down, it might encapsulate more than one responsibility. Break it up. Read Gang of Four and Patterns of Enterprise Application Architecture from cover to cover. Learn about the different patterns that programmers have been using for decades. Or make up your own! If it feels right, try it out. You’ll know if it’s good.