Skip to main content

Command Palette

Search for a command to run...

Code Smell 319 - Hardcoded Stateless Properties

Don't turn collaborators into permanent roommates

Published
โ€ข4 min read
Code Smell 319 - Hardcoded Stateless Properties

TL;DR: You should avoid storing stateless utility classes as instance variables initialized with new.

Problems ๐Ÿ˜”

  • Hardcoded dependencies

  • Testing difficulties

  • High coupling

  • Hidden side effects

  • Rigid design

  • Misleading intent

  • Premature Optimization

  • Stack clutter

Solutions ๐Ÿ˜ƒ

  1. Use dependency injection

  2. Pass as parameter

  3. Use static methods

  4. Inline the logic

  5. Use local variables

  6. Inline object creation

Refactorings โš™๏ธ

https://maxicontieri.substack.com/p/refactoring-024-replace-global-variables

https://maxicontieri.substack.com/p/refactoring-030-inline-attributes

https://maxicontieri.substack.com/p/refactoring-007-extract-class-5b0b5960d0e7

Context ๐Ÿ’ฌ

Hardcoding a stateless class in the constructor creates permanent coupling.

Even if the class is cheap to instantiate, you lose the ability to swap it.

Stateless objects shouldn't be part of the object's internal state.

You confuse readers by making a tool look essential to the object's identity.

It makes testing harder because you can't mock the hardcoded dependency.

Sample Code ๐Ÿ’ป

Wrong ๐Ÿšซ

class UserProcessor {
  private provider: MockDataProvider;

  constructor() {
    // You hardcode the dependency here.
    // This makes the class harder to test.
    this.provider = new MockDataProvider();
  }

  process(data: any) {
    return this.provider.format(data);
  }
}
interface DataProvider {
  format(data: any): any;
}

class UserProcessor {
  // You inject the dependency via constructor.
  // Now you can swap it or mock it easily.
  constructor(private readonly provider: DataProvider) {}

  process(data: any) {
    return this.provider.format(data);
  }
}
// Simpler but coupled
 class UserProcessor {
    constructor() {
      // Empty
    }
  
    process(data: any) {
      return new MockDataProvider().format(data);
    }
  }

Detection ๐Ÿ”

Look for the new keyword inside constructors.

Watch for private properties instantiated directly in the constructor rather than passed as parameters.

Most linters flag this pattern automatically when you create instances and assign them to private fields without dependency injection.

Tags ๐Ÿท๏ธ

  • Premature Optimization

Level ๐Ÿ”‹

[X] Beginner

Why the Bijection Is Important ๐Ÿ—บ๏ธ

Software should mimic a MAPPER of the real world.

In reality, a worker might use a tool to complete a task.

The tool is not a permanent physical attachment to the worker.

When you refactor to use dependency injection, you respect the bijection by treating collaborators as external entities, not internal state.

This keeps your simulation flexible and accurate.

AI Generation ๐Ÿค–

AI generators frequently create this smell.

They often suggest code that just works by instancing dependencies directly in the constructor to save time.

AI Detection ๐Ÿงฒ

AI can easily detect this smell without explicit instructions.

When you show AI a class with new keywords in the constructor, it recognizes the pattern as hardcoded coupling.

AI identifies that stateless utility classes should be injected rather than instantiated internally.

The detection is straightforward because the pattern is syntactically obvious and semantically harmful.

Try Them! ๐Ÿ› 

Remember: AI Assistants make lots of mistakes

Suggested Prompt: remove the cached attribute

Without Proper Instructions With Specific Instructions
ChatGPT ChatGPT
Claude Claude
Perplexity Perplexity
Copilot Copilot
You You
Gemini Gemini
DeepSeek DeepSeek
Meta AI Meta AI
Grok Grok
Qwen Qwen

Conclusion ๐Ÿ

Storing stateless dependencies as instance variables makes your code rigid.

When you inject these dependencies instead, you improve testability and keep your objects focused on their true purpose.

Relations ๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ

https://maxicontieri.substack.com/p/code-smell-06-too-clever-programmer-bffec35daf0b

https://maxicontieri.substack.com/p/code-smell-20-premature-optimization-60409b7f90ec

Disclaimer ๐Ÿ“˜

Code Smells are my opinion.

Credits ๐Ÿ™

Photo by Possessed Photography on Unsplash


Coupling is the enemy of change

Rich Hickey

https://maxicontieri.substack.com/p/software-engineering-great-quotes-3af63cea6782


This article is part of the CodeSmell Series.

https://maxicontieri.substack.com/p/how-to-find-the-stinky-parts-of-your-code-fa8df47fc39c

Code Smells

Part 1 of 50

In this series, we will see several symptoms and situations that make us doubt the quality of our developments. We will present possible solutions. Most are just clues. They are no hard rules.

Up next

Code Smell 318 - Refactoring Dirty Code

You polish code that nobody touches while the real hotspots burn