Break Hidden Dependencies for Cleaner Code
TL;DR: Replace global variables with dependency injection to improve testability and reduce coupling. π
Problems Addressed π
- Hidden Dependencies
- Tight Coupling
- Testing Challenges
- Maintainability
- Singletons
Related Code Smells π¨

Code Smell 106 - Production Dependent Code
Maxi Contieri γ» Nov 27 '21
Steps π οΈ
- Identify global variables used across your codebase.
- Create a real-world abstraction to encapsulate these variables.
- Pass dependencies explicitly via function parameters or constructors.
- Refactor existing code to use the new dependency-injected structure.
- Remove the original global variable declarations.
Sample Code π»
Before β
// This global variable holds the API configuration
const globalConfig = { apiUrl: "https://api.severance.com" };
function fetchOuties() {
return fetch(`${globalConfig.apiUrl}/outies`);
// globalConfig is NOT passed as parameter
}
After π
function fetchOuties(parameterConfig) {
return fetch(`${parameterConfig.apiUrl}/outies`);
// 1. Identify global variables
// used across your codebase.
// 4. Refactor the existing code
// to use the new dependency-injected structure.
}
const applicationConfig = { apiUrl: "https://api.severance.com" };
// 2. Create a real-world abstraction
// to encapsulate these variables.
fetchOuties(applicationConfig);
// 3. Pass dependencies explicitly
// via function parameters or constructors.
// const globalConfig = { apiUrl: "https://api.severance.com" };
// 5. Remove the original
// global variable declarations.
// Why Is 'config' a Dependency?
// Because:
// outies() depends on knowing the API URL to work
// Without this information,
// The function can't perform its core task
// The dependency is
// explicitly declared in the function signature
A Step Beyond: API Reification
class ApiService {
constructor(parameterConfig) {
this.variableConfig = parameterConfig;
}
// parameterConfig, variableConfig
// and applicationConfig
// are very bad names.
// They are here to emphasize the change
fetchOuties() {
return fetch(`${this.variableConfig.apiUrl}/outies`);
}
}
const apiService =
new ApiService({ apiUrl: "https://api.severance.com" });
apiService.fetchOuties();
Type π
[X] Semi-Automatic
Safety π‘οΈ
This refactoring is safe if you audit all global variable references and thoroughly test the code after injection.
Why is the Code Better? π±
Testability: Dependencies can be replaced (not mocked) for unit tests.
Explicit Contracts: Functions declare what they need.
Scalability: Configuration changes donβt require code edits.
Coupling: Code is less coupled.
How Does it Improve the Bijection? πΊοΈ
By making dependencies explicit, the code mirrors real-world interactions where components rely on declared inputs, not hidden state.
You also reduce Coupling which is usually the more important problem you must solve.
Limitations β οΈ
Over-injection can lead to parameter bloat.
Common Misconceptions
"But it's just a parameter!"
- Exactly! Passing dependencies via parameters is Dependency Injection. Frameworks often obscure this basic principle.
"This is too simple to be DI!"
- Dependency Injection doesn't require complex frameworks. This is a pure, framework-less injection.
"Dependency Injection vs Dependency Inversion"
- Inversion is the principle (why). It tells you to depend on abstractions to reduce coupling.
- Injection is the practice (how). Itβs one way (there are many others) to apply the principle by passing dependencies from outside instead of creating them inside a class.
Refactor with AI π€
You can use AI tools to analyze your codebase and identify global variables.
The AI can suggest where to implement dependency injection and help generate the necessary interfaces or classes for your dependencies.
Try Them! π
Remember: AI Assistants make lots of mistakes
Suggested Prompt: 1. Identify global variables used across your codebase.2. Create a real-world abstraction to encapsulate these variables. 3. Pass dependencies explicitly via function parameters or constructors. 4. Refactor existing code to use the new dependency-injected structure. 5. Remove the original global variable declarations.
Without Proper Instructions | With Specific Instructions |
---|---|
ChatGPT | ChatGPT |
Claude | Claude |
Perplexity | Perplexity |
Copilot | Copilot |
Gemini | Gemini |
DeepSeek | DeepSeek |
Meta AI | Meta AI |
Qwen | Qwen |
Tags π·οΈ
- Dependency Injection
Level π
[X] Intermediate
Related Refactorings π©ββ€οΈβπβοΏ½

Refactoring 018 - Replace Singleton
Maxi Contieri γ» Nov 5 '24
See also π

Coupling: The one and only software design problem
Maxi Contieri γ» Feb 6 '21

Singleton: The Root of all Evil
Maxi Contieri γ» Nov 17 '20
Wikipedia: Dependency Injection
Wikipedia: Dependency Inversion
Credits π
This article is part of the Refactoring Series.
Top comments (0)