Photo by Filipe Resmini on Unsplash
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.)
Let's continue...
Don't make weak tests to create a false sensation of coverage.
square = Square(5)
assert square.area() != 0
# This will lead to false negatives since it is too vague
square = Square(5)
assert square.area() = 25
# Assertion should be precise
With Mutation Testing techniques we can find these errors on our tests.
We should use development techniques like TDD that request concrete business cases and make concrete assertions based on our domain.
Code Smell 30 - Mocking Business
This smell was inspired by @Mario Cervera and used with his permission.
Timestamps are widely used. They have a central issuing authority and do not go back, do they?
# using time module
import time
# ts stores the time in seconds
ts1 = time.time()
ts2 = time.time() #might be the same!!
numbers = range(1, 100000)
#create a sequence of numbers and use them with a hotspot
#or
sequence = nextNumber()
Timestamps are very popular on many languages and are ubiquitous.
We need to use them just to model... timestamps.
This smell was inspired by recent Ingenuity software fault.
If we don't follow our MAPPER rules and model sequences with time, we will face trouble.
Luckily, Ingenuity is a sophisticated Autonomous vehicle and has a robust fail-safe landing software.
This video describes the glitch.
https://www.youtube.com/watch?v=6IoMiwxL2wU
Code Smell 71 - Magic Floats Disguised as Decimals
Jon Bentley
Processing an algorithm as a sequence of nested callbacks is not clever.
TL;DR: Don't process calls in a callback way. Write a sequence.
var fs = require('fs');
var fileWithData = '/hello.world';
fs.readFile(fileWithData, 'utf8', function(err, txt) {
if (err) return console.log(err);
txt = txt + '\n' + 'Add Data!';
fs.writeFile(fileWithData, txt, function(err) {
if(err) return console.log(err);
console.log('Information added');
});
});
var fs = require('fs');
function logTextWasAdded(err) {
if(err) return console.log(err);
console.log('Information added');
};
function addData(error, actualText) {
if (error) return console.log(error);
actualText = actualText + '\n' + 'Add data';
fs.writeFile(fileWithData, actualText, logTextWasAdded);
}
var fileWithData = 'hello.world';
fs.readFile(fileWithData, 'utf8', addData);
This problem shines at the naked eye. Many linters can detect this complexity and warn us.
Callback Hell is a very common problem in programming languages with futures or promises.
Callbacks are added in an incremental way. There's no much mess at the beginning.
Complexity without refactoring makes them hard to read and debug.
Code Smell 06 - Too Clever Programmer
If a name is already used, we can always prefix it with 'the'.
TL;DR: don't prefix your variables.
var result;
result = getSomeResult();
var theResult;
theResult = getSomeResult();
var averageSalary;
averageSalary = calculateAverageSalary();
//..
var averageSalaryWithRaises;
averageSalaryWithRaises = calculateAverageSalary();
As with many of our naming conventions, we can instruct our linters to forbid names like theXxx....
Always use intention revealing names.
If your names collide use local names, extract your methods and avoid 'the' prefixes.
Code Smell 38 - Abstract Names
Photo by Josue Michel on Unsplash
One difference between a smart programmer and a professional programmer is that the professional understands that clarity is king. Professionals use their powers for good and write code that others can understand.
Robert C. Martin
Exceptions are a great way of separating happy path versus trouble path. But we tend to over-complicate our solutions.
try {
transaction.commit();
} catch (e) {
logerror(e);
if (e instanceOf DBError){
try {
transaction.rollback();
} catch (e) {
doMoreLoggingRollbackFailed(e);
}
}
}
//Nested Try catchs
//Exception cases are
//more important than happy path
//We use exceptions as control flow
try {
transaction.commit();
} catch (transactionError) {
this.withTransactionErrorDo(
transationError, transaction);
}
//transaction error policy is not defined in this function
//so we don't have repeated code
//code is more readable
//It is up to the transaction
//and the error to decide what to do
We can detect this smell using parsing trees.
Don't abuse exceptions, don't create Exception classes no one will ever catch, and don't be prepared for every case (unless you have a good real scenario with a covering test).
Happy path should always be more important than exception cases.
Code Smell 73 - Exceptions for Expected Cases
Code Smell 26 - Exceptions Polluting
Photo by David Clode on Unsplash
Thanks to @Rodrigo for his inspiration
Karolina Szczur
And that’s all for now…
The next article will explain 5 more code smells!