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 - XXXIII) here.
Let's continue...
Code Smell 166 - Low-Level Errors on User Interface
Fatal error: Uncaught Error: Class 'logs_queries_web' not found in /var/www/html/query-line.php:78
Stack trace: #0 {main} thrown in /var/www/html/query-line.php on line 718
TL;DR: Catch your errors. Even the ones you don't expect.
Problems
- Security
- Error Handling
- Error Logging
- Bad UX Experience
Solutions
-
Use a top-level handler.
-
Avoid languages favoring return codes.
-
Expect database and low-level errors.
Context
Even in 2022, we can see "serious" websites showing casual users a stack or debugging message.
Sample Code
Wrong
<?
Fatal error: Uncaught Error: Class 'MyClass'
not found in /nstest/src/Container.php:9
Right
<?
// A user-defined exception handler function
function myException($exception) {
logError($exception->description())
// We don't show Exception to final users
}
// Set user-defined exception handler function
set_exception_handler("myException");
Detection
- [x]Automatic
We can use mutation testing to simulate problems and see if they are handled correctly.
Tags
- Security
Conclusion
We need to keep maturing.
Our solutions shouldn't be sloppy.
We need to improve our reputation as serious software engineers.
Relations
More Info
Disclaimer
Code Smells are just my opinion.
Credits
Photo by jesse orrico on Unsplash
80 percent of my problems are simple logic errors. 80 percent of the remaining problems are pointer errors. The remaining problems are hard.
Mark Donner
Software Engineering Great Quotes
Code Smell 167 - Hashing Comparison
Hashing guarantees two objects are different. Not that they are the same.
TL;DR: If you check for the hash, you should also check for equality
Problems
Solutions
- Check for hash (fast), and then check for Equality (slow)
Context
On Oct 7th, 2022, one of the larger blockchains had to be halted.
This news was shocking since most blockchains are decentralized by definition.
You can read a full article here:
How a Hacker Stole $566M USD Exploiting a Code Smell
Sample Code
Wrong
public class Person {
public String name;
// Public attributes are another smell
@Override
public boolean equals(Person anotherPerson) {
return name.equals(anotherPerson.name);
}
@Override
public int hashCode() {
return (int)(Math.random()*256);
}
// This is just an example of non-correlation
// When using HashMaps we can make a mistake
// and guess the object is not present in the collection
}
Right
public class Person {
public String name;
// Public attributes are another smell
@Override
public boolean equals(Person anotherPerson) {
return name.equals(anotherPerson.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
// This is just an example of non-correlation
}
Detection
- [x]Semi-Automatic
Many linters have rules for hash and equality redefinition.
With mutation testing, we can seed different objects with the same hash and check our tests.
- Identity
- Security
Conclusion
Every performance improvement has its drawbacks.
Caches and replications are notable examples.
We can (must) use them carefully.
Relations
Code Smell 150 - Equal Comparison
More Info
Disclaimer
Code Smells are just my opinion.
This will surprise some of your readers, but my primary interest is not with computer security. I am primarily interested in writing software that works as intended.
Wietse Venema
Software Engineering Great Quotes
Code Smell 168 - Undocumented Decisions
We need to make some changes. We need to be clear on why
TL;DR: Be declarative on your design or implementation decisions.
Problems
- Code Comments
- Lack of testability
Solutions
- Be Explicit about the reasons.
- Convert the comment to a method.
Context
Sometimes we find arbitrary rules not so easily testable.
If we cannot write a failing test, we need to have a function with an excellent and declarative name instead of a comment.
Sample Code
Wrong
// We need to run this process with more memory
set_memory("512k)
run_process();
Right
increase_memory_to_avoid_false_positives();
run_process();
Detection
- [x]Semi-Automatic
This is a semantic smell.
We can detect comments and warn us.
Tags
- Comments
Conclusion
Code is prose. And design decisions should be narrative.
Relations
Code Smell 05 - Comment Abusers
Code Smell 75 - Comments Inside a Method
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Goh Rhy Yan on Unsplash
Programs, like people, get old. We can’t prevent aging, but we can understand its causes, limit its effects and reverse some of the damage.
Mario Fusco
Software Engineering Great Quotes
Code Smell 169 - Glued Methods
Don't make two or more things at once.
TL;DR: Try to be as atomic as possible in your methods
Problems
- Coupled Code
- Harder to test
- Harder to read
Solutions
- Break the method
Refactorings
https://maximilianocontieri.com/refactoring-002-extract-method
Context
If you name a method with 'And', you are probably missing an extract-and-break method opportunity.
Sample Code
Wrong
calculatePrimeFactorsRemoveDuplicatesAndPrintThem()
// Three responsibilities
Right
calculatePrimeFactors();
removeDuplicates();
printNumbers();
// Three different methods
// We can test them and reuse them
Detection
- [x]Semi-Automatic
Some linters can warn us about methods including the term 'and'.
Tags
- Coupling
Conclusion
When making methods, it is very important to play some rubber duck story and tell ourselves if we are making things right.
Relations
%[https://maximilianocontieri.com/code-smell-85-and-functions]
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Scott Sanker on Unsplash
Learning the art of programming, like most other disciplines, consists of first learning the rules and then learning when to break them.
Joshua Bloch
Code Smell 170 - Refactor With Functional Changes
Developing is great. refactoring is amazing. Don't make it at the same time
TL;DR: Don't change functionally and refactor at the same time.
Problems
- Hard to review solutions
- Merge Conflicts
Solutions
- Never change functionality while refactoring
Context
Sometimes we detect a refactoring is needed for further development.
We are experts at learning.
We should put our solution on hold. Work on the refactoring, and continue with our solution.
Sample Code
Wrong
getFactorial(n) {
return n * getFactorial(n);
}
// Rename and Change
factorial(n) {
return n * factorial(n-1);
}
// This is a very small example
// Things go works while dealing with huge code
Right
getFactorial(n) {
return n * getFactorial(n);
}
// Change
getFactorial(n) {
return n * getFactorial(n-1);
}
// Run the tests
factorial(n) {
return n * factorial(n-1);
}
// Rename
Detection
This is a refactoring smell.
- [x]Manual
Tags
- Refactoring
Conclusion
We should use a physical token.
Either we are in the refactoring stage or the developing stage.
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Dannie Jing on Unsplash
When I’m studying code, refactoring leads me to higher levels of understanding that I would otherwise miss. Those who dismiss comprehension refactoring as useless fiddling with the code don’t realize they never see the opportunities hidden behind the confusion.
Martin Fowler
5 more code smells are coming soon…