When building modules that depend on other domain-specific modules, favor passing dependencies as parameters during initialization rather than using static imports. This pattern improves:
- Readability: Dependencies are explicitly visible in the function signature.
- Testability: You can easily pass mock dependencies during testing.
- Extensibility: You can swap dependencies with different implementations that share the same signature.
Avoid statically retrieving or exposing parts of a dependency within a module. Instead, initialize dependencies at a 'boot' level and pass them into your module's entry point.
// OK: Dependencies are passed as parameters
// boot.ts
const myDependency = startMyDependency()
const myOtherDependency = getOrCreateMyDependency()
const myModule = startMyModule(myDependency, myOtherDependency)
// myModule.ts
function startMyModule(myDependency, myOtherDependency) {
myDependency.interact()
myOtherDependency.interact()
}
// KO: Statically retrieving dependencies inside the module
import { getOrCreateMyDependency } from './myDependency'
function startMyModule() {
const myDependency = getOrCreateMyDependency()
myDependency.interact()
}