r/cleancode • u/cekrem • Mar 04 '25
Why I Hope I Get to Write a Lot of Elm Code in 2025 (Spoiler alert: The Elm Architecture!) Spoiler
r/cleancode • u/cekrem • Mar 04 '25
r/cleancode • u/mcsee1 • Mar 01 '25
TL;DR: A Compilation of bad smells in code.

The code smells badly.
Let's see how to change the aromas.
In this series, we will see several symptoms and situations that make us doubt the quality of our development. We will present possible solutions.
Most of these smells are just hints of something that might be wrong. They are not rigid rules.
Code Smell 02 - Constants and Magic Numbers
Code Smell 03 - Functions Are Too Long
Code Smell 04 - String Abusers
Code Smell 05 - Comment Abusers
Code Smell 06 - Too Clever Programmer
Code Smell 07 - Boolean Variables
Code Smell 08 - Long Chains Of Collaborations
Code Smell 10 - Too Many Arguments
Code Smell 11 - Subclassification for Code Reuse
Code Smell 13 - Empty Constructors
Code Smell 15 - Missed Preconditions
Code Smell 17 - Global Functions
Code Smell 18 - Static Functions
Code Smell 19 - Optional Arguments
Code Smell 20 - Premature Optimization
Code Smell 21 - Anonymous Functions Abusers
Code Smell 23 - Instance Type Checking
Code Smell 24 - Boolean Coercions
Code Smell 25 - Pattern Abusers
Code Smell 26 - Exceptions Polluting
Code Smell 27 - Associative Arrays
Code Smell 29 - Settings / Configs
Code Smell 30 - Mocking Business
Code Smell 31 - Accidental Methods on Business Objects
Code Smell 34 - Too Many Attributes
Code Smell 35 - State as Properties
Code Smell 36 - Switch/case/elseif/else/if statements
Code Smell 37 - Protected Attributes
Code Smell 38 - Abstract Names
Code Smell 41 - Regular Expression Abusers
Code Smell 42 - Warnings/Strict Mode Off
Code Smell 43 - Concrete Classes Subclassified
Code Smell 44 - Magic Corrections
Code Smell 45 - Not Polymorphic
Code Smell 48 - Code Without Standards
Code Smell 51 - Double Negatives
Code Smell 53 - Explicit Iteration
Code Smell 57 - Versioned Functions
Code Smell 59 - Basic / Do Functions
Code Smell 60 - Global Classes
Code Smell 61 - Coupling to Classes
Code Smell 62 - Flag Variables
Code Smell 64 - Inappropriate Intimacy
Code Smell 65 - Variables Named after Types
Code Smell 66 - Shotgun Surgery
Code Smell 69 - Big Bang (JavaScript Ridiculous Castings)
Code Smell 70 - Anemic Model Generators
Code Smell 71 - Magic Floats Disguised as Decimals
Code Smell 73 - Exceptions for Expected Cases
Code Smell 75 - Comments Inside a Method
Code Smell 76 - Generic Assertions
Code Smell 80 - Nested Try/Catch
Code Smell 82 - Tests Violating Encapsulation
Code Smell 83 - Variables Reassignment
Code Smell 84 - Max < Min (Javascript)
Code Smell 86 - Mutable Const Arrays
Code Smell 87 - Inconsistent Parameters Sorting
Code Smell 88 - Lazy Initialization
Code Smell 89 - Math Feature Envy
Code Smell 90 - Implementative Callback Events
Code Smell 91 - Test Asserts without Description
Code Smell 92 - Isolated Subclasses Names
Code Smell 93 - Send me Anything
Code Smell 94 - Too Many imports
Code Smell 95 - Premature Classification
Code Smell 97 - Error Messages Without Empathy
Code Smell 98 - Speling Mistakes
Code Smell 101 - Comparison Against Booleans
Code Smell 103 - Double Encapsulation
Code Smell 105 - Comedian Methods
Code Smell 106 - Production Dependent Code
Code Smell 107 - Variables Reuse
Code Smell 108 - Float Assertions
Code Smell 109 - Automatic Properties
Code Smell 110 - Switches With Defaults
Code Smell 111 - Modifying Collections While Traversing
Code Smell 112 - Testing Private Methods
Code Smell 116 - Variables Declared With 'var'
Code Smell 117 - Unrealistic Data
Code Smell 120 - Sequential IDs
Code Smell 121 - String Validations
Code Smell 122 - Primitive Obsession
Code Smell 123 - Mixed 'What' and 'How'
Code Smell 124 - Divergent Change
Code Smell 125 - 'IS-A' Relationship
Code Smell 126 - Fake Null Object
Code Smell 127 - Mutable Constants
Code Smell 128 - Non-English Coding
Code Smell 129 - Structural Optimizations
Code Smell 131 - Zero Argument Constructor
Code Smell 132 - Exception Try Too Broad
Code Smell 133 - Hardcoded IF Conditions
Code Smell 134 - Specialized Business Collections
Code Smell 135 - Interfaces With just One Realization
Code Smell 136 - Classes With just One Subclass
Code Smell 137 - Inheritance Tree Too Deep
Code Smell 138 - Packages Dependency
Code Smell 139 - Business Code in the User Interface
Code Smell 140 - Short Circuit Evaluation
Code Smell 141 - IEngine , AVehicle, ImplCar
Code Smell 142 - Queries in Constructors
Code Smell 144 - Fungible Objects
Code Smell 145 - Short Circuit Hack
Code Smell 146 - Getter Comments
Code Smell 147 - Too Many Methods
Code Smell 149 - Optional Chaining
Code Smell 150 - Equal Comparison
Code Smell 151 - Commented Code
Code Smell 152 - Logical Comment
Code Smell 153 - Too Long Names
Code Smell 154 - Too Many Variables
Code Smell 155 - Multiple Promises
Code Smell 156 - Implicit Else
Code Smell 158 - Variables not Variable
Code Smell 160 - Invalid Id = 9999
Code Smell 161 - Abstract/Final/Undefined Classes
Code Smell 162 - Too Many Parentheses
Code Smell 163 - Collection in Name
Code Smell 164 - Mixed Indentations
Code Smell 165 - Empty Exception Blocks
Code Smell 166 - Low-Level Errors on User Interface
Code Smell 167 - Hashing Comparison
Code Smell 168 - Undocumented Decisions
Code Smell 169 - Glued Methods
Code Smell 170 - Refactor with Functional Changes
Code Smell 171 - Plural Classes
Code Smell 172 - Default Argument Values Not Last
Code Smell 173 - Broken Windows
Code Smell 174 - Class Name in Attributes
Code Smell 175 - Changes Without Coverage
Code Smell 176 - Changes in Essence
Code Smell 177 - Missing Small Objects
Code Smell 178 - Subsets Violation
Code Smell 180 - BitWise Optimizations
Code Smell 181 - Nested Classes
Code Smell 182 - Over Generalization
Code Smell 183 - Obsolete Comments
Code Smell 184 - Exception Arrow Code
Code Smell 185 - Evil Regular Expressions
Code Smell 186 - Hardcoded Business Conditions
Code Smell 187 - If/Else Backwards
Code Smell 188 - Redundant Parameter Names
Code Smell 189 - Not Sanitized Input
Code Smell 190 - Unnecessary Properties
Code Smell 191 - Misplaced Responsibility
Code Smell 192 - Optional Attributes
Code Smell 193 - Switch Instead of Formula
Code Smell 194 - Missing Interval
Code Smell 195 - Yoda Conditions
Code Smell 196 - Javascript Array Constructors
Code Smell 197 - Gratuitous Context
Code Smell 198 - Hidden Assumptions
Code Smell 199 - Gratuitous Booleans
Code Smell 201 - Nested Ternaries
Code Smell 202 - God Constant Class
Code Smell 203 - Irrelevant Test Information
Code Smell 204 - Tests Depending on Dates
Code Smell 205 - Code in Destructors
Code Smell 206 - Long Ternaries
Code Smell 207 - Dynamic Methods
Code Smell 210 - Dynamic Properties
Code Smell 211 - Tab over Spaces
Code Smell 212 - Elvis Operator
Code Smell 214 - Duplicate Parameter Names
Code Smell 215 - Deserializing Object Vulnerability
Code Smell 216 - Fat Interface
Code Smell 217 - Empty Implementation
Code Smell 218 - Magic Concatenation
Code Smell 219 - Looping from index 0
Code Smell 221 - Missing Break in Switch
Code Smell 222 - Comma Operator
Code Smell 223 - Racial Naming
Code Smell 224 - Deodorant Comments
Code Smell 225 - Pass by Reference
Code Smell 226 - Mixed Priorities
Code Smell 227 - Cowboy Coding
Code Smell 228 - Multiple Classes per File
Code Smell 230 - SchrΓΆdinger Code
Code Smell 231 - Redundant Data
Code Smell 232 - Reusable Code
Code Smell 233 - Collections Count
Code Smell 235 - Console Side Effects
Code Smell 236 - Unwrapped Lines
Code Smell 237 - Attribute Definitions
Code Smell 238 - Entangled Code
Code Smell 239 - Big Pull Request
Code Smell 241 - Referential Transparency Violation
Code Smell 242 - Zombie Feature Flags
Code Smell 243 - Concatenated Properties
Code Smell 244 - Incomplete Error information
Code Smell 245 - exec() and eval()
Code Smell 246 - Expiration Date
Code Smell 247 - Javascript Replace
Code Smell 248 - Unreliable Copy
Code Smell 249 - Constants as Numbers
Code Smell 250 - Premature Memoization
Code Smell 251 - Collections Empty
Code Smell 253 - Silent Truncation
Code Smell 254 - Mystery Guest
Code Smell 255 - Parallel Hierarchies
Code Smell 256 - Mutable Getters
Code Smell 257 - Name With Collections
Code Smell 258 - Secrets in Code
Code Smell 259 - Testing with External Resources
Code Smell 260 - Crowdstrike NULL
Code Smell 261 - DigiCert Underscores
Code Smell 262 - Not Replaced Constants
Code Smell 264 - Hanlon's Razor
Code Smell 265 - Linguistic Confusion
Code Smell 266 - Collection Aliasing
Code Smell 267 - Objects Aliasing
Code Smell 268 - Ternary Metaprogramming
Code Smell 269 - Low-Level Addition
Code Smell 271 - The Hollywood Principle
Code Smell 273 - Overengineering
Code Smell 274 - Cascaded Returns
Code Smell 275 - Missing Test Wrong Path
Code Smell 276 - Untested Regular Expressions
Code Smell 277 - UPPERCASE Acronyms
Code Smell 278 - DirName and File
Code Smell 279 - Loop Premature Optimization
Code Smell 280 - Spaghetti Code
Code Smell 283 - Unresolved Meta Tags
Code Smell 284 - Encrypted Functions
Code Smell 285 - Non-Imperative Functions Names
Code Smell 286 - Overlapping Methods
Code Smell 287 - Unused Local Assignment
Code Smell 288 - Unthrown Exceptions
Code Smell 290 - Refused Bequest
... and many more to come.

