Sign in to follow this  
T1Oracle

Argument against "manager" classes

Recommended Posts

I know that usually inexperienced individuals do this, but I have even books that have "manager" written in sample code. I think that this needs to stop for the following reasons: 1) Most "manager" classes are just niave encapsulations (or worse, replacements) of standard STL containers. If you are keeping objects in a std::list then just define an std::list, 90% of the time you wil not benefit from some custom interface. STL containers are amazingly versatile things especially when combined with STL algorithms. The end user should not be robbed of the versatility of STL containers. 2) "Manager" is often used to describe classes that do a wide range of very different things. Some handle garbage collection, reference counting, memory allocation, thread synchronization, buffer creation and reuse, inter object communication. 3) Most "manager" classes can be more effectively replaced with the following solutions: - a) A simple raw STL container with 0 encapsulation - b) A version of the "mediator" pattern (look up Design Patterns) - c) A version of the "factory" pattern (look up Desing Patterns). There is no reason why a Factory cannot contain data that is shared between instances of the created object. - d) This is an idea that I am modifying, but... A "resource pool" pattern. I consider a "factory" that maintains a list of objects for reuse of those objects by multiple users as a "resource pool." There are many types of "pools" demonstrated by programmers far better than me. I have seen VBO pools, streaming buffer pools, thread pools, etc... - d continued) Essentially, anytime that you have an object who's creation and destruction is costly there is a chance that a pool is the solution. Instead of destroying the object you keep it in memory and reassign it to another user when it is needed again. It is also a good solution for when the same data is used by multiple object instances (ie, a mesh used by several different instances of an Entity). When the object is loaded into memory you can hold on to a copy of it, pass out a const (which is an obvious limitation) reference so that it is not copied, and divy out references everytime that same data is requested. Regardless of what specific solution that your application needs the fact still remains that the term "manager" will provide zero hint as to what you are actually describing. Programming is a very exacting science, even in the midst of abstractions, if you are not clear on what it is that is being designed, then it will generate ambiguity. Ambiguity leads to buggy, sloppy, unmaintainable software. If you get the inclining to call something a "manager" please stop first, think about it, and then try to understand what it is that you really need. Chances are that you will come up with a better performing, more versatile, and less ambiguous solution. There are many options out there, please consider them. Also as a side but still slightly related rant... Please stop using "char *" as an ID for everything. Every engine I see does this, and many "manager" classes do this as well. Numbers are faster, std::string's are less error prone, and everytime you rely on abritrary strings as ID's you force every other part of you engine to adapt to that dependance. Maybe this is what you want, but the chances are that there are other solutions that would allow for much looser coupling. Yes... Loose Coupling is a good thing!

Share this post


Link to post
Share on other sites
Personally, I've always considered a manager as an object that tracks a collection (or collections) of objects and performs actions on the set of objects or a subset thereof. For example: A RenderManager class holds a collection of references to all objects in the world. It stores them in an octree (or whatever structure you want). Calling "RenderManager::Render (target)" for example would then render all the visible objects to the specified target.

To sum up then, a manager is a collection with added functionality common to all contained objects.

As for object IDs - use GUIDs rather than ints. GUIDs are guaranteed to be unique (and DevStudio has a tool to create them). I would personally tie them to a char */string type in debug builds as well just to make debugging easier (using an ID class).

Skizz

Share this post


Link to post
Share on other sites
Quote:
Original post by T1Oracle
3) Most "manager" classes can be more effectively replaced with the following solutions:
- c) A version of the "factory" pattern (look up Desing Patterns).

Ok well, this is true for most of my 'Manager'-classes: they are factories with some extra sugar (keeping track of used memory etc).
What I'm not sure if I understand correctly, have you just written a 500+-word rant to persuade me to call my TextureManager a TextureFactory? [wink]

Share this post


Link to post
Share on other sites
Sorry but managers are great. I do think sometimes they are over-used, however for resource management they are an excelent choice.

1 - Managers provide functions to edit items WITHIN a list. Just having some STL global container does not provide the same functionality as a manager so you can't really compare them. A manager provides a nice way to organise and expose functions that edit/insert/delete items that its holding. If you don't have a manger and just provide a global array/list/vector then your going to have to keep re-writing the code to edit the list all over the place. Hence a manager - it keeps all the functions dealing with the list in a nice centralised place. And it makes the code reusable as its easy to remove that class and insert it into your next project (while its not easy to dig through all your code that changes a list had you just provided a global link).

