Circular dependency with noop.js
felixfbecker opened this issue · 8 comments
The circular dependency of Tracer -> noop -> Tracer is definitely a code smell that is worked around here with an initialize
function that needs to be called. Why not simply remove the noop.js file, and let the tracer, span etc files export a noop instance (if we need an eagerly instantiated instance at all)?
Good point. Could be a remnant of the original design that required the use of delegate, which was later change to define just an API that can be implemented independently.
I think the dependency should be
- Tracer API
- Noop tracer implements Trace API
- Global tracer wrapper with a delegate of type Tracer
- Global tracer by default initialized to Noop tracer.
Why do we need a delegate for the GlobalTracer? Can we just ensure it's always initialized to a NoopTracer and avoid the delegation overhead?
import Tracer from './tracer';
const noopTracer = new Tracer();
let _globalTracer: noopTracer;
export function initGlobalTracer(tracer: Tracer): void {
_globalTracer = tracer || noopTracer;
}
/**
* Returns the global tracer.
*/
export function globalTracer(): Tracer {
return _globalTracer;
}
Your example still requires `initGlobalTracer to be called once, but you can change it if you initialise it directly. Pretty sure it would work.
Only thing I can think of: the delegate would let you swap out the tracer reference later, in case you already stored the reference somewhere else before the tracer was initialized. I think in my solution some portion of your code could get stuck with a noopTracer
by accident due to init ordering.
I am concerned that calling apply
the way we do in the delegate will prevent JS optimizations from occurring, so if we can get out from under the delegation it would be nice.
Why do you think .apply()
would deoptimize the function?
https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#what-is-safe-arguments-usage
Ah, I see I am incorrect. I thought apply
had similar issues to bind
and prevented object caching.
I think the dependency should be
- Tracer API
- Noop tracer implements Trace API
- Global tracer wrapper with a delegate of type Tracer
- Global tracer by default initialized to Noop tracer.
SGTM – I'll try to make this happen or find someone who can make this happen. :)
Currently there are no interfaces to implement, the Tracer
, Span
etc classes actually already act as a noop implementation. I use successfully like that: https://sourcegraph.com/github.com/sourcegraph/javascript-typescript-langserver/-/blob/src/project-manager.ts#L834-835
I allow to pass a parent span, and default it to a noop span if none is passed.