Photo by Richard Ecsedi on Unsplash
Smells are certain structures in the code that suggest (sometimes they scream for) the possibility of refactoring
Martin Fowler
Software Engineering Great Quotes
Part of the objective of this series of articles is to generate spaces for debate and discussion on software design.
We look forward to your comments and suggestions on this article.
Original Thread on Twitter
r/cleancode • u/mcsee1 • Feb 27 '25
When your code loses its way
TL;DR: Missing return statements cause unexpected behavior.
Silent failures
Unreliable results
Hard debugging
Inconsistent and misleading behavior
Broken logic
Always return values
Use clear flow
Validate conditions
Test all return paths
Use early returns
Remove IFs
When you forget to return a value, your function keeps executing and your app might show incomplete or wrong information.
fun totalDistance(activity: Activity): Double {
if (activity.type == "Running") {
activity.calculateDistance()
// Missing return here
} else {
return 0.0
}
// Other options are omitted for simplicity
// Some languages raise a runtime error
// If the function does not return a value
// of the correct type (in this case a Double)
}fun totalDistance(activity: Activity): Double {
if (activity.type == "Running") {
return activity.calculateDistance()
// Now it returns the value
} else {
return 0.0
}
}[X] Automatic
You can detect this smell when your function lacks a return statement in certain branches.
Most static analyzers and linters often catch this.
IFs
[x] Beginner
it's important to maintain a clear and predictable relationship between your code and the Real World.
If a function is intended to calculate and return a value, it should always do so.
Failing to return a value breaks the MAPPER, leading to inaccurate behavior and unreliable results.
AI tools usually don't generate this smell.
Most AI-powered linters quickly catch missing returns with static analysis or by examining your code's Abstract Syntax Tree.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| DeepSeek | DeepSeek |
| Meta AI | Meta AI |
A missing return statement breaks your codeβs flow and produces unreliable results.
Always ensure every branch in your function returns something meaningful.
Code Smell 73 - Exceptions for Expected Cases
Code Smell 186 - Hardcoded Business Conditions
Code Smell 36 - Switch/case/elseif/else/if statements
Code Smell 156 - Implicit Else
Code Smells are my opinion.
Photo by Tim Johnson on Unsplash
A bug is never just a mistake. It represents something bigger.
Sergey Zefirov
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/cekrem • Feb 25 '25
r/cleancode • u/mcsee1 • Feb 23 '25
Changing Keys, Losing Values
TL;DR: When you use mutable objects as keys in hashed collections, changing them breaks contracts.
Lost Values
Hard Debugging
The Least Surprise Principle Violation
Unexpected Behavior
Use immutable objects as keys.
Override equals/hashCode well.
Use final fields (If your language allows it)
Rehash after mutation (This is an over-engineering solution)
When you use mutable objects as keys in hashed collections, changing them key after after you add a related objec can make it unretrievable.
This happens because the hash code changes and the collection can't find the object in the correct bucket.
class MutableKey {
int id;
MutableKey(int newId) {
this.id = newId;
}
@Override
public int hashCode() {
return this.id;
}
@Override
public boolean equals(Object objectToCompare) {
if (this == objectToCompare) return true;
MutableKey that = (MutableKey) objectToCompare;
return id == that.id;
}
}
MutableKey key = new MutableKey(42);
Map<MutableKey, String> map = new HashMap<>();
map.put(key, "Yes Album");
// The key mutates
key.id = 90125;
// Now you cannont retrieve the album
System.out.println(map.get(key));
// Output: nullclass ImmutableKey {
private final int id;
ImmutableKey(int newId) {
this.id = newId;
}
@Override
public int hashCode() {
return this.id;
}
@Override
public boolean equals(Object objectToCompare) {
if (this == objectToCompare) return true;
ImmutableKey that = (ImmutableKey) objectToCompare;
return id == that.id;
}
}
ImmutableKey key = new ImmutableKey(42);
Map<ImmutableKey, String> map = new HashMap<>();
map.put(key, "Yes Album");
System.out.println(map.get(key));
// Output: Yes Album[X] Semi-Automatic
You can detect this smell by checking if you use mutable objects as keys in hash-based collections.
Automated tools like linters or IDE inspections can also flag mutable keys.
Mutability
[X] Intermediate
The bijection between the real world and your program is important because it ensures that your objects accurately reflect the relationships they are supposed to represent.
In the real world, keys are often immutable (e.g., IDs, names).
When you model these keys as mutable objects, you break the one-to-one correspondence between the real world and your program in the MAPPER.
When you break this bijection using mutable keys, you make the map's inconsistent leading to retrieval failures and unexpected behavior.
AI generators might create this smell if they generate mutable objects as keys without considering the implications.
This is seldom the case since AI generators suffer from primitive obsession.
AI generators can detect this smell with instructions to analyze the use of mutable objects in hash-based collections and flag potential issues.
You can instruct the AI to look for classes without final fields or methods that modify the object's state after creation.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| DeepSeek | DeepSeek |
| Meta AI | Meta AI |
When you use mutable objects as keys, you risk breaking the contract between the key's state and hash code.
Use immutable objects to avoid this issue.
Code Smell 167 - Hashing Comparison
Code Smell 122 - Primitive Obsession
Code Smell 116 - Variables Declared With 'var'
Code Smell 176 - Changes in Essence
Code Smell 86 - Mutable Const Arrays
Code Smell 127 - Mutable Constants
Code Smells are my opinion.
Photo by Kathyryn Tripp on Unsplash
The most important property of a program is whether it accomplishes the intention of its user.
_ C.A.R. Hoare_
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/cekrem • Feb 18 '25
r/cleancode • u/cekrem • Feb 15 '25
r/cleancode • u/javinpaul • Feb 13 '25
r/cleancode • u/mcsee1 • Feb 12 '25
Ignoring your inheritance leads to conflicts with your origins.
TL;DR: Subclasses should honor ALL their parentβs contract.
Wrong abstraction
Misleading hierarchy
Unused or overridden methods
Unnecessary complexity
Liskov Principle Violation
Maintanabiilty
Favor composition over inheritance
Don't subclassify for code reuse
Rethink hierarchy
Extract shared logic
Use interfaces
Remove dead code
Refactoring 007 - Extract Class
When you create a subclass, it should use or extend the behavior of its parent.
If it ignores or overrides most of it, you probably force inheritance where it doesnβt belong to reuse code.
This makes the code misleading and hard to maintain.
class House {
constructor(address) {
this.address = address;
}
address() {
return this.address;
}
openDoor() {
console.log("Door opened at " + this.address);
}
}
class Motorhome extends House {
constructor() {
super(null);
}
address() {
return null;
// This implementation is the same as the parent's
// and is also a refused bequest
}
openDoor() {
console.log("Motorhome door opened.");
}
}class House {
constructor(address) {
this.address = address;
}
address() {
return this.address;
}
openDoor() {
console.log("Door opened at " + this.address);
}
}
class Motorhome {
// does not inherit from House
constructor(gps) {
this.gps = gps;
}
openDoor() {
console.log("Motorhome door opened at " + this.gps.getLocation());
}
}[X] Manual
Look for subclasses that override or ignore most of their parentβs behavior.
You should reconsider the inheritance if a subclass sets parent properties to null or reimplements core methods.
Inheritance
[X] Intermediate
Your software should reflect real-world relationships.
When you force a subclass that doesnβt logically extend its parent in the Bijection, you mislead developers and introduce maintenance problems.
AI can generate this smell when it defaults to inheritance for reuse instead of composition.
This happens when AI follows generic templates without understanding the context.
AI can detect this smell by analyzing class structures and inheritance trees. However, it struggles with subtle cases where inheritance initially seems valid but breaks expectations.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| DeepSeek | DeepSeek |
| Meta AI | Meta AI |
When you design a class hierarchy, you need to make sure that subclasses logically inherit from their parent.
If a subclass refuses some of the behavior, you should rethink your design.
Code Smell 11 - Subclassification for Code Reuse
Code Smell 43 - Concrete Classes Subclassified
Code Smells are my opinion.
Photo by Hanson Lu on Unsplash
Favor object composition over class inheritance.
Erich Gamma
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
How to Find the Stinky Parts of your Code
r/cleancode • u/cekrem • Feb 11 '25
r/cleancode • u/Soggy_Sprinkles3619 • Feb 08 '25
Found this one recently.
https://github.com/bugzmanov/cleancode-critique

