Infinite code, smells!
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. They are not required fixed per se… ( You should look into it though.)
Previous Code Smells
Let's continue...
Code Smell 81 - Result
result = ???
TL;DR: Use good names always. Result is always a very bad name.
Problems
- Readability
Solutions
- Rename result.
- If you don't know how to name it, just name the variable with the same name as the last function call.
- Don't use IDEs without automatic refactors.
Sample Code
Wrong
var result;
result = lastBlockchainBlock();
//
// Many function calls
addBlockAfter(result);
Right
var lastBlockchainBlock;
lastBlockchainBlock = findlastBlockchainBlock();
//...
// Many function calls
// we should refactor them to minimize space
// between variable definition and usage
addBlockAfter(lastBlockchainBlock);
Detection
We must forbid the word result to be a variable name.
Tags
- Readability
Conclusion
Result is an example of generic and meaningless names.
Refactoring is cheap and safe.
Always leave the campground cleaner than you found it.
When you find a mess on the ground, clean it, doesn’t matter who did it. Your job is to always leave the ground cleaner for the next campers.
Relations
More info
Credits
Code is like humor. When you have to explain it, it’s bad.
Cory House
Code Smell 82 - Tests Violating Encapsulation
Objects work fine and fulfill business objectives. But we need to test them. Let's break them.
TL;DR: Don't write methods with the only purpose of being used in your tests.
Problems
- Encapsulation Violation.
- Bad interfaces
- Coupling
Solutions
- Don't break encapsulation.
- Test must be in full control.
- If you cannot control your object, you are coupled. Decouple them!
Sample Code
Wrong
<?
class Hangman {
private $wordToGuess;
function __construct() {
$this->wordToGuess = getRandomWord();
//Test is not in control of this
}
public function getWordToGuess(): string {
return $this->wordToGuess;
//Sadly we need to reveal this
}
}
class HangmanTest extends TestCase {
function test01WordIsGuessed() {
$hangmanGame = new Hangman();
$this->assertEquals('tests', $hangmanGame->wordToGuess());
//how can we make sure the word is guessed?
}
}
Right
<?
class Hangman {
private $wordToGuess;
function __construct(WordRandomizer $wordRandomizer) {
$this->wordToGuess = $wordRandomizer->newRandomWord();
}
}
class MockRandomizer implements WordRandomizer {
function newRandomWord(): string {
return 'tests';
}
}
class HangmanTest extends TestCase {
function test01WordIsGuessed() {
$hangmanGame = new Hangman(new MockRandomizer());
//We are in full control!
$this->assertFalse($hangmanGame->wordWasGuessed());
$hangmanGame->play('t');
$this->assertFalse($hangmanGame->wordWasGuessed());
$hangmanGame->play('e');
$this->assertFalse($hangmanGame->wordWasGuessed());
$hangmanGame->play('s');
$this->assertTrue($hangmanGame->wordWasGuessed());
//We just test behavior
}
}
Detection
This is a design smell.
We can detect we need a method just for test.
Tags
- Information Hiding
Conclusion
White-box tests are fragile. They test implementation instead of behavior.
Relations
More Info
Credits
This smell was inspired by @Rodrigo
Nothing makes a system more flexible than a suite of tests.
Robert Martin
Code Smell 83 - Variables Reassignment
Variable reuse is something we see in big chunks of code.
TL;DR: Don't reuse variable names. You break readability and refactor chances and gain nothing but laziness.
Problems
- Readability
- Refactor chances
- Missed Optimization
- Mutability
- Garbage Collection Missed Opportunities
Solutions
- Define, use and dispose variables.
- Keep your Definition, Usage and Destroy variables short.
Sample Code
Wrong
class Item:
def __init__(self, name):
self.name = name
def taxesCharged(self):
return 1;
class Money:
pass
lastPurchase = Item('Soda');
# Do something with the purchase
taxAmount = lastPurchase.taxesCharged();
# Lots of stuff related to the purchase
# I drink the soda
# I cannot extract method from below without passing
# useless lastPurchase as parameter
# a few hours later..
lastPurchase = Item('Whisky');
# I bough another drink
taxAmount += lastPurchase.taxesCharged();
Right
class Item:
def __init__(self, name):
self.name = name
def taxesCharged(self):
return 1;
class Money:
pass
def buySupper():
supperPurchase = Item('Soda');
# Do something with the purchase
# Lots of stuff related to the purchase
# I drink the soda
return supperPurchase;
def buyDrinks():
# I could extract method!
# a few hours later..
drinksPurchase = Item('Whisky');
# I bough another drink
return drinksPurchase;
taxAmount = buySupper().taxesCharged() + buyDrinks().taxesCharged();
Detection
Many linters can warn us from reusing variables
Tags
- Readability
Conclusion
Reusing variables is a non-contextual copy and paste hint.
Relations
Code Smell 03 - Functions Are Too Long
More Info
Credits
Photo by Robby McCullough on Unsplash
Either way you look at it (DRY or laziness), the idea is the same: make your program flexible. When change comes (and it always does), you'll have a much easier time changing with it.
Chris Pine
Code Smell 84 - Max < Min (Javascript)
Some functions do not behave as expected. Sadly, most programmers accept them.
TL;DR: Don't trust max() and min() functions. Just ignore them.
Problems
- Principle of least astonishment
- Bijection Violation.
- Unexpected Results
Solutions
- Use mature languages.
- Avoid max() and min() functions.
- Model Infinites carefully.
Sample Code
Wrong
console.log(Math.max() > Math.min());
//returns false
console.log(Math.max());
//returns -Infinite
Right
console.log(Math.max() > Math.min());
console.log(Math.max());
//returns Exception. Not enough arguments passed.
//Max requires at least one argument
Detection
These functions belong to the standard Math library. Therefore, they are not easy to avoid.
We can block them on our linters.
Tags
- Javascript
Conclusion
We need to be very careful using functions that violate real-world concepts using language tricks.
Relations
Code Smell 69 - Big Bang (JavaScript Ridiculous Castings)
More Info
Credits
Photo by Cris Baron on Unsplash
Inspired by @@Oliver Jumpertz
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
Rick Cook
Code Smell 85 - And Functions
Do not perform more than requested.
TL;DR: Unless you need atomicity, do not perform more than one task.
Problems
- Coupling
- Single Responsibility Principle violation
- Readability
- Low Cohesion
- Testability
Solutions
- Break the function
Sample Code
Wrong
def fetch_and_display_personnel():
data = # ...
for person in data:
print(person)
Right
def fetch_personnel():
return # ...
def display_personnel(data):
for person in data:
print(person)
Detection
Functions including "and" are candidates. However, we need to check them carefully since there might be false positives.
Tags
- Readability
- Naming
Conclusion
We should avoid doing more than needed, and our functions should be both minimal and atomic.
More Info
Credits
This smell was inspired by
If it takes more than a sentence to explain what you are doing, it’s almost always a sign that what you are doing is too complicated.
Sam Altman
And that’s all for now…
The next article will explain 5 more code smells!