2 - So you don't like that manager is a widely used name? How does that make them less valualbe?

3 - I would say the half the things you mentioned in that list ARE managers. You already stated that the term manager covers a wide range of topics, then you say that managers could be replaced with some very specific things - aren't you just listing what a good manager should do?


I'm still not really clear why you hate managers? Infact I don't even really know what you think managers are. Personally I've used managers many times in both my homebrew and profeshinal games and when used correctly they are great. I'd never start a project without cut+pasting my texture/mesh/sound managers in first - they just make everything so much easier and never once have they even shown up on my profiler. Personally mine are fast, they are very reusable, and they are easy to maintain because all the code is packaged nicely into on single class. Whats not to like?

Share this post


Link to post
Share on other sites
I appologize if any of this sounds mean, my intent is not malice.

Quote:
Original post by Skizz
tracks a collection (or collections) of objects and performs actions

Key phrase "peforms actions," those actions are very important. In fact the most important detail of a class to the user is not what it contains but what it does with it. "Performs actions" is a very non-descript (read "ambiguous) way to cause trouble.
Quote:
Original post by Skizz
It stores them in an octree (or whatever structure you want)

Awesome, and now your "RenderManager" is coupled to collision detection and/or view frustrum culling.

Furthermore, think about the phrase "whatever structure you want." So, what again is a "RenderManger"? Oh yea a "RenderManger" is "whatever structure you want."


Quote:
Original post by Skizz
As for object IDs - use GUIDs rather than ints. GUIDs are guaranteed to be unique (and DevStudio has a tool to create them

Why can't an int be a GUID?

typedef int GUID;

class GUIDFactory
{
public:
// guaranteed to return a globally unique id per instance of GUIDFactory
GUID GetGUID() { return oldID++; };
private:
GUID oldID;
};



I believe that the term "manager" is a temptation that lures in and then narrows the minds of programmers. If you understand your problem thoroughly then you will that what you are doing can be described in specific terms, and you will likely see that there are more optimal ways to do those things. There is no one "blanket" answer. For an "optimal" (even a somewhat optimal) solution, each problem must be dealt with in terms of its unique circumstances.

Share this post


Link to post
Share on other sites
Quote:
Original post by T1Oracle
I believe that the term "manager" is a temptation that lures in and then narrows the minds of programmers.


lol - now we get to your real argument. You just don't like the term manager. The fact the term doesn't have a very finite definition in no way "narrows the minds of programmers". The fact that they are illdefined is actually a benifit in my mind. I hate people who just stick to design patterns for the sake of it as if somehow that'll make them write good code. Code that has a fancy name is not better code (infact in my experience is usually worse). You can write a manager todo whatever you want, however you want and its still a manager. That doesn't make managers bad - that makes them awsome :P

Share this post


Link to post
Share on other sites
Quote:
Original post by kaysik
1 - Managers provide functions to edit items WITHIN a list.

So does the STL. Ever heard of remove_if, copy_if, transform, for_each? The STL has plenty of useful algorithms. If your application really needs encapsulation on this level then you are most likely in need of a flyweight pattern or maybe a composite.


Quote:
Original post by kaysik
2 - So you don't like that manager is a widely used name? How does that make them less valualbe?

A name is a brief yet meaningful summary of what an object does.

Quote:
Original post by kaysik
I would say the half the things you mentioned in that list ARE managers. You already stated that the term manager covers a wide range of topics, then you say that managers could be replaced with some very specific things - aren't you just listing what a good manager should do?

Then how does it make any less sense to define the entire application as a manager. After all, your program (game, app, whatever...) only does what a good manager should do. It encapsulates it interal data and performs actions on them What simpler definition of a program could there possibly be?

Quote:
Original post by kaysik
never once have they even shown up on my profiler

Did you compare them against any other solutions? What about versatility, loose coupling, and code size? How much of those "managers" aren't even being used? How much code are you writting just to deal with the specific querks of a given "manager?" How much work would you have to do to add in a feature not supported by that "manager?" How much refactoring would be needed to swap one "manager" for another?

When you get the term "manager" what exactly are you guaranteed?

Share this post


Link to post
Share on other sites
Quote:
Original post by kaysik
Code that has a fancy name is not better code (infact in my experience is usually worse)

It is not a name, it is a gaurantee of specific functionality. It is a contract between the user and the library that is partially communicated by the name itself.

It is not about design patterns either. Those are examples of a more specific option in place of the "term" manager.

The saddest thing about "managers" is that they almost always do more than they should and require more of the user than they should.

If the programmer understood their problem domain they would not impose unnessary limitations on the user.

Share this post


Link to post
Share on other sites
class AClassWithAID
{
public:
AClassWithAID():
ID((int)this)
{
}

int ID() { return mID }

private:
int ID;
}


Now every ID is garuanteed to be unique :-)

Share this post


Link to post
Share on other sites
See also: Don't name classes Object, Manager, Handler, Data.

Personally I hate 'manager' in class names, for a few reasons.

1. FooManager is an invitation for other programmers to lump in anything even slightly foo-related into the same class. Before long you've got a massive behemoth of a class that's doing everything and anything.

2. The use of 'manager' in the name implies one of two things - either the class should be better named (eg. FooFactory, FooPool, FooList), or that theres really two or more classes being lumped into one. Case in point:

Quote:
Ok well, this is true for most of my 'Manager'-classes: they are factories with some extra sugar (keeping track of used memory etc).

What you probably should have here is a FooFactory and a FooMemoryTracker instead of a single FooManager.
- You maintain single-responsibility princible for classes.
- Code functionality and data is more localised (less to go wrong, more robust).
- Better code reuse, you could probably have lots of different factories but a single tracker class that works with them all.

Share this post


Link to post
Share on other sites
Quote:
Original post by T1Oracle
So does the STL. Ever heard of remove_if, copy_if, transform, for_each? The STL has plenty of useful algorithms.


Yes - but thats not what I meant. It doesn't perform operations ON the list, but WITHIN it. Take my entity manager, every time you create an entity it needs to have its spawn timer set, and it needs to have its spawn script run. If I didn't have an enitty manager I'd have to either put that code manually in every function which created an entity (a pain in the butt), or I'd have to write a standalone function todo it. Why wouldn't I put that function (and the rest like it) with my entity "manager"? My manager also, adds the item to the list and does memory management etc, but its most usefull functions are the specifics which no STL algorithm can do because they are unique.


Quote:
Original post by T1Oracle
A name is a brief yet meaningful summary of what an object does.


Exactly - my managers "manage" my resources :P I don't see how a "factory" or "flyweight pattern" is any more descriptive than "manager".



Quote:
Original post by T1Oracle
Then how does it make any less sense to define the entire application as a manager.


lol - true, I'd also say my IDE manages my code an is therefor a manager. And because I manage the IDE i'm its manager. yay - infinite loop of joy. But that doesn't take away from the fact my resource managers manage my resources ...



Quote:
Original post by T1Oracle
What about versatility, loose coupling, and code size? How much of those "managers" aren't even being used? How much code are you writting just to deal with the specific querks of a given "manager?" How much work would you have to do to add in a feature not supported by that "manager?" How much refactoring would be needed to swap one "manager" for another?


- My managers are about 300-500 lines long on average ... I'd say about 80% of that is the actual resource loading (which you have to put somewhere so is unavoidable).
- I use all my managers - otherwise I wouldn't still keep them around.
- What do you mean specific quirks? The whole point of managers is to DEAL with the quirks of a chosen resourse so I'd have to say 100% of it is for quirks.
- Less code because off the manager. I'd only have to add it inside the manager, and expose a function or two to use it. If it wasn't inside a manager who knows how much code I'd have to tie in from random places to use it.
- No refactoring would be needed. My managers all return int ID's, and accept int ID's to todo whatever it is they do so I'd only every need to change the manager. I did this too ages ago when I change from .tga loading to .png - only change my texture manager and no other code.


Quote:
Original post by T1Oracle
When you get the term "manager" what exactly are you guaranteed?


Like I said - thats not a downside in my oppinion. I know exactly what I'm garenteed by MY managers ... if I gave you my class called "ManagerTexture" with has a int load(std:string fname); then i'm pretty sure you can tell what it does. If you give me a class called "FlyweightTexture" then I'd probably assume it loaded really small textures :P

Share this post


Link to post
Share on other sites
After fully reading all links posted and the definitions of those design patterns I didn't already know (read: flyweight) I still won't be renameing my classes. This is actual a style war. We both hate bad code with poor design, yet I don't see the name of a class as a factor in that - you do. Its not that I like vague classes with alot of useless and unrelated junk in them, its that I wouldn't write a manager like that so don't see the two as related! I'll grant you that if someone knows enough to follow a design patter then its harder to screw up, but I'm sure there are alot of EntityFactorie classes out ther with alot of bloat :P

I can see where your comming from, but I still say bad code isn't related to the term manager, its related to knowledge, skill and experience.



Oh and in keeping with all style wars: Curly brackets on a new line 4EVA!!!

Share this post


Link to post
Share on other sites
The main problem with "managers" is that everybody means a bit a different thing; there is no common definition of that term. So the term is widely used, and perhaps we understand something different. But these are my thoughts about that:

Managers implemented for resources like textures, sound, and so on normally provide a client transparent caching perhaps with a policy like LRU, and they may hide whether resources are loaded from individual files, archives, or the network. This is true additional functionality compared to containers available from STL. IMHO managers in this sense are okay. Whether you name this class a ResourceManager or a ResourcePool makes no real difference.

The above has something of the Factory pattern, correct. A Manager implemented by the Mediator pattern, well, I personally hasn't such a need yet, but perhaps that comes from my understanding of what a Manager is.

Coming to more esoteric thoughts, it is good practice to hide clients from implementation details. E.g. in Java there is a LinkedList class implementing the more general List class, itself implementing the even more general Collection class. Well, Collection and List are abstract and LinkedList can be instantiated (is an _implementation_ class). Recommended practice is to declare the member at most as a List and initializing it with a LinkedList (as an example). Granting client access to it should be done, if necessary at all, by an Iterator. Notice please that also std::list is an implementation class, and a (well written) Manager encapsulates its internally used std::list by generalizing the access without exposing the inner implementation. Generalizing accesses allows exchange without touching clients.

Maybe managers are overused, but that cannot mean that they are senseless.

Quote:
Original post by kaysik
I hate people who just stick to design patterns for the sake of it as if somehow that'll make them write good code. Code that has a fancy name is not better code (infact in my experience is usually worse).

Of course, using patterns just to use them isn't good practice. IMHO, the benefit of knowing (enough) patterns is that in practice one notices problems to be of the one or other kind since they look like the typical problem of the one or other pattern, and hence can be solved in a way at least similar to what the matching patterns suggest. Effective programming is mostly based on experience, and patterns are a kind of "tinned experience". Knowing patterns allows a more effective discussion of problem solutions; I see that weekly in our company.

Share this post


Link to post
Share on other sites
Quote:
Original post by OrangyTang
*genious indepth sense and understanding*

Thank you, I agree on all of your points.
Quote:
Original post by kaysik
Take my entity manager, every time you create an entity it needs to have its spawn timer set, and it needs to have its spawn script run.

Sounds like something that needs to be deligated down to the entity objects themselves. Either that or you need a EntityFactory which makes it clear what is being down with entities by this object. The EntityFactory is creating entities, it is not doing anything (on the user end) outside the scope of creating them. It may do some background stuff necessary during creation, but it not called on after creation.


Quote:
Original post by kaysik
Exactly - my managers "manage" my resources :P I don't see how a "factory" or "flyweight pattern" is any more descriptive than "manager".

Factories create objects, flyweights perform operations on them. These two constructs are not the same thing and most likely should not be.

Quote:
Original post by kaysik
resource managers manage my resources ...

Which means? Oh yea "whatever you want."

Quote:
Original post by kaysik
- No refactoring would be needed. My managers all return int ID's, and accept int ID's to todo whatever it is they do so I'd only every need to change the manager. I did this too ages ago when I change from .tga loading to .png - only change my texture manager and no other code.

What if you wanted to use something other than int ID's? You'd have to refactor all of your managers. What if you wanted resource loading to be handled through a packed resource file? Then you would have to refactor all of your managers since they are tightly coupled to your current IO methods. What if you wanted to employ a memory pool? You would have to refactor all affected managers to allow for resource pools. As the details change the refactoring will only get more complex and eventually you will forget what everything does. At some point (given that you work on anything large) the actual function of the objects within your software will escape you.


Quote:
Original post by kaysik
Like I said - thats not a downside in my oppinion. I know exactly what I'm garenteed by MY managers ... if I gave you my class called "ManagerTexture" with has a int load(std:string fname); then i'm pretty sure you can tell what it does. If you give me a class called "FlyweightTexture" then I'd probably assume it loaded really small textures :P

What does a "TextureFactory" do? The same exact thing that an "EntityFactory" does except for textures. If you need a texture object, then the "TextureFactory" will create on.

What does a "TexturePool" do? The same exact thing that a "MeshPool" does except for textures. If you need a texture and you don't want duplicate copies of the same texture in RAM, then acquire it from the pool.

If you had a fixed and restricting definition for what a "Manager" within your given application is. Then you can make it into your own pattern and it will be just as legitimate. It may not have a great name, but a defined meaning is the important fundamental here. Names should carry meaning, and objects have a defined domain over which they operate. Just as OrangyTang said:
Quote:
Original post by kaysik
1. FooManager is an invitation for other programmers to lump in anything even slightly foo-related into the same class. Before long you've got a massive behemoth of a class that's doing everything and anything.

That is a recipe for bad design. However, if you give "manager" a specific definiton for your system and follow it, then you can evade that problem.

Perhaps the real issue here is:
1) Names, no matter how you spell them, should have well defined unambiguous meanings.
2) Objects and methods should not be lumped together simply because they affect the same set of classes. Objects and methods should be put together according to have they function, and how they vary.

