1

I have a generic helper class (1) that can be used in other projects also. Imagine something like basic handling of file and folders, something useful and DRY that always come in handy.

I have another class (2) that is project specific, but it uses the generic class (1) to accomplish things.

The generic helper class (1) is used by creating a new object of it in specific places where is needed in the project.

GenericHelperClass ghc = new GenericHelperClass();

Same goes for the project specific class (2), is being used by creating a new object of it in specific places where is needed in the project.

ProjectSpecificClass psc = new ProjectSpecificClass();

But as I said the project specific class (2) uses the generic helper class (1) to do stuff.

So here I thought, that the project specific class (2) should have its own private generic helper class (1) to do its job.

But wait, there is going to be an instance of that generic helper class (1) in the project already, so why creating another one? Let's just pass that instance of (1) on the constructor of (2).

So (2) is now created like:

GenericHelperClass ghc = new GenericHelperClass();
// code and code and code
// .
// .
ProjectSpecificClass psc = new ProjectSpecificClass(ghc);

with this I have only one object of GenericHelpClass, and I have avoided using static.

The question is: Am I wrong here or am I just creating spaghetti-dependencies or something? Any suggestions?

(the names selection GenericHelperClass/ProjectSpecificClass is just for demonstration)

  • 1
    It looks like your generic helper class violates the single responsibility principle (en.wikipedia.org/wiki/Single_responsibility_principle). – James Youngman Feb 7 '16 at 11:58
  • @JamesYoungman its a helper class for basic i/o functions, write file, check if directory exists, create directory and stuff like this, nothing fancy. This class can be used as is on another project without something extra or something missing. I'm very interested to know what made you think that it violates the single responsibility so i can re-check my architecture again. Thanks for your comment James! – Sharky Feb 8 '16 at 7:47
  • The question really, is what does an instance of this class represent? What does it do? A class whose functionality is a kitchen-sink-full of various things is generally in need of design revision. This kind of class also lends itself to being used as a singleton, which can then result in problems (depending on the language) where it's hard to unit test classes which depend on it (because e.g. sometimes the class is instantiated in such a way as to make dependency injection difficult). – James Youngman Feb 8 '16 at 21:01
  • @JamesYoungman thank you, i understand what you are saying. so let's say i'm in need of some basic io functions as the ones i described. since these stuff are always in need in various projects, isnt building a general helper class a good move? I know it may starts to look like a pile of random things (and possibly grow into one if it continues that way), but what is the other option? If not in a general helper class, then where to put a FileExists function without repeating myself? Thanks again, im all ears waiting for your response! – Sharky Feb 9 '16 at 7:07
  • 1
    If the only thing joining together the helper functionality you are building is its purpose, you could designate that with a namespace name (such as filesystem), rather than having a class containing only static methods. On the other hand, if the class would have non-static methods, then you're already part-way to figuring out the answer to my earlier question "what does this class represent?". – James Youngman Feb 20 '16 at 17:53
4

There are some reasons which can make this design the better alternative:

GenericHelperClass ghc = new GenericHelperClass();
// ...
// using `ghc` here for other purposes
//...
ProjectSpecificClass psc = new ProjectSpecificClass(ghc);
  • if the construction of ghc is slow or needs lots of resources, it might be better to construct the object only once

  • if after construction of ghc the object has to be initialized in a specific way before it can be used, it is better to do this initialization only once

  • you want to expect the constructor of ProjectSpecificClass an object of type IGenericHelperClass (an interface) to make it possible to "mock the object out" for unit testing purposes

If none of the reasons apply to your case, keep things as simple as possible for the user of ProjectSpecificClass and construct the object inside, where it is needed, even when this is done twice. Standard object construction in C# is very fast, as long as there is no "heavy-weight" constructor code in place.

  • Thank you for your answer. Creating that general helper twice (once in project and once internally in the project-specific-class) will surely make things less complex, and would lead to just forget about it. But i am willing to add a bit "complexity" should i say? by just creating the general helper one time and then make sure i am passing it to the project specific class. (Since wherever i use the project specific class there is always the general helper also already present). So i think i won't "keep things as simple as possible" for the sake of micro(?)optimization - not sure if actually – Sharky Feb 1 '16 at 14:31
  • ..worths it. Well whatever, it starts feeling like paralysis by analysis. i should move on. Thanks again Doc! – Sharky Feb 1 '16 at 14:31
  • 1
    I am pretty sure you can mock the object even without using an interface. The basic usage of dependency injections fulfills the contract. – Andy Feb 1 '16 at 15:12
1

My own thought on these sorts of helpers are in effect filling in lacuna in the standard library. They should therefore be held to the same sort of rigorous standards that the standard library is held to. Particularly if this helper class(es) is being used in multiple project, it is essential to validate it with extensive testing. Just as the presumed high quality, stability and general utility of the interface of the standard library justify tighter coupling than to other interfaces which lack these qualities, directly instantiating a GenericHelperClass on need is usually justifiable.

Of course the extent to which you should decouple from the GenericHelperClass depends not only on its quality and stability, but also the domain(s) in which it is used. If the GenericHelperClass forms part of the interface to external systems such as databases or web apis, it is generally worthwhile to decouple from it and program to an interface so that it may be replaced by a double for unit tests. In the other direction, if GenericHelperClass is used to implement well known, pure functionality -- think a base64 encoder, mathematical functions or utility methods on collections -- this will be a waste of effort. Indeed, for this sort of use, it is completely acceptable to make GenericHelperClass static. (It's for this reason that Math is generally a static class.)

So in conclusion, it's difficult to say whether coupling SpecificHelperClass to GenericHelperClass is a bad or good idea without knowing the purpose of those classes. One general quasi-solution is to provide multiple constructors for SpecificHelperClass, one that allows a double of GenericHelperClass to be used for testing purposes and a default one that just uses GenericHelperClass.

  • Thank you for your answer. It implements pure functionality, so it could be static, but i don't know it feels wrong. Mostly because that generic helper class is not used across the whole project, but only in some specific parts. Practically, static-ing it won't eat up significant resources, they are just a couple of functions, but theoretically its a waste having it static just idling there in memory for most of the time. – Sharky Feb 1 '16 at 13:55
  • 1
    @Sharky: "its a waste having it static just idling there in memory for most of the time" sounds like premature optimization. There are other reasons why a class might be not static, but what you wrote looks to me like a wrong reason. – Doc Brown Feb 1 '16 at 14:21
  • @DocBrown im hearing you. im a bit confused and burned out atm. and maybe years of badmouthing static's made me stubborn. – Sharky Feb 1 '16 at 14:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.