Moo-Juice
Moo-Juice

Reputation: 38820

Possible Valid Use of a Singleton?

I've got to the point in my design, where I am seriously considering a singleton.

As we all know, the "common" argument is "Never do it! It's terrible!", as if we'd littered our code with a bunch of goto statements.

ServiceStack is a wonderful framework. Myself and my team are sold on it, and we have a complicated web-service based infrastructure to implement. I have been encouraging an asynchronous design, and where possible - using SendAsync on the service-stack clients.

Given we have all these different systems doing different things, it occurred to me I'd like to have a common logger, (A web service in itself actually, with a fall-back to a local text file if the web service is not available - e.g. some demons are stalking the building). Whilst I am a big fan of Dependency Injection, it doesn't seem clean (at least, to me) to be passing a reference to a "use this logger client" to every single asynchronous request.

Given that ServiceStack's failure signature is a Func<TRESPONSE, Exception> (and I have no fault with this), I am not even sure that if the enclosing method that made the call in the first place would have a valid handle.

However, if we had a singleton logger at this point, it doesn't matter where we are in the world, what thread we are on, and what part of a myriad of anonymous functions we are in.

Is this an accepted valid case, or is it a non-argument - down with singletons?

Upvotes: 5

Views: 293

Answers (4)

mythz
mythz

Reputation: 143369

Logging is one of the areas which makes sense to be a singleton, it should never have any side-effects to your code and you will almost always want the same logger to be used globally. The primary thing you should be concerned with when using Singletons is ThreadSafety, which in the case of most Loggers, they're ThreadSafe by default.

ServiceStack's Logging API allows you to both provide a substitutable Logging implementation by configuring it globally on App_Start with:

LogManager.LogFactory = new Log4NetFactory(configureLog4Net:true);

After this point every class now has access to Log4Net's logger defined in the Factory above:

class Any
{
    static ILog log = LogManager.GetLogger(typeof(Any));
}

In all Test projects I prefer everything to be logged to the Console, so I just need to set it once with:

LogManager.LogFactory = new ConsoleLogFactory();

By default ServiceStack.Logging, logs to a benign NullLogger which ignores each log entry.

Upvotes: 3

Alexander
Alexander

Reputation: 4173

There's only one problem with classic implementation of a singleton - it is easily accessible, and provokes direct use, which leads to strong coupling, god objects, etc.

under classic implementation I mean this:

class Singleton
{
   public static readonly Singleton Instance = new Singleton();
   private Singleton(){}
   public void Foo(){}
   public void Bar(){}
}

If you use singleton only in terms of an object lifecycle strategy, and let IoC framework manage this for you, maintaining loose coupling - there is nothing wrong with having 'just one' instance of a class for entire lifetime of application, as long as you make sure it is thread-safe.

Upvotes: 3

Wiktor Zychla
Wiktor Zychla

Reputation: 48279

As always, I prefer to have a factory. This way I can change the implementation in future and maintain the client contract.

You could say that singleton's implmenentation could also change but factories are just more general. For example, the factory could implement arbitrary lifetime policy and change this policy over time or according to your needs. On the other hand, while this is technically possible to implement different lifetime policies for a singleton, what you get then should probably not be considered a "singleton" but rather a "singleton with specific lifetime policy". And this is probably just as bad as it sounds.

Whenever I am to use a singleton, I first consider a factory and most of the times, the factory just wins over singleton. If you really don't like factories, create a static class - a stateless class with static methods only. Chances are, you just don't need an object, just a set of methods.

Upvotes: 0

Steven
Steven

Reputation: 172825

If you are placing that common logging behind a static facade that application code calls, ask yourself how you would actually unit test that code. This is a problem that Dependency Injection tries to solve, but you are reintroducing it by letting application logic depend on a static class.

There are two other problems you might be having. To question I have for you is: Are you sure you don't log too much, and are you sure you aren't violating the SOLID principles.

I've written an SO answer a year back that discusses those two questions. I advice you to read it.

Upvotes: 0

Related Questions