In general, caching and memoisation makes sense when:
- Obtaining a result (or at least it can be) with a high delay or otherwise is expensive than the costs caused by the caching itself.
- The results have a search template where there will be frequent calls with the same function inputs (that is, not only arguments, but also any instance, static and other data that affect the result).
- In the code that invokes the code, there is no existing caching mechanism, which makes it unnecessary.
- The code that calls this code will have no other caching mechanism that makes it unnecessary (why memoise
GetHashCode()
almost never makes sense in this method, even though people are often tempted when the implementation is relatively expensive). - It is impossible to become obsolete, it is unlikely to become obsolete when the cache is loaded, it does not matter if it becomes obsolete, or where persistence is easily detected.
There are times when each use case for a component will correspond to all of these. There are many more where they will not be. For example, if a component caches results, but is never called twice with the same inputs of a specific client component, then this caching is just waste that negatively impacted performance (possibly minor, maybe serious).
Most often, it makes sense for client code to define a caching policy that suits it. It is also often easier to configure for a specific use at the moment in the face of real data than in a component (since the real-world data it will encounter can differ significantly from the use for use).
It is even more difficult to find out what degree of resistance may be acceptable. Typically, a component should assume that 100% freshness is required from it, while a client component may know that a certain amount of inaccuracy will be in order.
On the other hand, it may be easier for a component to retrieve information that is used in the cache. Components can work hand in hand in these cases, although it is much more active (an example is the If-Modified-Since mechanism used by RESTful web services, where the server can indicate that the client can safely use the information it cached).
Additionally, the component may have a custom cache policy. Connection pooling is a caching policy; consider how it is configured.
So in short:
A component that can decide which caching is possible and useful.
Most often this is client code. Although the details of the likely delay and inaccuracies documented by the authors of the component will help here.
Less commonly can be client code using a component, although you need to cache the details to enable this.
And sometimes it can be a component with a caching policy configured by the calling code.
Rarely can there be only a component, because the same caching policy is less commonly used for all possible use cases. One of the important exceptions is that the same instance of this component will serve several clients, because then the factors that affect the above apply to these several clients.