Wednesday, November 22, 2017

Useful caching pattern

One of the SO answers contains an interesting caching pattern, proposed by user Keith
static string GetCachedData(string key, DateTimeOffset offset)
{
    Lazy lazyObject = new Lazy(() => SomeHeavyAndExpensiveCalculationThatReturnsAString());

    var available = MemoryCache.Default.AddOrGetExisting(key, lazyObject, offset); 

    if (available == null)
       return lazyObject.Value;
    else
       return ((Lazy)available).Value;
}
It relies on the MemoryCache::AddOrGetExisting returning null on the very first call that adds the item to the cache but returning the cached item in case it already exists in the cache. A clever trick worth of remembering.

Monday, November 13, 2017

Node.js, circularly dependent modules and intellisense in VS Code

Circularily dependand modules in Node.js is something most people recommend you should definitely avoid. Let's start with an example of two classes that mutually require each other:
// a.js
var B = require('./b');

class A {
    createB() {
        return new B();
    }
}
    
module.exports = A;

// b.js
var A = require('./a');

class B {
    createA() {
        return new A();
    }    
}

module.exports = B;

// app.js
var A = require('./a');
var B = require('./b');

var a = new B().createA();
var b = new A().createB();

console.log(a);
console.log(b);
Although this looks correct and intellisense works correctly, this of course doesn't work because of the circular dependency.
And while there are multiple resources that cover the topic (e.g. [1] or [2]) I'd like to emphasize that VS Code does a nice job in inferring of what actual type of the returned value from the method is, regardless of what approach to the issue you take.

Let's check the first approach, where you inline the reference

// b.js
class B {
    createA() {
        var A = require('./a');
        return new A();
    }    
}

module.exports = B;
Note that the VS Code still correctly infers the return type of the method:
The second approach involves moving requires to the end of both modules
// a.js
class A {
    createB() {
        return new B();
    }
}
    
module.exports = A;

var B = require('./b');

// b.js
class B {
    createA() {
        return new A();
    }    
}

module.exports = B;

var A = require('./a');
The type inference still works.

The last fact worth mentioning is that VS Code respects the JSDoc's @type annotation, whenever there type can't be inferred automatically, you can help it.

Take a look at VS Code not able to infer the actual type of a variable

var a = new B().createA();
var b = new A().createB();

var _unknown;
and how a hint helps it
var a = new B().createA();
var b = new A().createB();

/** @type {A} */
var _unknown;