*Edit, quotes fixed sorry OrangyTang*

Share this post


Link to post
Share on other sites
Quote:
Original post by T1Oracle
I appologize if any of this sounds mean, my intent is not malice.

Quote:
Original post by Skizz
tracks a collection (or collections) of objects and performs actions

Key phrase "peforms actions," those actions are very important. In fact the most important detail of a class to the user is not what it contains but what it does with it. "Performs actions" is a very non-descript (read "ambiguous) way to cause trouble.
Quote:
Original post by Skizz
It stores them in an octree (or whatever structure you want)

Awesome, and now your "RenderManager" is coupled to collision detection and/or view frustrum culling.

Furthermore, think about the phrase "whatever structure you want." So, what again is a "RenderManger"? Oh yea a "RenderManger" is "whatever structure you want."

The point I was making was that somewhere you'd want a class that organsised a collection of objects in such a way that, in my example, rendering them was efficent. It has to be done somewhere. It can't be decoupled - it is the thing doing the spatial organisation. Something has to organise it. I called it RenderManager because it organises the objects within it and renders them. How it does it is totally decoupled from users of the class.

The dictionary definition of manager includes:
Quote:

a person who controls and manipulates resources and expenditures, as of a household.

which does match my RenderManager example. The RenderManager is a class that controls and manipulates objects(resources).


Quote:

Quote:
Original post by Skizz
As for object IDs - use GUIDs rather than ints. GUIDs are guaranteed to be unique (and DevStudio has a tool to create them

Why can't an int be a GUID?

GUID has a very specific meaning. It's a 128-bit number hashed from various sources (MAC address, time, etc...). Windows has built in support for creating them. You can probably get libraries for other OSes. Your ID generation is problematic in that it will cause unusual effects when used in networked environment (multiplayer games) or possibly in multithreaded scenarios. GUIDs are globally unique.

Skizz

Share this post


Link to post
Share on other sites
Quote:
Original post by Julian90
class AClassWithAID
{
public:
AClassWithAID():
ID((int)this)
{
}

int ID() { return mID }

private:
int ID;
}


Now every ID is garuanteed to be unique :-)


A very bad way of doing it.

ObjectWithID *obj1 = new ObjectWithID;
delete obj1;
AnotherObjectWithID obj2 = new AnotherObjectWithID; // this will very likely have the same address!

How would an observer know if the object it is observing was destroyed? Sometimes another object can be created and have the same ID.

Skizz

Share this post


Link to post
Share on other sites
Quote:
Original post by Skizz
Quote:
Original post by Julian90
class AClassWithAID
{
public:
AClassWithAID():
ID((int)this)
{
}

int ID() { return mID }

private:
int ID;
}


Now every ID is garuanteed to be unique :-)


