5

Some of what I've been reading about this yesterday and today:

  • (SO) Should you avoid static classes?
  • (SO) When to Use Static Classes in C# - Mark S. Rasmussen makes a nice comment here
  • Singleton vs Static - Nice quote from here:
    These differences are extremely subtle but they do impact how resilient the system will hold up after years of subtle changes, new features, enhancements, etc. Most developers dislike system maintenance and I feel the biggest reason is because systems aren't really designed to be maintained. By incorporating the "singleton" pattern above, I've abstracted object creation and typing away from my core business logic which is critical to long-term maintenance.
  • Singleton Considered Stupid
  • (SO) Class with single method — best approach? - Once again, a quote from Mark S. Rasmussen:
    Demanding consumers to create an instance of classes for no reason; True utility classes that do not pose any risk to bloat are excellent cases for static methods - System.Convert as an example. If your project is a one-off with no requirements for future maintenance, the overall architecture really isn't very important - static or non static, doesn't really matter - development speed does, however.
  • (SO) Making Methods All Static in Class - Speed is not an issue right now for me, the code must work *PROPERLY* when called by multiple clients from the website and from (possibly, but unlikely) multiple clients from the admin app.

We are (I am) busy rewriting of of our main applications at the moment, and one of the projects in the solution is "Common" and it contains a single class, "clsCommon". This class has no properties, a single private method that is called as the only line in the constructor and then just public methods.

This class handles things like (not the real method names or signatures):

  • Copying files:
    • CopyFile
    • DecryptAndCopyFile
  • XML Settings File:
    • GetSpecificXMLValue (queries an XML settings file for a value)
    • SetSpecificXMLValue
    • DeleteSpecificXMLValue
  • Creating directories
  • Getting timestamps as strings (`return DateTime.Now.ToString("yyyyMMddHHmmss");`)
  • Various string functions on passed parameters
  • Writing out to log files.
  • Checking a passed string parameter if it contains only elements in a whitelist (the whitelist is `readonly` private List that is assigned a value in the constructor.)

Currently all the other projects in the solution have a reference to this project, and they provide access to the class by:

namespace Us.OtherProjects
{
   public class clsCommon : Us.Common.clsCommon
   {}
}

namespace Us.OtherProjects
{
   public static class clsMain
   {
         public static clsCommon CommonClsClassReferenceForGlobalUsage = new clsCommon();
         .
         .
         .
   }
}

namespace Us.OtherProjects
{
   public class clsOtherClass
   {
      .
      .
      .
         private void someMethod()
         {
            string something = clsMain.CommonClsClassReferenceForGlobalUsage.Foo();
         }
      .
      .
      .
   }
}

What are your opinions about making this class a static class, or maybe a singleton as described by Jon Skeet here?

Community
  • 1
  • 1
AndrewJacksonZA
  • 1,243
  • 2
  • 18
  • 31

2 Answers2

6

When i hear words Common, Manager, Helper I instantly think about code smell. There is nothing easier than naming class w/o actual meaning and just burrow huge plumbing code inside. Usually this happens when developer is too influenced with procedural programming.

Answering to question - I dislike static things in general (concurrency problems, harder instance life time management etc.). There are rare cases when static is useful and i believe this ain't one of these.


If 'wannabe static helper method' fits, write extension method. If it doesn't, then it should be in separate service or in base class of something (that depends on context).


So a class that manages things shouldn't be called SomethingManager? I disagree in that specific case

There are cases when it might be appropriate. But as i see it - 'XManager' just tells you that this 'Manager' class works with class 'X' and 'manages' something whatever 'managing' is supposed to mean. Helpers help with something. What exactly? Who knows - got to check out code. 'Common' is even more vague. Have seen every kind of stuff in such a classes/namespaces/projects (data access, security and UI related stuff tied together with business domain logic).


Hmmm... so maybe namespace Us.Common { public (static?) class Strings {} public (static?) class Files {} public (static?) class Settings {} } Opinions on this architecture change? Once again, I'm interested in maintainability and usability please.

