It smells because there are likely many instances where it could be edited or improved.
Most of these smells are just hints of something that might be wrong. Therefore, they are not required to be fixed per se… (You should look into it, though.)
Previous Code Smells
You can find all the previous code smells (Part i - XXXVII) here.
Let's continue...
Code Smell 186 - Hardcoded Business Conditions
You are FTX and your code allows special cases
TL;DR: Don't add hard business rules to your code.
Problems
- Open / Closed Principle Violation
- Hardcoding
- Testability
Solutions
- Reify the condition.
- Create configuration options and set the exception on the configuration behavior.
- Don't use Settings/Configs.
Context
According to Reuters, in a recent FTX scandal, there was a hardcoded condition to skip risk controls to its own portfolio.
The code was explicit and developers were aware of that rule.
Sample Code
Wrong
if (currentExposure > 0.15 && customer != "Alameda") {
// Be extra careful not to liquidate
liquidatePosition();
}
Right
customer.liquidatePositionIfNecessary(0.15);
// This follows the Tell, Don't ask principle
Detection
- [x]Semi-Automatic
We can search for primary hardcoded conditions (related to primitive types).
We might have more false positives than actual problems.
Tags
- Hardcoding
Conclusion
If you make code reviews, pay special attention to this kind of hard coding.
Relations
Code Smell 133 - Hardcoded IF Conditions
Code Smell 29 - Settings / Configs
More Info
Credits
Photo by Alexander Mils on Unsplash
Computer science inverts the normal. In normal science, you're given a world, and your job is to find out the rules. In computer science, you give the computer the rules, and it creates the world.
Alan Kay
Software Engineering Great Quotes
Code Smell 187 - If/Else Backwards
The first thing we read after the if the condition is the IF
TL;DR: You have the important else condition on the else.
Problems
- Readability
Solutions
- Swap the conditions.
Context
It is not as straightforward as it appears to write IF clauses in an elegant manner.
There are lots of variants and choices.
We need to pay special attention to readability.
Sample Code
Wrong
fun addToCart(item: Any) {
if (!cartExists()) {
// Condition is negated
this.createCart();
this.cart.addItem(Item);
// Repeated Code
}
else {
// Normal case is on the else clause
this.cart.addItem(Item);
}
}
Right
fun addToCart(item: Any) {
if (cartExists()) {
this.cart.addItem(Item);
}
else {
this.createCart();
this.cart.addItem(Item);
}
}
fun addToCartShorter(item: Any) {
if (!cartExists()) {
this.createCart();
}
this.cart.addItem(Item);
}
Detection
- [x]Semi-Automatic
We can find negated expressions on IF conditions and check for this anti-pattern.
Tags
- IFs
Conclusion
We need to read code like prose.
Humans read the standard case first and the exceptional one after it.
Relations
Code Smell 51 - Double Negatives
Code Smell 156 - Implicit Else
More Info
Credits
Photo by Karol Kasanicky on Unsplash
Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defense against complexity.
D. Gelernter
Code Smell 188 - Redundant Parameter Names
Use contextual and local names
TL;DR: Don't repeat your parameters' names. Names should be contextual.
Problems
- Duplication
- Readability
Solutions
- Remove the repeated part from the name
Context
When using names, we often miss that words are contextual and need to be read as a whole sentence.
Sample Code
Wrong
class Employee
def initialize(@employee_first_name : String, @employee_last_name : String, @employee_birthdate : Time)
end
end
Right
class Employee
def initialize(@first_name : String, @last_name : String, @birthdate : Time)
end
end
Detection
- [x]Semi-Automatic
We can check our parameter names and try to find duplication.
Tags
- Naming
Conclusion
Use short and contextual names for your parameters.
Relations
Code Smell 174 - Class Name in Attributes
Code Smell 87 - Inconsistent Parameters Sorting
Credits
Photo by Wolfgang Hasselmann on Unsplash
As a rule, software systems do not work well until they have been used, and have failed repeatedly, in real applications.
David Parnas
Code Smell 189 - Not Sanitized Input
Bad actors are there. We need to be very careful with their input.
TL;DR: Sanitize everything that comes from outside your control.
Problems
- Security
Solutions
- Use sanitization and input filtering techniques.
Context
Whenever you get input from an external resource, a security principle requests you to validate and check for potentially harmful inputs.
SQL Injection is a notable example of a threat.
We can also add assertions and invariants to our inputs.
Even better, we can work with Domain Restricted Objects.
Sample Code
Wrong
user_input = "abc123!@#"
# This content might not be very safe if we expect just alphanumeric characters
Right
import re
def sanitize(string):
# Remove any characters that are not letters or numbers
sanitized_string = re.sub(r'[^a-zA-Z0-9]', '', string)
return sanitized_string
user_input = "abc123!@#"
print(sanitize(user_input)) # Output: "abc123"
Detection
- [x]Semi-Automatic
We can statically check all the inputs and also we can also use penetration testing tools.
Tags
- Security
Conclusion
We need to be very cautious with the inputs beyond our control.
Relations
Code Smell 121 - String Validations
Code Smell 178 - Subsets Violation
Code Smell 15 - Missed Preconditions
More Info
Credits
Photo by Jess Zoerb on Unsplash
Companies should make their own enterprise systems as often as network security companies should manufacture their own aspirin.
Phil Simon
Code Smell 190 - Unnecessary Properties
Stop thinking of data as attributes. They are only needed to back your behavior
TL;DR: Don't focus on accidental properties. You won't need many of them.
Problems
- Anemic Models
- Properties bloating
- YAGNI violation
Solutions
- Create attributes only to support your methods (behavior).
Context
Whenever they want to model a person or an employee, junior programmers or students add an attribute 'id' or 'name' without thinking if they are really going to need them.
We need to add attributes 'on-demand' when there's enough evidence. Objects are not 'data holders'.
Sample Code
Wrong
class PersonInQueue
attr_accessor :name, :job
def initialize(name, job)
@name = name
@job = job
end
end
Right
class PersonInQueue
def moveForwardOnePosition
# implement protocol
end
end
Detection
- [x]Semi-Automatic
We can detect unused attributes.
But in many cases, we need an excellent designer to validate the actual need.
Tags
- Anemic
Conclusion
Start designing your objects from the protocol.
Add attributes only when needed.
Relations
Code Smell 144 - Fungible Objects
Code Smell 109 - Automatic Properties
Credits
Photo by Melanie Pongratz on Unsplash
Object thinking focuses our attention on the problem space rather than the solution space.
David West
5 more code smells are coming soon…