A very bad way of doing it.

ObjectWithID *obj1 = new ObjectWithID;
delete obj1;
AnotherObjectWithID obj2 = new AnotherObjectWithID; // this will very likely have the same address!

How would an observer know if the object it is observing was destroyed? Sometimes another object can be created and have the same ID.

Skizz


I know i was wondering how long it would take for someone to point out how atrocious it was.

Another flaw is as follows:

as i recall int is defined as an integer with at least 2 bytes and at most 4 bytes however on a 64 bit system one object may be allocated at 0x0000000000000001 and another at 0x0000000100000001 which when cast to an int they will most lickly both end up as 0x00000001. :-)

It also suffers the same network problems as mentioned above

Share this post


Link to post
Share on other sites
Quote:
Original post by Skizz
Quote:
Original post by T1Oracle
I appologize if any of this sounds mean, my intent is not malice.

Quote:
Original post by Skizz
tracks a collection (or collections) of objects and performs actions

Key phrase "peforms actions," those actions are very important. In fact the most important detail of a class to the user is not what it contains but what it does with it. "Performs actions" is a very non-descript (read "ambiguous) way to cause trouble.
Quote:
Original post by Skizz
It stores them in an octree (or whatever structure you want)

Awesome, and now your "RenderManager" is coupled to collision detection and/or view frustrum culling.

Furthermore, think about the phrase "whatever structure you want." So, what again is a "RenderManger"? Oh yea a "RenderManger" is "whatever structure you want."

It can't be decoupled - it is the thing doing the spatial organisation. Something has to organise it.

Yes it can be decoupled and by your example there I sounds like it very well should be. Collision detection and rendering are not the same thing. Afterall, why don't you just make one large class that does everything and call it Game?

Regardless, decoupling the tree from the renderer is trivial. Just have a renderer that takes a BVH (bounding volumen hierarchy which is what an octree is), a camera, and renders the visible geometry when RenderScene() is called. The render can even own instances of those objects.

Regardless, the render is a "renderer" not a manager. The other parts needed in the process of rendering are delegated down to separate objects. There is no reason why this must add a performance penalty. It may even make things faster as the actually problem space will be clearer with proper design.

The issue here is "layering."
Quote:
Original post by Skizz
The dictionary definition of manager includes:
Quote:

a person who controls and manipulates resources and expenditures, as of a household.

which does match my RenderManager example. The RenderManager is a class that controls and manipulates objects(resources).

Program: Software that controls and manipulates data.

Quote:
Original post by Skizz
GUID has a very specific meaning. It's a 128-bit number hashed from various sources (MAC address, time, etc...). Windows has built in support for creating them. You can probably get libraries for other OSes. Your ID generation is problematic in that it will cause unusual effects when used in networked environment (multiplayer games) or possibly in multithreaded scenarios. GUIDs are globally unique.

Skizz

The meaning of "globally unique" depends on the scope of the application. MS have its own definition and implementation, but it not absolute necessity that you application follows that definition nor is there any guarantee that Microsoft's GUID will be optimal for your specific needs.

The actual usage of the ID is very important in determining its proper use. Throwing GUID's at everything that needs searchable identy is not only bad design but it may also cost you performance (time calculating a GUID, RAM storing 128 bits when 32 or any other lesser value will do).

Furthermore, there is no such thing as a truly global unique identifyer that is unique over all world wide possible instances. At some point a GUID algorithm will produce the same number twice. See the tread on random numbers.

Simpler more optimal solutions are possible given a more specific problem. For one thing, a networked may not even need the MAC address to be a factor in the hash, the player's login name may be more than adequate.

Share this post


Link to post
Share on other sites
There are certainly situations where an object performing managerial duties on a collection of other objects is appropriate and correct. Yes, sometimes managerial objects are mis- or over-used (just like singletons; in fact these often go hand-in-hand), but that doesn't speak to a flaw in the concept of a managing entity.

When it is correct to use a managing entity, for example, it is not correct to replace that entity with a SC++L container, because in doing so you both violate encapsulation (as you even said: "an STL container with 0 encapsulation") or make it impossible to enforce invariants that must be maintained on the set of objects as a whole, such as actions performed when objects are added to or removed from the set (which is usually not functionality that can be placed into the objects themselves without tightly coupling the objects to the manager, because as you mentioned, tight coupling is generally bad) or maintaining a certain ordering in the case of an orderable container.

Furthermore the bulk of your arguments, when they aren't against mis- or over- use (which again is hardly the fault of concept itself, rather the programmers using it), seem to be about nomenclature; the fact that the term "manager" has no concrete description about what, exactly, the managerial duties actually are.

Well, yes. But the same problem applies to "factory," (it constructs things, but who knows how?), "pool," (it is some kind of shared/common collection of things, but who knows what kind of collection?), "resource," "engine," et cetera. Just about any common term has some element of ambiguity unless placed in the proper context. The best you can hope from the term "manager" is the same thing you can hope from those terms and others: "something that performs a certain kind of controlling or guiding action on a set of things." What those actions are are context-specific, and unless you start using stupidly long type names, that will always be the case, so I don't really see what the problem is.

Note that this is not an argument that "FooManager" is an acceptable name (it may not be, as OrangyTang pointed out). This is an argument that entities performing managerial functions are not inherently "evil." Picking type names that aren't stupid is an entirely different issue.

Share this post


Link to post
Share on other sites
Quote:
T1Oracle said:
Yes it can be decoupled and by your example there I sounds like it very well should be. Collision detection and rendering are not the same thing. Afterall, why don't you just make one large class that does everything and call it Game?

I have never, in any of my posts in this thread, mentioned collision detection. Why then do you assume I am including collision in my argument? That is something you have added to my example and then used as a counter argument. Octrees can be used for many things other than collision (sparse three dimensional arrays, for example).

To expand my case (to include collision!):

RenderManager: Handles spatial organisation of objects, efficently draws visible objects.

CollisionManager: Handles spatial organisation of objects, efficently handles collision detection.

The organisation of the objects does not need to be the same (and probably won't be). The set of objects managed by the RenderManager does not have to be the same of those managed by the CollisionManager. Missiles could, for example, be renderable objects but not collidable objects (i.e. nothing can hit them). They do collide against other objects so do use the CollisionManager. Invisible force fields are collidable but not renderable. They could use a common, shared storage. They could use separate storage. They could use a another class to store data, they could implement their own system. It really doesn't matter. The details are hidden from users of the managers.

To emphasise my use of manager: ThingManager only does actions to objects related to Thing, so RenderManager only renders things (nothing else, at all, no collision, no AI, no anything else!), CollisionManager only does collision, AIManager only does AI related things, ResourceManager only does resource handling. I find this use of "Manager" to be useful - a thing that handles a group of related things.

Skizz

Share this post


Link to post
Share on other sites
Quote:
Original post by Skizz
Personally, I've always considered a manager as an object that tracks a collection (or collections) of objects and performs actions on the set of objects or a subset thereof. For example: A RenderManager class holds a collection of references to all objects in the world. It stores them in an octree (or whatever structure you want). Calling "RenderManager::Render (target)" for example would then render all the visible objects to the specified target.

You mean
fmap render octree
? Manager classes are used in languages that don't have support for functions free from classes and/or higher order functions. It's really a pattern used as a workaround for the limitation of the language. The more "managers" you see in the source code, the shittier your host language is. For example, you'll almost never see "managers" in Haskell or Lisp, you'll see them show up in places in C++, and you'll see them scattered all over Java code.

Share this post


Link to post
Share on other sites
I totally agree with jpetrie. It is all about invariants and encapsulation.

Design patterns have very specific meanings. If something is called a factory, I would assume it always returns a newly created object. If something is called a pool, I assume is a resource optimization, etc.

Managers seem like a specialization of the facade pattern. They are 'glue' that presents a unified interface to other more complex systems. For example, a TextureManager may internally use a Pool and a Factory to create textures. It may support methods for making queries about the number of textures in memory, the amount of memory space they take, etc.

Yes, these could be done by iterating over all of the textures manually everywhere to calculate this info, but the manager could cache it (as an invariant) when textures and created/destroyed. This would be more efficient as well as more encapsulated.

Share this post


Link to post
Share on other sites
Quote:
Original post by BrianL
I totally agree with jpetrie. It is all about invariants and encapsulation.

Design patterns have very specific meanings. If something is called a factory, I would assume it always returns a newly created object. If something is called a pool, I assume is a resource optimization, etc.

Managers seem like a specialization of the facade pattern. They are 'glue' that presents a unified interface to other more complex systems. For example, a TextureManager may internally use a Pool and a Factory to create textures. It may support methods for making queries about the number of textures in memory, the amount of memory space they take, etc.

Yes, these could be done by iterating over all of the textures manually everywhere to calculate this info, but the manager could cache it (as an invariant) when textures and created/destroyed. This would be more efficient as well as more encapsulated.

You make an intersting claim however lets point a few things out:

1) Factory
a. Definition: Well defined while still abstract - A Factory is an object which encapsulates the details needed to create certain concrete objects. This may be realized through the Abstract Factory which only returns abstract pointers, or the Factory Method who's returned object is decided by the set parameters.
b. Scope: Has a limited scope in which it may be applied - If it does not return newly created objects then it is not a factory.
c. Application: Not all objects are Factories.

2) Pool
a. Definition: Well defined while still abstract - A variation of the Factory pattern that optimizes the allocation of memory by pooling resources for memory resuse inplace of constant allocation and deallocation of RAM.
b. Scope: Has a limited scope in which it may be applied - If it does not optimize the use or memory by restricting the occurance of memory allocation and deallocation then it is not a pool.
c. Application: Not all objects are Pools.

