1

Recently, one of my colleagues stated that the cache should always be required dependency. We should require it in non-null constructor parameter. And we can't use null-object pattern with it.

How to bring over this point of view? What do you suggest? How do you inject cache in your technologies?

update1: By cache I mean interface, that can query value by key, store it, determine is hit/miss and etc. So it's some kind of backend storage for https://en.wikipedia.org/wiki/Memoization

4
  • 7
    This question is not answerable. What "cache" are you talking about? Is it some object that your organization has produced? Is it a specific library (in which case you need to say what it is and tag the question appropriately)? Is it your term for memoization? I'm guessing that it's neither the CPU cache nor a webserver cache, since you talk about it in reference to constructors.
    – kdgregory
    Commented Oct 14, 2016 at 11:21
  • 3
    Caching isn't about required vs optional dependency. It's about time. Commented Oct 14, 2016 at 11:28
  • 3
    In many cases a cache is simply a transparent wrapper, so it wouldn't have a separate interface that needs to be injected. Commented Oct 14, 2016 at 12:59
  • I don't know your exact case, but in general, caching is a complicated subject (what cache algorithm is appropriate? whats your expiration strategy? how much storage will it use? does the cache need to be instantaneously correct? are you sharing mutable state? etc etc) and so can be surprisingly risky to implement. So, it's often better to add caching only once you've identified a need for it, hence it should be an optional dependency. Commented Oct 14, 2016 at 15:03

2 Answers 2

7

PSR-6 recommendation regarding Caching Interface expresses a view I personally prefer:

While caching is often an important part of application performance, it should never be a critical part of application functionality.

So, I'm in favor of considering it as an optional dependency.

1

No, one either uses a cache or doesn't.

In your application, one would determine whether caching was necessary. I would inject caching as a decorator pattern.

Consider this interface.

public interface ICommand<in TIn, out TOut>
    {
        TOut Execute(TIn command);
    }

We pass something in and get something back out. Maybe to get something takes a long time. So, we decide to add caching.

public class CacheDecorator<TIn, TOut> : ICommand<TIn, TOut>
    {
        private readonly ICache _cache;
        private readonly ICommand<TIn, TOut> _command;
        private readonly string _key;

        public CacheDecorator(string key, ICache cache, ICommand<TIn, TOut> command)
        {
            _command = command;
            _key = key;
            _cache = cache;
        }

        public TOut Execute(TIn input)
        {
            TOut obj;
            if (_cache.Get(_key, out obj))
            {
                Debug.WriteLine(string.Format("Cache hit for key {0}", _key));
                return obj;
            }

            Debug.WriteLine(string.Format("Cache miss for key {0}", _key));
            obj = _command.Execute(input);
            _cache.Set(_key, obj);

            return obj;
        }
    }

Now any command that get's something back can be cached. If we don't need caching then the command is not decorated.

Let's pretend we are getting a widget and getting a widget is expensive:

 public Widget GetWidget(string id)
        {
            var widgetCommand = new WidgetServiceCommand();
            var command = new CacheDecorator<string, Widget>(id, _cache, widgetCommand);
            return command.Execute(id);
        }

If getting widgets was not expensive, then just remove the decorator and the widget is not cached.

1
  • Hmm.. My usecase is this: I'm a lib developer and I want to potentially cover by cache some points in code, but I dont' want to force lib's user to inject cache always. In your case you stand in a position of app developer, where you know 100% when you need cache or not.
    – gaRex
    Commented Oct 14, 2016 at 18:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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