You might find useful this post. According to it - it's Logical cohesion in Your case.

Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
  • 1
    +1 Agreed. Ayende provides the ultimate explanation IMO: http://ayende.com/Blog/archive/2009/04/29/let-us-burn-all-those-pesky-util-amp-common-libraries.aspx – Mark Seemann Feb 25 '10 at 09:40
  • 1
    So a class that manages things shouldn't be called SomethingManager? I disagree in that specific case. And frankly if you need a small specific operation that you perform in several different places on something, like an XmlDocument, I don't even consider a static helper class bad design as long as it doesn't become a "do everything" class. – Skurmedel Feb 25 '10 at 09:42
  • Hmmm... so maybe namespace Us.Common { public (static?) class Strings {} public (static?) class Files {} public (static?) class Settings {} } Opinions on this architecture change? Once again, I'm interested in maintainability and usability please. – AndrewJacksonZA Feb 25 '10 at 09:46
  • 1
    @AndrewJackson It's hard to answer how exactly you need to structure your code without knowing exact context. This architecture change isn't good enough for me, but it's better than having 'everything related' stuff inside one class. – Arnis Lapsa Feb 25 '10 at 09:55
  • Thanks for your help Arnis. Judging from your post I'm assuming that you can't recommend a better architecture based on the information that I've provided? – AndrewJacksonZA Feb 25 '10 at 10:30
  • 1
    Yes and no. And technically - i already did. Architecture just isn't simple enough to be passed around like an e-mail. Re-read answer by Henk and blog post by Ayende - i can't add much more to this topic. – Arnis Lapsa Feb 25 '10 at 10:58
5

The criterion here is state. If your class is just a container for independent functions (ie CopyFile, GetTimeStamp) a static class is the most logical approach. See the System.Math class.

However your class has a constructor and i assume it holds some state (name of config/log file). That calls for a Singleton.

Looking at the list of functionality, I think you should refactor this into several classes. Some can (and should) be static. Use Singleton(s) for the parts that need state, like Logging and Configuration etc.

The main design issue I see here is having 1 class that does Logging, Configuration, Formatting and a bunch of other stuff as well.

H H
  • 263,252
  • 30
  • 330
  • 514
  • The constructor just instantiates and adds the appropriate whitelist characters to the private readonly whiltelist. I'm also leaning towards a singleton, but I just have this feeling... something's bugging me about changing this class (which I know looks like a bucket containing random methods that are called from multiple projects that the original developers - from a VB6 background - might not have had the time to do correctly.) Like I said, this class is from the website code which we still have to rewrite and from the admin app - does this make a... – AndrewJacksonZA Feb 25 '10 at 10:28
  • difference at all? It doesn't appear to, but I'm not sure. Maybe just paranoia? :-) – AndrewJacksonZA Feb 25 '10 at 10:28
  • @Andrew, it does not matter all that much. You probably should follow the "if it is not broken, don't fix it" rule here. It sounds like the constructor could be eliminated entirely, would make thing a little easier. But you still haven' described what state (fields) it contains. – H H Feb 25 '10 at 10:37
  • @Henk: private readonly List m_DatabaseAttributeNameWhitelist; private const string THE_SYSTEM_XML_FILENAME = "MyConfigFile.xml"; private readonly string THE_SYSTEM_XML_PATH = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase.ToString()).Replace("file:\\", String.Empty), THE_SYSTEM_XML_FILENAME); private const string THE_SYSTEM_XML_SYSTEM_SECTION_NAME = "System"; private const char DATABASE_ATTRIBUTE_NAME_REPLACEMENT_CHARACTER = '_'; – AndrewJacksonZA Feb 25 '10 at 10:50
  • @Henk: Constructor contents: m_DatabaseAttributeNameWhitelist = new List(63); // Add 0 - 9, 'A' - 'Z', 'a' - 'z' and DATABASE_ATTRIBUTE_NAME_REPLACEMENT_CHARACTER to m_DatabaseAttributeNameWhitelist – AndrewJacksonZA Feb 25 '10 at 10:50