Yet more code smells? Aren't them enough?
We see several symptoms and situations that make us doubt the quality of our development.
Let's look at some possible solutions.
Most of these smells are just hints of something that might be wrong. They are not rigid rules.
This is part V. Part I can be found here, Part II here, Part III is here, Part IV here, part V, VI, VII, VIII, IX and the last one (for now).
Let's continue...
Not operator is our friend. Not not operator is not our friend.
if ( !work.isNotFinished() )
if ( work.isDone() )
This is a semantic smell. We need to detect it on code reviews.
We can tell linters to check for Regular Expressions like !not or !isNot etc as a warning.
Double negation is a very basic rule we learn as junior developers.
There are lots of production systems filled with this smell.
We need to trust our test coverage and make safe renames and other refactors.
Photo by Daniel Herron on Unsplash
It’s harder to read code than to write it.
Joel Spolsky
Fragile, Intermittent, Sporadic or Erratic tests are common in many organizations.
Nevertheless, they mine the developers trust.
We must avoid them.
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import components.set.Set;
import components.set.Set1L;
public abstract class SetTest {
protected abstract Set<String> constructor();
@Test
public final void testAddEmpty() {
Set<String> s = this.constructor();
s.add("green");
s.add("blue");
assertEquals("{green. blue}", s.toString());
//This is fragile since it dependes on set sort (which is not defined)
}
}
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import components.set.Set;
import components.set.Set1L;
public abstract class SetTest {
protected abstract Set<String> constructor();
@Test
public final void testAddEmpty() {
Set<String> s = this.constructor();
s.add("green");
assertEquals("{green}", s.toString());
}
@Test
public final void testEntryAtSingleEntry() {
Set<String> s = this.createFromArgs("red");
Boolean x = s.contains("red");
assertEquals(true, x);
}
}
Detection can be done with test run statistics.
It is very hard to put some test in maintenance since we are removing a safety net.
Fragile tests show system coupling and not deterministic or erratic behavior.
Developers spend lots of time and effort fighting against this false positives.
The amateur software engineer is always in search of magic.
Grady Booch
Photo by Elena Mozhvilo on Unsplash
for (i = 0; i < colors.count(), i++) {
print(colors[i]);
}
foreach (color of colors) {
print(color);
}
//Closures and arrow functions
colors.foreach(color => print(color));
Linters can find this smell using regex.
There might be false positives. See exceptions below.
If the problem domain needs the elements to be bijected to natural numbers like indices, the first solution is adequate.
Remember all time to find real world analogies.
This kind of smell do not ring the bell to many developers because they think this is a subtlety.
Clean code is full of this few declarative things that can make a difference.
If you get tired of writing for loops, take a break and continue later.
David Walker
Photo by Kris Mikael Krister on Unsplash
<?
final class DatabaseQueryOptimizer {
public function selectWithCriteria($tableName, $criteria) {
//Make some optimizations manipulating criterias
}
private function sqlParserOptimization(SQLSentence $sqlSentence): SQLSentence {
//Parse the SQL converting it to an string and then working with their nodes as strings and lots of regex
//This was a very costly operation overcoming real SQL benefits.
//But since we made too much work we decide to keep the code.
}
}
<?
final class DatabaseQueryOptimizer {
public function selectWithCriteria($tableName, $criteria) {
//Make some optimizations manipulating criterias
}
}
Using some mutation testing variants we can remove the dead code and see it test fails.
We need to have good coverage to rely on this solution.
Dead code is always a problem.
We can use modern development techniques like TDD to ensure all code is alive.
It is very hard to predict, especially the future.
Niels Bohr
Picture by Nicolas Poussin
<?
final class Point {
public $x;
public $y;
}
final class DistanceCalculator {
function distanceBetween(Point $origin, Point $destination) {
return sqrt((($destination->x - $origin->x) ^ 2) + (($destination->y - $origin->y) ^ 2));
}
}
<?
final class Point {
private $rho;
private $theta;
public function x() {
return $this->rho * cos($this->theta);
}
public function y() {
return $this->rho * sin($this->theta);
}
}
final class DistanceCalculator {
function distanceBetween(Point $origin, Point $destination) {
return sqrt((($destination->x() - $origin->x() ^ 2) + (($destination->y() - $origin->y()) ^ 2)));
}
}
You can set your linters to warn you for public attributes, setters and getters usage and discourage them.
If your classes are polluted with setters, getters and public methods you will certainly have ways to couple to their accidental implementation.
A data structure is just a stupid programming language.
Bill Gosper
We are done for now. But we are pretty sure we will come across even more smells very soon!
I keep getting more suggestions on twitter, so they won't be the last!