Problem: Unify Cache Clients

Medium
30 min
Wrap multiple cache backends (in-memory and Redis-like) under a single unified API.

Problem statement

Your application uses two cache systems depending on the environment:

  • In-memory cache in development, for simplicity.

  • Redis-like cache in production, which stores data asynchronously.

The problem is that both systems expose different method names and behaviors.

  • The in-memory cache uses synchronous methods:

setItem(key, value)
getItem(key)
  • The Redis-like client uses async methods:

async set(key, value)
async get(key)

You need a way for the rest of your app to talk to any cache with a single, consistent interface, without conditionals spread across the codebase.

Goal

Implement a CacheAdapter class that exposes two methods:

  • async set(key, value)

  • async get(key)

The adapter should:

  • Wrap either the in-memory or Redis-like client.

  • Normalize sync vs. async behavior so both can be awaited.

  • Return the same kind of results regardless of the underlying cache.

Constraints

  • You cannot modify the original cache clients.

  • The adapter must detect which methods are available.

  • All cache operations should work with await syntax.

  • The adapter must detect which methods are available.

Sample output

The examples below illustrate what the output should look like:

(async () => {
const memory = new CacheAdapter(memoryCache);
const redis = new CacheAdapter(redisCache);
await memory.set('user', 'Alice');
await redis.set('user', 'Bob');
console.log(await memory.get('user'));
console.log(await redis.get('user'));
})();
/* Expected output:
Alice
Bob
*/

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Problem: Unify Cache Clients

Medium
30 min
Wrap multiple cache backends (in-memory and Redis-like) under a single unified API.

Problem statement

Your application uses two cache systems depending on the environment:

  • In-memory cache in development, for simplicity.

  • Redis-like cache in production, which stores data asynchronously.

The problem is that both systems expose different method names and behaviors.

  • The in-memory cache uses synchronous methods:

setItem(key, value)
getItem(key)
  • The Redis-like client uses async methods:

async set(key, value)
async get(key)

You need a way for the rest of your app to talk to any cache with a single, consistent interface, without conditionals spread across the codebase.

Goal

Implement a CacheAdapter class that exposes two methods:

  • async set(key, value)

  • async get(key)

The adapter should:

  • Wrap either the in-memory or Redis-like client.

  • Normalize sync vs. async behavior so both can be awaited.

  • Return the same kind of results regardless of the underlying cache.

Constraints

  • You cannot modify the original cache clients.

  • The adapter must detect which methods are available.

  • All cache operations should work with await syntax.

  • The adapter must detect which methods are available.

Sample output

The examples below illustrate what the output should look like:

(async () => {
const memory = new CacheAdapter(memoryCache);
const redis = new CacheAdapter(redisCache);
await memory.set('user', 'Alice');
await redis.set('user', 'Bob');
console.log(await memory.get('user'));
console.log(await redis.get('user'));
})();
/* Expected output:
Alice
Bob
*/

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Node.js
// Simulated in-memory cache
const memoryCache = {
store: {},
setItem(key, value) {
this.store[key] = value;
return true;
},
getItem(key) {
return this.store[key] ?? null;
}
};
// Simulated async Redis-like cache
const redisCache = {
store: {},
async set(key, value) {
return new Promise(resolve => {
setTimeout(() => {
this.store[key] = value;
resolve('OK');
}, 100);
});
},
async get(key) {
return new Promise(resolve => {
setTimeout(() => {
resolve(this.store[key] ?? null);
}, 100);
});
}
};
// Your code here
// Example usage
(async () => {
const memory = new CacheAdapter(memoryCache);
const redis = new CacheAdapter(redisCache);
await memory.set('user', 'Alice');
await redis.set('user', 'Bob');
console.log(await memory.get('user'));
console.log(await redis.get('user'));
})();
/* Expected output:
Alice
Bob
*/