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 - XXXV) here.
Let's continue...
Code Smell 176 - Changes in Essence
Mutation is good. Things change.
TL;DR: Don't change essential attributes or behavior
Problems
- Bijection violation
Solutions
-
Protect essential attributes from change.
Refactorings
Refactoring 001 - Remove Setters
Context
Heraclitus said:
“No man ever steps in the same river twice. For it’s not the same river and he’s not the same man.”
The man stays the same in essence. But his body evolves.
Sample Code
Wrong
const date = new Date();
date.setMonth(4);
Right
const date = new Date("2022-03-25");
Detection
- [x]Manual
This is a semantic smell. We need to model which attributes/behaviors are essential and which are accidental.
Tags
Conclusion
We need to favor immutable objects.
Objects can mutate in accidental ways; not in essential ones.
Relations
More Info
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Nick Fewings on Unsplash
Changes in software design will eventually mean "one step forward, two steps back". It is inevitable.
Salman Arshad
Code Smell 177 - Missing Small Objects
We see small primitive data everywhere
TL;DR: Don't forget to model the smallest ones
Problems
- Primitive obsession
Solutions
-
Find responsibilities for small objects in the MAPPER.
-
Reify them.
Context
Since the early computing days, we map all we see to the familiar primitive data types: Strings, Integers, Collections, etc.
Mapping to dates violates abstraction and fail-fast principles.
in the Wordle TDD Kata, we describe a Wordle word to be different than a String or Char(5), since they don't have the same responsibilities.
Sample Code
Wrong
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
}
Right
public class Name {
private final String name;
public Name(String name) {
this.name = name;
// Name has its own creation rules, comparison etc.
// Might be different than a string
}
}
public class Person {
private final Name name;
public Person(Name name) {
// name is created as a valid one,
// we don't need to add validations here
this.name = name;
}
}
Detection
- [x]Manual
This is a semantic smell. It is related to design activity
Exceptions
In a very small number of mission-critical systems, we have a tradeoff from abstraction to performance.
This is not the usual case. We do premature optimization by not relying on a modern computer and virtual machine optimizations.
As always, we need to stick to evidence in real-world scenarios.
Tags
- Primitive
Conclusion
Finding small objects is a very hard task requiring experience to make a good job and avoid overdesign.
There's no silver bullet in choosing how and when to map something.
Relations
Code Smell 122 - Primitive Obsession
More Info
How to Create a Wordle with TDD in Javascript
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Shane Aldendorff on Unsplash
The secret to building large apps is never build large apps. Break your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application.
Justin Meyer
Code Smell 178 - Subsets Violation
Invisible objects have rules we need to enforce at a single point.
TL;DR: Create Small objects and restrict your domain.
Problems
- Bijection Fault
- Repeated Code validation
Solutions
- Create small objects and validate the domain.
Context
This is a primitive obsession smell.
EmailAddresses are a subset of string.
Valid Ages are a subset of Real.
Ports are a subset of Integers.
A wordle word is a subset of String.
Sample Code
Wrong
destination = "[email protected]"
destination = "destination.example.com"
// No error thrown
Right
public class EmailAddress {
public String emailAddress;
public EmailAddress(String address) {
string expressions = @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
if (!Regex.IsMatch(email, expressions) {
throw new Exception('Invalid address');
}
this.emailAddress = address;
}
}
destination = new EmailAddress("[email protected]");
Not to be confused with the anemic Java version
Detection
- [x]Manual
This is a semantic smell.
Tags
- Primitive Obsession
Conclusion
We need to be loyal to the bijection of the real world.
Subsets are very important for early validations and fail fast principle.
Relations
Code Smell 122 - Primitive Obsession
More Info
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Mona Eendra on Unsplash
Every craftsman starts his or her journey with a basic set of good-quality tools.
Andrew Hunt
Code Smell 179 - Known Bugs
Every software has a list of known bugs. Why?
TL;DR: Don't track bugs. Fix them.
Problems
- Hard to-track lists
- Technical Debt
- Functional Debt
Solutions
-
Stop calling it a Bug
-
Reproduce the Defect.
-
Cover the scenario with automation.
-
Make the most straightforward fix (even hardcoding solutions)
-
Refactor
Welcome to TDD!
Context
We don't like to be interrupted.
Then, we create lists and delay fixes and solutions.
We should be able to change software easily.
We need to improve our software if we can't do quick fixes and corrections.
Not by creating To-Fix lists.
Sample Code
Wrong
<?
function divide($numerator, $denominator) {
return $numerator / $denominator;
// FIXME denominator value might be 0
// TODO Rename function
}
Right
<?
function integerDivide($numerator, $denominator) {
if (denominator == 0) {
throw new DivideByZero();
}
return $numerator / $denominator;
}
// we pay our debts
Detection
- [x]Automatic
We need to avoid creating bugs and issues.
Tags
- Technical Debt
Conclusion
We need to discourage bugs and issue trackers on the engineering side.
Of course, customers need to track their findings, and we need to address them ASAP.
Relations
More Info
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Justin Lauria on Unsplash
In general, the longer you wait before fixing a bug, the costlier (in time and money) it is to fix.
Joel Spolsky
Code Smell 180 - BitWise Optimizations
Bitwise operators are faster. Avoid these micro-optimizations.
TL;DR: Don't use bitwise operators unless your business model is bitwise logic.
Problems
- Readability
- Cleverness
- Premature Optimization
- Maintainability
- Bijection Violation
Solutions
- Improve readability
Context
Some clever programmers solve problems we don't have.
We should optimize code based on evidence and use the scientific method.
We should benchmark only if necessary and improve code only if really necessary and bear the cost of changeability and maintainability.
Sample Code
Wrong
const nowInSeconds = ~~(Date.now() / 1000)
Right
const nowInSeconds = Math.floor(Date.now() / 1000)
Detection
- [x]Semi-Automatic
We can tell our linters to warn us and manually check if it is worth the change.
Exceptions
- Real-time and mission-critical software.
Tags
- Premature Optimization
Conclusion
If we find this code in a pull request or code review, we need to understand the reasons. If they are not justified, we should do a rollback and change it to a normal logic.
Relations
Code Smell 20 - Premature Optimization
Code Smell 165 - Empty Exception Blocks
Code Smell 06 - Too Clever Programmer
Code Smell 129 - Structural Optimizations
More Info
Disclaimer
Code Smells are just my opinion.
Credits
Photo by Frédéric Barriol on Unsplash
Original Article Here.
Watch the little things; a small leak will sink a great ship.
Benjamin Franklin
5 more code smells are coming soon…