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.)
Don't add IFs checking for the production environment.
TL;DR: Avoid adding conditionals related to production
def send_welcome_email(email_address, environment):
if ENVIRONMENT_NAME == "production":
print(f"Sending welcome email to {email_address} from Bob Builder <[email protected]>")
else:
print("Emails are sent only on production")
send_welcome_email("[email protected]", "development")
# Emails are sent only on production
send_welcome_email("[email protected]", "production")
# Sending welcome email to [email protected] from Bob Builder <[email protected]>
class ProductionEnvironment:
FROM_EMAIL = "Bob Builder <[email protected]>"
class DevelopmentEnvironment:
FROM_EMAIL = "Bob Builder Development <[email protected]>"
# We can unit test environments
# and even implement different sending mechanisms
def send_welcome_email(email_address, environment):
print(f"Sending welcome email to {email_address} from {environment.FROM_EMAIL}")
# We can delegate into a fake sender (and possible logger)
# and unit test it
send_welcome_email("[email protected]", DevelopmentEnvironment())
# Sending welcome email to [email protected] from Bob Builder Development <[email protected]>
send_welcome_email("[email protected]", ProductionEnvironment())
# Sending welcome email to [email protected] from Bob Builder <[email protected]>
Complexity is a sign of technical immaturity. Simplicity of use is the real sign of a well design product whether it is an ATM or a Patriot missile.
Daniel T. Ling
Software Engineering Great Quotes
Reusing variables makes scopes and boundaries harder to follow
TL;DR: Don't read and write the same variable for different purposes
// print line total
double total = item.getPrice() * item.getQuantity();
System.out.println("Line total: " + total );
// print amount total
total = order.getTotal() - order.getDiscount();
System.out.println( "Amount due: " + total );
// variable is reused
function printLineTotal() {
double total = item.getPrice() * item.getQuantity();
System.out.println("Line total: " + total );
}
function printAmountTotal() {
double total = order.getTotal() - order.getDiscount();
System.out.println( "Amount due: " + total );
}
Code Smell 03 - Functions Are Too Long
Refactoring 002 - Extract Method
Simplicity before generality, use before reuse.
Kevlin Henney
Software Engineering Great Quotes
Asserting two float numbers are the same is a very difficult problem
TL;DR: Don't compare floats
Assert.assertEquals(0.0012f, 0.0012f); // Deprecated
Assert.assertTrue(0.0012f == 0.0012f); // Not JUnit - Smell
Assert.assertEquals(0.0012f, 0.0014f, 0.0002); // true
Assert.assertEquals(0.0012f, 0.0014f, 0.0001); // false
// last parameter is the delta threshold
Assert.assertEquals(12 / 10000, 12 / 10000); // true
Assert.assertEquals(12 / 10000, 14 / 10000); // false
We can add a check con assertEquals() on our testing frameworks to avoid checking for floats.
Code Smell 71 - Magic Floats Disguised as Decimals
God made the natural numbers; all else is the work of man.
Leopold Kronecker
Software Engineering Great Quotes
What happens if you combine 4 code smells?
TL;DR: Avoid Getters, Avoid Setters, Avoid Metaprogramming. Think about Behavior.
class Person
{
public string name
{ get; set; }
}
class Person
{
private string name
public Person(string personName)
{
name = personName;
//imutable
//no getters, no setters
}
//... more protocol, probably accessing private variable name
}
Code Smell 70 - Anemic Model Generators
Nothing is harder than working under a tight deadline and still taking the time to clean up as you go.
Kent Beck
Software Engineering Great Quotes
Default means 'everything we don't know yet'. We cannot foresee the future.
TL;DR: Don't add a default clause to your cases. Change it for an exception. Be Explicit.
Since case and switches are also an smell, we can avoid them.
switch (value) {
case value1:
// if value1 matches the following will be executed..
doSomething();
break;
case value2:
// if value2 matches the following will be executed..
doSomethingElse();
break;
default:
// if value does not presently match the above values
// or future values
// the following will be executed
doSomethingSpecial();
break;
}
switch (value) {
case value1:
// if value1 matches the following will be executed..
doSomething();
break;
case value2:
// if value2 matches the following will be executed..
doSomethingElse();
break;
case value3:
case value4:
// We currently know these options exist
doSomethingSpecial();
break;
default:
// if value does not match the above values we need to take a decision
throw new Exception('Unexpected case ' + value + ' we need to consider it');
break;
}
Code Smell 36 - Switch/case/elseif/else/if statements
The cost of adding a feature isn’t just the time it takes to code it. The cost also includes the addition of an obstacle to future expansion. The trick is to pick the features that don’t fight each other.
John Carmack
Software Engineering Great Quotes