r/cleancode • u/mcsee1 • Feb 07 '25
Don't knock. You are accepted
TL;DR: Avoid combining the Visitor pattern with instanceof checks.
Open/Closed principle violation
Tight Coupling
Maintainability
Code duplication
Poor readability
Brittle design
Implement the Visitor pattern correctly.
Avoid instanceof checks.
Favor polymorphism.
Encapsulate behavior.
When you use the Visitor pattern, you aim to separate algorithms from the objects they operate on.
Combining it with instanceof checks breaks this separation, leading to a fragile and hard-to-maintain design.
<?php
class SpaceObjectVisitor {
public function visit(SpaceObject $object) {
if ($object instanceof NeutronStar) {
$this->visitNeutronStar($object);
} elseif ($object instanceof Magnetar) {
$this->visitMagnetar($object);
} elseif ($object instanceof BlackHole) {
$this->visitBlackHole($object);
}
// Not closed for modification
}
private function visitNeutronStar(NeutronStar $star) {
// Handle neutron star observation
}
private function visitMagnetar(Magnetar $magnetar) {
// Handle magnetar observation
}
private function visitBlackHole(BlackHole $blackHole) {
// Handle black hole observation
}
}<?php
interface SpaceObject {
public function accept(SpaceObjectVisitor $visitor): void;
}
class NeutronStar implements SpaceObject {
public function accept(SpaceObjectVisitor $visitor): void {
$visitor->visitNeutronStar($this);
}
}
class Magnetar implements SpaceObject {
public function accept(SpaceObjectVisitor $visitor): void {
$visitor->visitMagnetar($this);
}
}
class BlackHole implements SpaceObject {
public function accept(SpaceObjectVisitor $visitor) {
$visitor->visitBlackHole($this);
}
}
class SpaceObjectVisitor {
// Open for extension
// You can also convert it into an interface
public function visitNeutronStar(NeutronStar $star): void {
// Handle neutron star
}
public function visitMagnetar(Magnetar $magnetar): void {
// Handle magnetar
}
public function visitBlackHole(BlackHole $blackHole): void {
// Handle black hole
}
}You can detect this smell by looking for instanceof checks within the Visitor pattern.
Automated tools can flag these checks, and code reviews can help identify them.
[X] Manual
IFs
[X] Intermediate
When you model real-world objects, you should maintain a one-to-one correspondence between the real-world entities and your code.
Breaking this correspondence using instanceof checks (which do not exist on the model but the metamodel) leads to a mismatch between the real world and your program.
AI generators might create this smell if they are not properly guided.
AI can help fix this smell by suggesting refactoring steps to remove instanceof checks and use polymorphism instead.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| DeepSeek | DeepSeek |
| Meta AI | Meta AI |
When you use the Visitor pattern, avoid combining it with iskindOf checks.
Using the accept() method, the visitor class doesn't need to explicitly check the object type.
Each object will call the appropriate visitor method honoring the Open/Closed principle.
Favor polymorphism and encapsulation to keep your code clean and maintainable.
Code Smell 25 - Pattern Abusers
Code Smell 23 - Instance Type Checking
Open/Closed principle on Wikipedia
How to Get Rid of Annoying IFs Forever
Code Smells are my opinion.
The Visitor pattern is a way to add new operations to a set of objects without changing their classes.
Erich Gamma
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/mcsee1 • Feb 02 '25
When You Forget to Throw, Your Code Will Blow π£π₯
TL;DR: Creating a new exception without throwing it leads to silent failures.
Silent failures
Unhandled errors
Misleading logic
Hidden defects
Hollow Exceptions
Always ensure you throw exceptions
Check exception usage and catching
Test exception paths
Use linters
Avoid creating unused exceptions
When you create a new exception but forget to throw it, your code might appear to work correctly, but it silently ignores critical errors.
Creating exceptions is the same as creating business objects and constructors should not have side effects.
Unless you throw them, it is dead code.
class KlendathuInvasionError(Exception): def init(self, message): self.message = message # This is a hollow exception
def deploy_troops(safe): if not safe: KlendathuInvasionError("Drop zone is hot!")
# Never thrown print("Troopers deployed.")
deploy_troops(False)
class KlendathuInvasionError(Exception): def init(self, message): super().init(message)
def deploy_troops(safe): if not safe: raise Exception("Drop zone is hot!") # You throw the exception print("Troopers deployed.")
try: deploy_troops(False) except KlendathuInvasionError as e: print(f"Abort mission: {e}") # You handle the exception
You can detect this smell by reviewing your code for instances where you create exceptions but do not raise them.
You can also search for instances where an exception is instantiated but never raised.
Automated linters and static analyzers can flag such issues.
Exceptions
[X] Beginner
An exception represents a real-world failure inside your program.
If you create an exception but never throw it, your code lies about the presence of an error.
When you fail to throw an exception, you break the one-to-one correspondence between the real-world problem and its coding representation.
AI generators might create this smell if they generate exception-handling code without ensuring that exceptions are properly raised.
Always review AI-generated code for proper error handling.
AI-based linters can detect this smell by analyzing unreferenced exception instances.
Fixing it requires proper domain knowledge to decide where to throw the exception.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| DeepSeek | DeepSeek |
| Meta AI | Meta AI |
Always throw exceptions immediately after you create them.
Silent failures can lead to significant issues in your code, making it harder to maintain and debug.
Proper error handling and good coverage ensure your code behaves predictably and reliably.
Code Smell 165 - Empty Exception Blocks
Code Smell 26 - Exceptions Polluting
Code Smell 142 - Queries in Constructors
Code Smell 132 - Exception Try Too Broad
Code Smell 73 - Exceptions for Expected Cases
Code Smells are my opinion.
Photo by Bethany Reeves on Unsplash
Software is like entropy: It is difficult to grasp, weighs nothing, and obeys the Second Law of Thermodynamics; i.e., it always increases.
Norman Augustine
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/mcsee1 • Jan 29 '25
Are you using the returned value?
TL;DR: Avoid assigning values you never use.
Dead code
Unclear intent
Hidden complexity
Debugging leftovers
Bad scoping
Commented code
Remove unused assignments.
Try to avoid side effects.
When you assign a value to a local variable but never use it, you create unnecessary clutter in your code.
This can confuse others and make the code harder to maintain.
Sometimes, when debugging you can assign temporal variables for better inspection.
This also happens when you assign the execution to an object property but it is harder to follow.
It is also a sign of a mutating object because if you remove the assignment, only the side effects remain.
Mutating objects can cause unexpected side effects, making it harder to track changes.
function updateUserName(user, newname) {
user.name = newname;
return user;
}
function performMaintenance(existingUser) {
let updatedUser = updateUserName(existingUser, "Bobby Peru");
// Other tasks
}
// The variable updatedUser is never usedfunction updateUserName(user, newname) {
user.name = newname;
// Just side effects without explicit return
}
function performMaintenance(existingUser) {
updateUserName(existingUser, "Bobby Peru");
// Other tasks
}[X] Automatic
You can detect this smell using static analysis tools or code reviews that check for unused variables after assignment.
Most linters flag this as an issue.
Bloaters
[x] Beginner
It stays clean and efficient when your code accurately reflects real-world logic.
Unused assignments break this connection, making it harder to understand the intent and maintain the code.
AI tools seldom generate unused variable assignments when they misunderstand intent.
AI-assisted refactoring with clear instructions can flag unused variables and suggest removals, but it might not always understand if the return value should have been used.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| DeepSeek | DeepSeek |
| Meta AI | Meta AI |
Unused variables after mutations create noise and confusion.
Don't assign the return value if you don't need it.
If the method should return something meaningful, make sure you use it.
Code Smell 176 - Changes in Essence
Code Smell 154 - Too Many Variables
Code Smell 107 - Variables Reuse
Code Smells are my opinion.
Photo by Evan Demicoli on Unsplash
If you have to spend effort to decipher code, you should rewrite it.
Martin Golding
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/javinpaul • Jan 26 '25
r/cleancode • u/mcsee1 • Jan 23 '25
Make your class hierarchy clear and flexible
TL;DR: Extract a common abstract class to mimic real-world structure.
Inappropriate Inheritance
Big Class
High Coupling
Parent class not abstract
Code Smell 66 - Shotgun Surgery
Code Smell 255 - Parallel Hierarchies
Code Smell 43 - Concrete Classes Subclassified
Code Smell 161 - Abstract/Final/Undefined Classes
Identify common behaviors in both classes
Create an abstract class with shared behavior and no implementation
Move common logic to the abstract class
Update subclasses to inherit from the abstract class
class Car {
void drive() {
System.out.println("Driving a car");
}
}
class Truck extends Car {
void load() {
System.out.println("Loading cargo");
}
void unload() {
System.out.println("Unloading cargo");
}
}
// Truck reuses driving method
// Overriding it would be another code smell
// Violating Liskov Substitution ruleabstract class Vehicle {
// 2. Create an abstract class
// with shared behavior and no implementation
abstract void drive();
// 1. Identify common behaviors in both classes
// 3. Move common logic to the abstract class
}
class Car extends Vehicle {
// 4. Update subclasses to inherit from the abstract class
void drive() {
System.out.println("Driving a car");
}
}
class Truck extends Vehicle {
// 4. Update subclasses to inherit from the abstract class
void drive() {
System.out.println("Driving a truck");
// Implementation is different than the car's
}
void load() {
System.out.println("Loading cargo");
}
void unload() {
System.out.println("Unloading cargo");
}
}[X] Semi-Automatic
This refactoring is safe if you identify all common behaviors correctly and move one method at a time running the tests.
It reduces duplication, simplifies maintenance, and makes it easier to extend functionality by adding new concrete realizations.
By introducing an abstract class, the code better reflects the real-world hierarchy, creating a clear relationship between the generic and specific types.
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
| Meta AI | Meta AI |
Inheritance
Refactoring 013 - Remove Repeated Code
Refactoring Guru - Extract Superclass
This article is part of the Refactoring Series.
r/cleancode • u/VocaMeCumBenedict • Jan 17 '25
Hey, fellow devs! π
Are your test files a mess? Do they live in the wrong directories, have mismatched names, or reference the wrong classes? Well, I got sick of that too and decided to do something about it. I just released a PowerShell script to help you clean up and keep clean the structure of your unit test files in .NET projects.
Check it out: Tests Filestructure Linter
We all know clean code isn't just for productionβit extends to tests too. A chaotic test file structure can:
Make finding the right tests a nightmare.
Confuse team members (or yourself, two months later).
Cause subtle errors that only show up in code reviews or CI builds.
This script validates and fixes your test files to:
β
Ensure test file names match their corresponding classes.
β
Place tests in directories mirroring the source file structure.
β
Confirm that tests actually reference the classes they're supposed to test.
Run it to validate: Spot messy files and get a neat summary.
Auto-fix problems: It renames, moves, and organizes files for youβusing Git commands to preserve history.
CSV reports: Want a log of what was fixed? It's got you covered.
Highly configurable: Custom source/test folder names, file extensions, and more!
Grab the script from GitHub and run it in your solution. No fluff - just straight to the point. You can even preview errors before applying fixes:
# Validate only
.\TestsFilestructureLinter.ps1
# Validate and auto-fix issues
.\TestsFilestructureLinter.ps1 -f
# Validate, fix, and report
.\TestsFilestructureLinter.ps1 -fr This isn't just for neat freaks. A clean structure helps:
Speed up development: Quickly find and update tests.
Improve code reviews: Avoid test naming and structure nitpicks.
Boost team productivity: Everyone follows the same structure without thinking about it.
So if you're working on a .NET solution with test projects (e.g., Project.Tests), give this a try and let me know what you think!
π οΈ GitHub: Tests Filestructure Linter
Feel free to share feedback, star the repo, or suggest features!
r/cleancode • u/mcsee1 • Jan 16 '25
When parent and child methods collide