3) Facade
a. Definition: Well defined while still abstract and leaves out a lot of impelementation details in favor of a focus on the interface - An object that provides a simplified interface to a larger body of code.
b. Scope: Has a limited scope in which it may be applied - If it does not produce an interface which simplifies the complexity of a greater system, then it is not a facade.
c. Application: Not all objects are Facades

4) Manager
a. Definition: The epitome of ambiguity - Something which stores data and performs actions on it.
b. Scope: Anything and everything in software fits under the definition of manager.
c. Application: All objects are managers, all programs are managers.

The term manager is generally used under the following conditions:
1) The programmer does not fully understand their problem space
2) The programmer seeks an easy out to true design by lumping all Foo related things into one giant FooManager.
3) Do to the lack of a true design step, the programmer is unaware of other possible means for organizing data, methods, and responsibilities in a more thoroughly contrived manner.
4) Since everything is a manager, you might as well call it a manager.

Share this post


Link to post
Share on other sites
You say that managers are "the epitome of ambiguity". Well, there's this thing called documentation which can be used to resolve ambiguities. Look:

//-------------------------------------------------------------------------------
// Class: RenderManager
//
// Description: A specialisation of the facade design pattern, this class
// provides methods for add/removing objects to the set of
// renderable objects and for efficently rendering the objects.
//
// Interface: AddObject - adds object to set of renderable objects
// RemoveObject - removes object from set of renderable objects
// Render - renders all objects within a view volume to a target
//
// Implementation: Internally, the render manager uses two octrees, one for
// all the static geometry in the scene and one for the dynamic
// objects. When rendering, the octrees are used to cull objects.
//
//-------------------------------------------------------------------------------

