Why you should never ever ever have Managers in your class name
blog.shoutt.me
blog.shoutt.me
You should probably consider hiding all of that complexity behind an intention-revealing interface. Something like ConnectionManager - it will manage all the hairy connection internals and let you write cleaner code as your extend your app.
Software Design is hard. :)
ThingManager is a bad metaphor for a class that follows single responsibility principle (http://en.wikipedia.org/wiki/Single_responsibility_principle). It encourages you to stuff too much into a class because managers do many things, and it's not always clear what exactly they do - almost anything can be thought of as some sort of "management". The real reason is mentioned two paragraphs from the end - the name is simply too ambiguous.
Take the DriverManager class from the JDK (JDBC). To me, it's always been a clean way to register JDBC drivers, get connections, etc. It is responsible for internally managing available driver classes and selecting the appropriate driver to use for a particular connection string. It manages all of this internally, and, from my perspective, it is well-named.
I do think, like anything, the concept can be overused. But, I just don't agree with this kind of "never, ever use x in your class names or your code is evil" blanket statement.
It seems to me that the issue is that they named the class ConnectionManager when it should have been Connection. But then if you are doing connection pooling, and you need specific control over the Connection objects, then what would the harm be in delegating this to a ConnectionManager class, which manages a bunch of Connection objects?
ConnectionPool makes you think of it as an actual object. ConnectionManager makes you think of this all encompassing thing that handles/manages anything that is Connection related.
That said, I sympathize with the impulse that the term "manager" says there's something wrong in your OO design. It is simply that determining how to get around the problem is hard.
I'm just hoping for a discussion, this is an important topic for me as a developer.
The counter-example given is bad in another way, if you have the max retries on a per-connection basis, you're going to be blocking trying to make connections to an end point that's down. If this state is per-end point, handled by a Manager/Factory/Pool, then you can make the retry logic global.
The main key with rules in software engineering is that it takes experience to know when it makes sense to break them. There's few things that fall in the "never ever" category.
Sometimes I learn better by making the mistakes and learning not to repeat them; that can be pretty annoying for others that have to work with my code I guess. Most mistakes I've made while programming are non-fatal/non-critical, but they do add up and refactoring perhaps helps with that. I think pair programming further alleviates such issues? So the lesson learnt is that I should be more mindful of how I name classes/methods, which I honestly haven't paid much attention to in the past.
-- Phil Karlton
There should be a short list of words never to appear in names. "Manager" is certainly one. I nominate "Handler" as another.
http://developer.android.com/reference/android/os/Handler.ht...
- system. Everything is a system.
- data. Everything that isn't executable is data.
If you are going to ban names, I nominate the entire index of the GoF book: Factory, Singleton, Command, Proxy, etc. all sort of convey an idea of the kind of stuff they probably do, but nothing truly precise about the details.
Or I can just accept a rough meaning of the word, name my classes / modules / variables / etc reasonably and then rely on a coherent approach to design and documentation to provide with the details.
- XXXManager: owns the lifetime of objects of class XXX and the relationships between them.
- XXXHandler: responds to events relating to XXX.
- XXXFactory: creates instances of the polymorphic type XXX
- etc.
It works fine until we realize that the app requires multiple simultaneous connections to the server. Now because you have a ConnectionManager, you go ahead and introduce an array inside the class which maintains the state of all the open connections to the server.
No competent programmer would make this mistake solely because the class is called ConnectionManager.
For example, we're using a legacy codebase now where there is some complicated logic involved in managing attributes for products. ProductService is a singleton with no internal state that does things like removeAttribute(product, "foo") and serves other purposes. Before we introduced this pattern this kind of functionality was copy-pasted all around our controllers.
In short, I don't see the harm in this convention. Perhaps Manager or Service is bland name, but it's immediately clear to our developers what it does, and if you want to see if something has been done before with products, you look in Product or ProductService.
Ironic, isn't it? :)
PS. Don't get me wrong - a Manager, or Util, or Helper is not the greatest crime against software design. The intention here is clear, functionality - no, not really. However engineering is about tradeoffs, and it is sometimes practical to have a dumping place for miscellaneous stuff. Just keep in mind that it is a "be careful" territory, those places do tend to turn into ugly and hairy mess over time.
Good workers don't need much managers.
They learn that objects encapsulate behavior, and soon start deriving all kinds of non-objects to hold their actions ("ConnectionManager", "ConnectionHandler", etc.), while the state is kept all over the place.
You should look at objects as just another data structure. Once you realize this, it's pretty clear that you should have a "Connection" that keeps the state and a bunch of methods to manipulate it. This comes natural if you program in C or other paradigms, where a "Connection" would be a struct or something like a hash.
Another code-smell is a codebase littered with singletons.
If I understand you correctly, it seems you would have reached the opposite conclusion: that is, if I learn that objects encapsulate behaviors/actions then I would create classes like "Connection" with all the attendant methods and would have no need for external classes like ConnectionManager.
But, if I treat a Connection like a struct, then I would need these external classes like ConnectionManager to perform the actions.
So, it seems exactly opposite from what you suggest.
Can I make it more clear? People learn (wrongfully) in OO that objects encapsulate behavior, so the first thing they do is create "Manager" classes and outline their program flow. This is even worse in languages that only gives you classes to work with - e.g., Java. Wrong. The first thing one should do is define the data structures - and when using OO, doubly so, because the data structures will map to classes seamlessly.
When you have those "Manager/Controller/Handler" classes, it's a pretty big sign you're inventing a non-object to store all the control flow in one place, instead of thinking about proper objects and message passing.
Classes can and should encapsulate behavior in good OO design. This is why classes can contain methods. I don't know if you think that feature is also "wrong" in an OO language, but without it some of the primary benefits of OO, such as polymorphism, begin to disappear.
Speaking of polymorphism, how do you propose that would be achieved under the constraints you would impose? Prior to editing the parent, you had written that you prefer something like:
Connection conn = Connection( params )
instead of
Connection conn = new ConnectionManager().getConnection( params )
In that case, how would you propose that the former code (i.e. your preferred approach) instantiate the appropriate Connection subclass? There wasn't even a new operator or valid construction syntax in your preferred approach, so perhaps you recognized this limitation and were suggesting some magic would occur.
Before editing, you also said not to "get you started on statics". So, without statics, you couldn't even do something like Connection.getInstance(params) to allow the Connection class to determine which subclass to create. So, the calling code would have to be aware of which subclass to instantiate, which would be simply awful.
Perhaps this is why you edited your comment.
But leaving your edits aside, you still seem to think of objects as only data or structs with no behaviors, which is an extremely limiting constraint on OO design. In fact, it would eliminate so many benefits of OO programming that it wouldn't be OO at all.
Of course, classes encapsulating behavior is the reason behind OO. What's wrong is the backwards thinking: "I need a place to hold my behavior, let me write a ThingManager class for that".
> Connection conn = Connection( params ) instead of Connection conn = new ConnectionManager().getConnection( params ) In that case, how would you propose that the former code (i.e. your preferred approach) instantiate the appropriate Connection subclass? There wasn't even a new operator or valid construction syntax in your preferred approach, so perhaps you recognized this limitation and were suggesting some magic would occur.
The point is, why do you have a class after all then? A normal function that returns the appropriate object suffices. Of course this is not possible in pure-OO languages, like Java, so you abuse classes to hold logic like a namespace. Static methods are an even worse perversion of OO, for the same reason (lack of pure functions inside namespaces).
But this implies that there is never a natural hierarchy amongst classes or a case wherein you want a collection of objects to be managed by a class whose responsibility is to know about or manage objects. Those situations can and do arise. And shoving such functionality down into the "managed" objects themselves seems less desirable in my view. In such a design, the managed objects are basically saying "I am a subtype of x, and I also know about and manage other subtypes of x, similar to me".
Why should each x carry around such baggage and worry about managing other objects? To me, that breaks good OO design and separation of concerns. So, while I think Manager concepts can be abused, I also believe it is overkill to simply "outlaw" their use in any situation.
Again, going back to the DriverManager example, I would say that such a class is a more natural fit for managing drivers, registering them, etc., than the Driver class itself.
I agree that static methods aren't very OO-compliant. Ironically, I think they exist in pure OO languages specifically because of the strong class orientation. So, they are at times, in effect, the "normal function that returns the appropriate object subclasses" that you prefer.
Dep: from my build tool, it's a dependency, like when you do #include "foo/bar.h", then foo/bar.o is the dep, and it is built from foo/bar.cc and foo/bar.h. It figures out the inputs and outputs and whether it needs to be rebuilt, and can do the building, too.
DepTracker: it tracks all of the Deps. It's responsible for creating them as necessary and making sure they're all built (compiled) and ultimately linked if building a binary.
HttpClient: uses libcurl, generates GETs and POSTs and the like, for tasks like fetching feeds (Atom/RSS), talking to Mozilla's Persona (browserid), and Stripe.
HttpServer: uses libmicrohttpd, and gives the program an embedded HTTP server. This is great for debugging info.
FormatPost: takes my flat text in and gives back formatted HTML for my "/w/" posts, Atom feed, or even the books.
MySQLClient, PGSQLClient: interfaces to those external libraries as you would assume.
ParseAtom, ParseRSS: turns different flavors of XML into something a little more reasonable for my own purposes.
TCPSource, USRPSource, OsmoSDRSource: for different kinds of GNU Radio input scenarios.
These are just a few of the larger set. The word "Manager" does not appear in any of them, but that wasn't a conscious decision. It just hasn't happened.
More importantly, the acceptance in the developer community that its ok to define large number of classes with that name is just a bad influence. Noun style is not a bad thing at all. Its just that when you think of everything as Nouns that things go downhill (which lead to naming things -Managers, -Handlers etc).
Yeah, not seeing it. If I "think of everything as Nouns" then I might go with "Noun" or "NounManager" as a name - but they're both nouns, and I don't see how pointing that out helps.
I completely agree with the point that "Manager" style classes are a warning sign that something could be usefully refactored. But if you're just going to refactor stuff into other nouns, and you're trapped in a noun-centric language anyway, I don't see any real connection between the advice on the one hand and the message about how trapped I am on the other.
If I need to know the precise behavior, I will generally look it up anyway, but I do not need to know the precise behavior of everything.
The problem isn't the name but the person who instead of renaming it went with a monolithic approach.
From a external perspective, using a thingManager is likelier to be easier, but from an internal perspective, having both a thing and a thingManager will force you to think about putting the logic in the correct place.
If your tools don't let you change class names easily, they have room for improvement.
Why is "connection" OK but "connecter" bad?
Neither connection nor connector would be good, under this view, if it's just a thin package around an imperative program ("COBOL written in Java").