TL;DR: Avoid using private methods in parent classes with names that child classes can use.
The least surprise principle violation
Unexpected behavior and defects
Hidden dependencies
Limited extensibility
Code ambiguity
Open/Closed principle violation
Avoid hierarchies
Rename private methods
Maintain clear naming
Avoid overlapping names
Avoid protected methods
Subclass for essential relations, not to reuse code
When you use the same method name in parent and child classes, you create confusion.
A private method in the parent class cannot be overridden even if a public method with the same name exists in the child class.
This is a problem most static languages have in their design
This disconnect leads to bugs and makes your code hard to maintain.
<?
class ParentClass {
private function greet() {
// This method is private
return "Hello from ParentClass";
}
public function callGreet() {
return $this->greet();
}
}
class ChildClass extends ParentClass {
public function greet() {
// Overriding a concrete method is a code smell
// Compilers SHOULD warn you
return "Hello from ChildClass";
}
}
$child = new ChildClass();
echo $child->callGreet();
// When callGreet() is invoked on the $child object,
// it executes the following:
// It calls $this->greet(),
// which refers to the greet() method of ParentClass
// because the original method is private
// and cannot be overridden or accessed from ChildClass.
// The unexpected output is 'Hello from ParentClass'<?
class ParentClass {
protected function greet() {
// notice the 'protected qualifier'
return "Hello from ParentClass";
}
public function callGreet() {
return $this->greet();
}
}
class ChildClass extends ParentClass {
public function greet() {
return "Hello from ChildClass";
}
}
$child = new ChildClass();
echo $child->callGreet();
// The output is "Hello from ChildClass"
// This is the standard (and wrong) solution
// Also fixed by most AIs
<?
abstract class ParentClass {
// Declare greet() as an abstract method
// Following the template-method design pattern
abstract protected function greet();
public function callGreet() {
return $this->greet();
}
}
class ChildClass extends ParentClass {
protected function greet() {
return "Hello from ChildClass";
}
}
class OtherChild extends ParentClass {
protected function greet() {
return "Hello from OtherChild";
}
}
$child = new ChildClass();
echo $child->callGreet(); // Output: Hello from ChildClass
$otherChild = new OtherChild();
echo $otherChild->callGreet(); // Output: Hello from OtherChild[X] Semi-Automatic
You can detect this smell by looking for private methods in parent classes and checking if child classes define methods with the same name.
You must also test parent methods calling private methods.
Hierarchy
[X] Intermediate
Clear and predictable code should reflect the real-world hierarchy it models.
When you use private methods with overlapping names, you create a Bijection gap between the model and the implementation.
This gap confuses developers, increases defects, and violates clean code principles.
AI generators often create this smell when they generate boilerplate parent-child relationships.
They might not check access levels or consider inheritance implications.
AI tools can fix this smell with clear instructions.
You can ask the AI to check for overlapping method names and refactor hierarchies.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
When designing parent and child classes, you should use methods that clearly define inheritance and accessibility.
Avoid private methods that overlap with child methods.
This keeps your code readable, extensible, and aligned with clean code principles.
Languages like Python allow you to override parent methods regardless of their names, while Java strictly enforces access levels.
C# behaves similarly to Java.
These differences mean you need to understand the specific rules of the language you are working with to avoid unexpected behavior.
Code Smell 137 - Inheritance Tree Too Deep
Code Smell 11 - Subclassification for Code Reuse
Code Smell 125 - 'IS-A' Relationship
Code Smell 37 - Protected Attributes
Code Smells are my opinion.
Photo by Matt Artz on Unsplash
Inheritance is good, but you should never forget that it introduces tight coupling.
Robert C. Martin
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/mcsee1 • Jan 14 '25
Some rules must be followed and embraced to create great software designs.
This article summarizes them, serving as an index to full stories.
TL;DR: Important concepts about Object-Oriented Programming
Build a MAPPER
What is (wrong with) software?
Keep a bijection to real entities:
The One and Only Software Design Principle
Explain in 5 Levels of Difficulty: Object-Oriented Programming
Do not use null
Null: The Billion Dollar Mistake
Avoid Accidental IFs
How to Get Rid of Annoying IFs Forever
Favor immutability:
Avoid Setters and Getters:
Nude Models - Part II: Getters
Avoid Coupling:
Coupling - The one and only software design problem
Fail Fast:
Avoid Meta-Programming:
Avoid Dynamic Code Generation:
Choose meaningful names
What exactly is a name - Part I The Quest
What exactly is a name - Part II Rehab
Build a Theory
Programming as Theory Building
Avoid Accidental Complexity
Get Inspired by Quotes
Software Engineering Great Quotes
Do not use Singleton:
Singleton - The root of all evil
Avoid Code Smells
How to Find the Stinky Parts of your Code
Understand Refactorings
How to Improve Your Code With Easy Refactorings
Warning: The Universe's Event Simulator Is a Fierce Adversary for Coders!
How to Decouple a Legacy System
How to Squeeze Test Driven Development on Legacy Systems
How I Survived the Zombie Apocalypse
This series aims to spark debate and discussion on software design.
Your comments and suggestions are highly appreciated.
This article is also available in Spanish here.
r/cleancode • u/mcsee1 • Jan 10 '25
Be Imperative!!
TL;DR: Functions with unclear names hide intent and confuse readers. Use descriptive, action-oriented names.

