visit
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.)
Changing a collection while traversing might lead to unexpected errors
TL;DR: Do not modify collections while traversing them
Collection<Integer> people = new ArrayList<>();
// here we add elements to the collection...
for (Object person : people) {
if (condition(person)) {
people.remove(person);
}
}
// We iterate AND remove elements
Collection<Integer> people = new ArrayList<>();
// Here we add elements to the collection...
List<Object> iterationPeople = ImmutableList.copyOf(people);
for (Object person : iterationPeople) {
if (condition(person)) {
people.remove(person);
}
}
// We iterate a copy and remove it from original
coll.removeIf(currentIndex -> currentIndex == 5);
// Or use language tools (if available)
Code Smell 53 - Explicit Iteration
Bugs are bugs. You write code with bugs because you do. If it’s a safe language in the sense of run-time safe, the operating system crashes instead of doing a buffer overflow in a way that’s exploitable.
- Ken Thompson
Software Engineering Great Quotes
If you work on unit testing, sooner or later you will face this dilemma
TL;DR: Don't test your private methods.
<?
final class Star {
private $distanceInParsecs;
public function timeToReachLightToUs() {
return $this->convertDistanceInParsecsToLightYears($this->distanceInParsecs);
}
private function convertDistanceInParsecsToLightYears($distanceInParsecs) {
return 3.26 * $distanceInParsecs;
// function is using an argument which is already available.
// since it has private access to $distanceInParsecs
// this is another smell indicator.
// We cannot test this function since it is private
}
}
<?
final class Star {
private $distanceInParsecs;
public function timeToReachLightToUs() {
return new ParsecsToLightYearsConverter($this->distanceInParsecs);
}
}
final class ParsecsToLightYearsConverter {
public function convert($distanceInParsecs) {
return 3.26 * $distanceInParsecs;
}
}
final class ParsecsToLightYearsConverterTest extends TestCase {
public function testConvert0ParsecsReturns0LightYears() {
$this->assertEquals(0, (new ParsecsToLightYearsConverter)->convert(0));
}
// we can add lots of tests and rely on this object
// So we don't need to test Star conversions.
// We can yet test Star public timeToReachLightToUs()
// This is a simplified scenario
}
Code Smell 21 - Anonymous Functions Abusers
Code Smell 18 - Static Functions
Just as it is a good practice to make all fields private unless they need greater visibility, it is a good practice to make all fields final unless they need to be mutable.- Brian Goetz
Software Engineering Great Quotes
Use entity domain names to model entity domain objects.
TL;DR: Don't name your variables as Data.
if (!dataExists()) {
return '<div>Loading Data...</div>';
}
if (!peopleFound()) {
return '<div>Loading People...</div>';
}
Code Smell 65 - Variables Named after Types
What exactly is a name - Part II Rehab
Twenty percent of all input forms filled out by people contain bad data.- Dennis Ritchie
Software Engineering Great Quotes
Have you encountered classes without behavior? Classes are their behavior.
TL;DR: Remove all empty classes.
Many developers still think classes are data repositories.
They couple different behavior concepts with returning different data.
class ShopItem {
code() { }
description() { }
}
class BookItem extends ShopItem {
code() { return 'book' }
description() { return 'some book'}
}
// concrete Class has no real behavior, just return different 'data'
class ShopItem {
constructor(code, description) {
// validate code and description
this._code = code;
this._description = description;
}
code() { return this._code }
description() { return this._description }
// dd more functions to avoid anemic classes
// getters are also code smells, so we need to iterate it
}
bookItem = new ShopItem('book', 'some book);
// create more items
We can also make our own scripts using metaprogramming.
Code Smell 26 - Exceptions Polluting
Code Smell 60 - Global Classes
An error arises from treating object variables (instance variables) as if they were data attributes and then creating your hierarchy based on shared attributes. Always create hierarchies based on shared behaviors, side.- David West
Software Engineering Great Quotes
Booleans are natural code smells. Returning and casting them is sometimes a mistake.
TL;DR: Don't return true or false. Be declarative.
When we create complex and mature software, we start to forget about this primitive obsession and care about real-world rules and identities.
boolean isEven(int num) {
if(num%2 == 0) {
return true;
} else {
return false;}
}
boolean isEven(int numberToCheck) {
// We decouple the what (to check for even or odd)
// With how (the algorithm)
return (numberToCheck % 2 == 0);
}
Search on code libraries for return true statements and try to replace them when possible.
Code Smell 36 - Switch/case/elseif/else/if statements
The good news is: Anything is possible on your computer. The bad news is: Nothing is easy.- Ted Nelson
Software Engineering Great Quotes