class RenderManager
{
// the code!
};

Now, you could have called the class RenderFacade but I think more people would know what a RenderManager did from the name alone without looking at any documentation.

The main point is that 'manager' is just a word, a word with a definition that closely matches what the programmer is trying to do.

What would you call the above class?

Skizz

Share this post


Link to post
Share on other sites
Quote:
Original post by Skizz
Now, you could have called the class RenderFacade but I think more people would know what a RenderManager did from the name alone without looking at any documentation.

We are (at least I am) aiming our libraries at C++ OO programmers, and such programmers should know what the facade pattern is.

Quote:
provides methods for add/removing objects to the set of
renderable objects and for efficently rendering the objects.
(Emphasis added)
And? It seems you have fallen into the trap many people pointed out, just putting lots of functionality into a single class. One class shouldn't have more than one responsibility.

Quote:
The main point is that 'manager' is just a word, a word with a definition that closely matches what the programmer is trying to do.

Yes, but because two programmers' definition might not match they might misunderstand each other.

Quote:
What would you call the above class?


I'd probably split it into a RenderList and a Renderer, but to make a good decision one would need to know something about the design of the rendering system.

EDIT:
Quote:
You say that managers are "the epitome of ambiguity". Well, there's this thing called documentation which can be used to resolve ambiguities.

Isn't self-documenting code a good idea?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this