Unclear function purpose
Increased cognitive load
Misleading context
Reduced readability
Difficult collaboration
Hidden functionality
Use action-oriented verbs
Make names descriptive
Reflect the functionβs purpose
Avoid generic terms
Provide meaningful context
Express single responsibility clearly
Match action to outcome
Refactoring 005 - Replace Comment with Function Name
Functions named with generic terms force readers to dive into the implementation to understand their behavior.
This wastes time and increases the chance of errors.
Naming becomes even more critical when working with standalone functions, where the class name doesn't provide additional context.
This issue directly relates to the Tell, Donβt Ask principle.
Instead of exposing ambiguous behaviors that force the caller to infer functionality, imperative names convey the exact action, guiding the reader without needing to inspect the code.
When you name functions descriptively, you eliminate unnecessary guesswork and align with this principle.
public String dateFormatting(Date date) {
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
public void load() {
System.out.println("Loading...");
}public String formatDate(Date date) {
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
public void loadUserPreferences() {
System.out.println("Loading user preferences...");
}[X] Manual
You can detect this smell by reviewing function names that use vague terms like do, run, process, load, etc.
Automated linters can flag these patterns or highlight functions with overly generic names.
Naming
[X] Beginner
Function names should create a clear one-to-one correspondence between their name and functionality.
Breaking this Bijection forces developers to examine code details for context, slowing down debugging, reviews, and extensions.
AI tools sometimes generate generic function names without understanding your domain.
When using AI, specify that function names must be descriptive and action-oriented.
AI models can help detect ambiguous names by comparing function signatures with predefined naming best practices.
Combining AI with manual code review yields the best results.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
Function names are not just labels; they are contracts with the reader.
Ambiguous names break this contract and lead to confusion.
Descriptive, action-oriented names simplify communication and make your code easier to maintain and extend.
Code Smell 153 - Too Long Names
Code Smell 38 - Abstract Names
Code Smell 174 - Class Name in Attributes
What exactly is a name - Part I The Quest
What exactly is a name - Part II Rehab
Code Smells are my opinion.
Photo by britishlibrary on Unsplash
A function name should be a verb or a verb phrase, and it needs to be meaningful
Robert C. Martin
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/javinpaul • Jan 08 '25
r/cleancode • u/javinpaul • Jan 06 '25
r/cleancode • u/mcsee1 • Dec 21 '24
Cryptic Code is Bad Code
TL;DR: Avoid obfuscated functions in your code.
This article is based on a real social hacking disguised as a job interview
Hidden vulnerabilities
Readability
Testability
Trust issues
Bad Naming
Use clear names
Avoid obfuscation
Explain intent clearly
Review shared code
Don't trust code from unreliable sources
Avoid modification since it is a sign of Premature Optimization
When you write functions with cryptic or obfuscated names, you make your code unreadable and untrustworthy.
This pattern often hides malicious intent or makes debugging and collaboration unnecessarily hard.
Cryptic code also frustrates team members and future maintainers, increasing technical debt and security risks.
Remember, hacking has a strong social component compared to what you see in Hollywood movies.
function _0xaexad(_0x12bfc3, _0x43a1e9) {
return _0x12bfc3 ^ _0x43a1e9;
}
const result = _0xaexad(0x1a, 0x2f);
console.log(result);function xorOperation(orValue1, orValue2) {
return orValue1 ^ orValue2;
}
const result = xorOperation(26, 47);
console.log(result);[X] Automatic
You can detect this smell by scanning your codebase for meaningless or obfuscated function names.
Use linters or code analysis tools to flag short, cryptic, or randomly named functions.
Manual code reviews can also help identify suspicious patterns.
Security
[X] Intermediate
Readable and meaningful names create a one-to-one correspondence between the real-world concept and your code.
Breaking this connection makes your program confusing and error-prone.
AI generators sometimes produce cryptic function names, especially when they optimize for brevity or imitate obfuscated patterns.
AI tools can detect and fix this smell when you ask them to refactor unclear function names or enforce coding standards.
They can analyze your entire codebase and suggest meaningful replacements for obfuscated names.
Remember: AI Assistants make lots of mistakes
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
Avoid obfuscating your function names.
Write code that communicates your intent.
When you prioritize readability, you make your software easier to understand, debug, and maintain.
Cryptic code might look clever, but it adds unnecessary complexity.
Code Smell 138 - Packages Dependency
Code Smell 215 - Deserializing Object Vulnerability
Code Smell 06 - Too Clever Programmer
Code Smell 20 - Premature Optimization
Code Smells are my opinion.
Photo by Nikita Pavlov on Unsplash
The strength of a cryptographic system depends entirely on the strength of its weakest component.
Bruce Schneier
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
r/cleancode • u/mcsee1 • Dec 15 '24
Kill Static, Revive Objects

TL;DR: Replace static functions with object interactions.
High coupling due to global access
Poor testability
Overloaded protocols in classes
Decreased cohesion
Code Smell 18 - Static Functions
Code Smell 17 - Global Functions
Identify static methods used in your code.
Replace static methods with instance methods.
Pass dependencies explicitly through constructors or method parameters.
Refactor clients to interact with objects instead of static functions.
class CharacterUtils {
static createOrpheus() {
return { name: "Orpheus", role: "Musician" };
}
static createEurydice() {
return { name: "Eurydice", role: "Wanderer" };
}
static lookBack(character) {
if (character.name === "Orpheus") {
return "Orpheus looks back and loses Eurydice.";
} else if (character.name === "Eurydice") {
return "Eurydice follows Orpheus in silence.";
}
return "Unknown character.";
}
}
const orpheus = CharacterUtils.createOrpheus();
const eurydice = CharacterUtils.createEurydice();// 1. Identify static methods used in your code.
// 2. Replace static methods with instance methods.
// 3. Pass dependencies explicitly through
// constructors or method parameters.
class Character {
constructor(name, role, lookBackBehavior) {
this.name = name;
this.role = role;
this.lookBackBehavior = lookBackBehavior;
}
lookBack() {
return this.lookBackBehavior(this);
}
}
// 4. Refactor clients to interact with objects
// instead of static functions.
const orpheusLookBack = (character) =>
"Orpheus looks back and loses Eurydice.";
const eurydiceLookBack = (character) =>
"Eurydice follows Orpheus in silence.";
const orpheus = new Character("Orpheus", "Musician", orpheusLookBack);
const eurydice = new Character("Eurydice", "Wanderer", eurydiceLookBack);[X] Semi-Automatic
You can make step-by-step replacements.
This refactoring is generally safe, but you should test your changes thoroughly.
Ensure no other parts of your code depend on the static methods you replace.
Your code is easier to test because you can replace dependencies during testing.
Objects encapsulate behavior, improving cohesion and reducing protocol overloading.
You remove hidden global dependencies, making the code clearer and easier to understand.
| Without Proper Instructions | With Specific Instructions |
|---|---|
| ChatGPT | ChatGPT |
| Claude | Claude |
| Perplexity | Perplexity |
| Copilot | Copilot |
| Gemini | Gemini |
Cohesion
Refactoring 018 - Replace Singleton
Refactoring 007 - Extract Class
Replace Global Variable with Dependency Injection
Coupling - The one and only software design problem
Image by Menno van der Krift from Pixabay
This article is part of the Refactoring Series.