Part forty is here!!!
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.)
You can find all the previous code smells (Part i - XXXIX) here.
Let's continue...
Array creation is homogenous and predictable, or is it a hack?
TL;DR: Be very careful with Javascript Arrays.
Javascript has a lot of magic tricks.
Knowing them makes some developers proud and a sense of belonging to juniors.
A language should be intuitive, homogeneous, predictable, simple, and pure.
const arrayWithFixedLength = new Array(3);
console.log(arrayWithFixedLength); // [ <5 empty items> ]
console.log(arrayWithFixedLength[0]); // Undefined
console.log(arrayWithFixedLength[1]); // Undefined
console.log(arrayWithFixedLength[3]); // Undefined
console.log(arrayWithFixedLength[4]); // Undefined
console.log(arrayWithFixedLength.length); // 3
const arrayWithTwoElements = new Array(3, 1);
console.log(arrayWithTwoElements); // [ 3, 1 ]
console.log(arrayWithTwoElements[0]); // 3
console.log(arrayWithTwoElements[1]); // 1
console.log(arrayWithTwoElements[2]); // Undefined
console.log(arrayWithTwoElements[5]); // Undefined
console.log(arrayWithTwoElements.length); // 2
const arrayWithTwoElementsLiteral = [3,1];
console.log(arrayWithTwoElementsLiteral); // [ 3, 1 ]
console.log(arrayWithTwoElementsLiteral[0]); // 3
console.log(arrayWithTwoElementsLiteral[1]); // 1
console.log(arrayWithTwoElementsLiteral[2]); // Undefined
console.log(arrayWithTwoElementsLiteral[5]); // Undefined
console.log(arrayWithTwoElementsLiteral.length); // 2
We can check for the notation with one argument and flag it as a warning.
Many "modern" languages are full of hacks to make life easier for programmers but are a source of potential undiscovered bugs.
Code Smell 06 - Too Clever Programmer
Code Smell 69 - Big Bang (JavaScript Ridiculous Castings)
Code Smell 93 - Send me Anything
Code Smells are just my opinion.
Photo by Ryan Quintal on Unsplash
Originally on this tweet:
When someone says, "I want a programming language in which I need only say what I want done," give him a lollipop.
Alan J. Perlis
Software Engineering Great Quotes
TL;DR: Don't prefix or suffix your names with irrelevant information
In software development, gratuitous context refers to the unnecessary inclusion of additional information or data in code or user interfaces that do not contribute to the functionality or usability of the software.
It can make the software more difficult to use, understand and maintain.
It also increases the risk of errors or defects.
struct WEBBExoplanet {
name: String,
mass: f64,
radius: f64,
distance: f64,
orbital_period: f64,
}
struct WEBBGalaxy {
name: String,
classification: String,
distance: f64,
age: f64,
}
struct Exoplanet {
name: String,
mass: f64,
radius: f64,
distance: f64,
orbital_period: f64,
}
struct Galaxy {
name: String,
classification: String,
distance: f64,
age: f64,
}
We can find command patterns and rename all objects.
Class Preffixing was a widespread practice decades ago to claim ownership.
Carefully consider the context and content of the software, and avoid including unnecessary or extraneous information wherever possible.
Now we know clean names are more important.
Code Smell 141 - IEngine , AVehicle, ImplCar
Code Smell 174 - Class Name in Attributes
What exactly is a name - Part II Rehab
Code Smells are my opinion.
Photo by Mitchell Griest on Unsplash
The most dangerous kind of waste is the waste we do not recognize.
Shigeo Shingo
Software is about contracts and ambiguous contracts are a nightmare
TL;DR: Keep your code explicit
Hidden assumptions are underlying beliefs or expectations not explicitly stated in the code.
They are still present and can impact the behavior of the software.
Various reasons can give rise to assumptions such as incomplete requirements, incorrect presumptions about the user or environment, limitations of the programming language or tools, and bad accidental decisions.
tenCentimeters = 10
tenInches = 10
tenCentimeters + tenInches
# 20
# this error is based on the hidden assumption of a unit (any)
# and caused the Mars Climate Orbiter failure
class Unit:
def __init__(self, name, symbol):
self.name = name
self.symbol = symbol
class Measure:
def __init__(self, scalar, unit):
self.scalar = scalar
self.unit = unit
def __str__(self):
return f"{self.scalar} {self.unit.symbol}"
centimetersUnit = Unit("centimeters", "cm")
inchesUnit = Unit("inches", "in")
tencCentimeters = Measure(10, centimeters)
tenInches = Measure(10, inches)
tenCentimeters + tenInches
# error until we introduce a conversion factor
# in this case the conversion is constant
# inches = centimeters / 2.54
This is a design smell
Hidden assumptions can be difficult to identify and can lead to bugs, security vulnerabilities, and usability issues.
To mitigate these risks, software developers should be aware of their assumptions and biases.
Developers also need to engage with users to understand their needs and expectations.
They must test their software in various scenarios to uncover hidden assumptions and edge cases.
Code Smell 02 - Constants and Magic Numbers
Coupling - The one and only software design problem
Code Smells are my opinion.
Photo by Christian Pfeifer on Unsplash
A human organization is just as much an information system as any computer system. It is almost certainly more complex, but the same fundamental ideas apply. Things that are fundamentally difficult, like concurrency and coupling, are difficult in the real world of people, too.
Dave Farley
A code that either returns or no returns at all
TL;DR: Check carefully your boolean expressions
When a function is designed to return an invariant value, it may be poor design, but it shouldn’t adversely affect the outcome of your program. However, when it happens on all paths through the logic, it is likely a mistake.
This rule raises an issue when a function contains several return statements that all return the same value.
# Gratuitous boolean expressions
if a > 0 and True:
print("a is positive")
else:
print("a is not positive")
if a > 0:
print("a is positive")
else:
print("a is not positive")
Many linters can detect this problem by parsing execution trees.
Boolean expressions should be straightforward to read and understand.
Code Smell 101 - Comparison Against Booleans
How to Get Rid of Annoying IFs Forever
Code Smells are just my opinion.
Photo by Jungwoo Hong on Unsplash
The central enemy of reliability is complexity.
Daniel Geer
An object that appears and disappears mysteriously
TL;DR: Add the necessary indirection layers, but no more.
A poltergeist (or gypsy wagon) is a short-lived object used to perform initialization or to invoke methods in another, more permanent class.
An object is responsible for many small tasks, resulting in excessive coupling and a lack of cohesion in the code.
public class Driver
{
private Car car;
public Driver(Car car)
{
this.car = car;
}
public void DriveCar()
{
car.driveCar();
}
}
Car porsche = new Car();
Driver homer = new Driver(porsche);
homer.DriveCar();
Car porsche = new Car();
porsche.driveCar();
// We don't need the driver
This is a design smell.
Don't add accidental complexity to the essential complexity we already have.
Remove middleman objects if they are not needed.
Code Smells are my opinion.
The art of programming is the art of organizing complexity, of mastering multitude and avoiding its bastard chaos as effectively as possible.
E. W. Dijkstra
5 more code smells are coming soon…