How to Find the Stinky Parts of Your Code [Part XXVI]

Written by mcsee | Published 2022/11/20
Tech Story Tags: refactoring | refactor-legacy-code | debugging | clean-code | code-smells | pixel-face | optimization | web-monetization

TLDRIt 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.) The smell of code smells is a classic, but it's not necessary to fix it per sepective. For example, code smells include: "Stinky-parts-of-your-code-part-ii-o96s3wl4"via the TL;DR App

Code smells Are a Classic.

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

Let's continue...

Code Smell 126 - Fake Null Object


Null Objects are great alternatives to The Billion Dollar Mistake. Sometimes we don't need them


TL;DR: Don't abuse patterns. Even NullObject.

.Problems

  • Empty Classes
  • Namespace Polluting
  • Duplicated Behavior

Solutions

  1. Create Null Objects instantiating real-object classes.

Context

Null Object pattern is an excellent alternative to Nulls and IFs (Both are code smells).

The structure of the pattern tells us to create a hierarchy.

This is not necessary; we need natural objects to be polymorphic to null objects.

Inheritance is not a proper way to achieve polymorphism.

A simple solution is to create a real object behaving like a null one.

For example: '0' is the numbers' null object.

“(or "") is String's null object

An empty collection is the collection's null object.

Sample Code

Wrong

abstract class Address {
	public abstract String getCity();
	public abstract String getState();
	public abstract String getZipCode();
}

// Using inheritance for null objects is a mistake
// We should use interfaces (when available)
public class NullAddress extends Address {
	
	public NullAddress() { }
	
	public String getCity() {
		return Constants.EMPTY_STRING;
	}

	public String getState() {
		return Constants.EMPTY_STRING;
	}

	public String getZipCode() {
		return Constants.EMPTY_STRING;
	}

}

public class RealAddress extends Address {
	
	private String zipCode;
	private String city;
	private String state;

	public RealAddress(String city, String state, String zipCode) {
		this.city = city;
		this.state = state;
		this.zipCode = zipCode;
	}

	public String getZipCode() {
		return zipCode;
	}
	
	public String getCity() {
		return city;
	}

	public String getState() {
		return state;
	}

}

Right

// There are just "addresses"
public class Address {
	
	private String zipCode;
	private String city;
	private String state;

	public Address(String city, String state, String zipCode) {
    // Looks anemic :(
		this.city = city;
		this.state = state;
		this.zipCode = zipCode;
	}

	public String zipCode() {
		return zipCode;
	}
	
	public String city() {
		return city;
	}

	public String state() {
		return state;
	}

}

Address nullAddress = new Address(Constants.EMPTY_STRING, Constants.EMPTY_STRING, Constants.EMPTY_STRING);
// we have our null object
// we should NOT assign it to a singleton, static or global
// It behaves like a null object. That's enough
// No premature optimizations

Detection

  • [x]Manual

This is a semantic smell.

Tags

  • Null

Conclusion

Creating Null Object classes is sometimes overdesign.

We need to create a real object.

This real object should never be a global, singleton, or static.

Too many smells to avoid.

Relations

Code Smell 12 - Null

Code Smell 32 - Singletons

Code Smell 114 - Empty Class

Code Smell 18 - Static Functions

Code Smell 17 - Global Functions

More Info

Credits

Photo by Juan Davila on Unsplash

Thanks to Hernan Wilkinson for this idea on his course Diseño a la Gorra (in Spanish)


All models are wrong but some models are useful

George Box

Software Engineering Great Quotes


Code Smell 127 - Mutable Constants

You declare something a constant. But you can mutate it.

TL;DR: Use inmutable constants

Problems

  • Mutability
  • The Least Surprise Principle violation
  • Coupling

Solutions

  1. Enforce mutability
  2. Avoid constants. They are hard to mock in tests.

Context

We learned to declare constants in our first course on computer programming.

As always, it is not important if something is constant.

It is important if it does not mutate.

Sample Code

Wrong

const DISCOUNT_PLATINUM = 0.1;
const DISCOUNT_GOLD = 0.05;
const DISCOUNT_SILVER = 0.02;

// Since variables are constants we cannot reassign them
const DISCOUNT_PLATINUM = 0.05; // Error

// We can group them
const ALL_CONSTANTS = {
  DISCOUNT: {
    PLATINUM = 0.1;
    GOLD = 0.04;
    SILVER = 0.02;  
  },
};

const ALL_CONSTANTS = 3.14; // Error

ALL_CONSTANTS.DISCOUNT.PLATINUM = 0.08; // NOT AN ERROR. WTF!


const ALL_CONSTANTS = Object.freeze({
  DISCOUNT: 
    PLATINUM = 0.1;
    GOLD = 0.05;
    SILVER = 0.02; 
});

const ALL_CONSTANTS = 3.14; // Error

ALL_CONSTANTS.DISCOUNT.PLATINUM = 0.12; // NOT AN ERROR. WTF!

Right

export const ALL_CONSTANTS = Object.freeze({
  DISCOUNT: Object.freeze({
    PLATINUM = 0.1;
    GOLD = 0.05;
    SILVER = 0.02;  
  }),
});

const ALL_CONSTANTS = 3.14; // Error

ALL_CONSTANTS.DISCOUNT.PLATINUM = 0.12; // ERROR

// Code works, but it is coupled and we cannot test it

Class TaxesProvider {
  applyPlatinum(product);
}

// Now we can couple to a interface (the protocol of taxes provider)
// Since class has no setters it is constant an immutable
// And we can replace it on tests

Detection

  • [x]Semi-Automatic

We can perform mutation testing to find changed values.

Tags

  • Constants

Conclusion

Mutability is essential.

We need to enforce it with the right tools.

Relations

Code Smell 86 - Mutable Const Arrays

Code Smell 107 - Variables Reuse

Code Smell 02 - Constants and Magic Numbers

More Info

Credits

This smell was inspired by This

Photo by Sangharsh Lohakare on Unsplash


You start digging in the code. The more you dig, the more stuff you turn up. Eventually you dig yourself into a hole you can’t get out of. To avoid digging your own grave, refactoring must be done systematically.

Eric Gamma

Software Engineering Great Quotes


Code Smell 128 - Non-English Coding

Using your local language is an excellent idea because domain naming is easier. Not

TL;DR: Stick to English. Always.

Problems

  • Polymorphism
  • Cultural gaps
  • Mixed Code
  • Syntactic Errors

Solutions

  1. Write in English
  2. Rename Domain Concepts to English

Context

All programming languages are written in English.

Unless for a few failed experiments during the '90s, all modern languages use English for their primitives and their frameworks.

If you wanted to read or write in medieval Europe, you had to acquire a new language at the same time. Writing meant Latin.

This is true for programming languages nowadays.

I am not a Native English speaker.

My code (tries to be) is in English.

Sample Code

Wrong

const elements = new Set();

elements.add(1);
elements.add(1);

echo elements.size() yields 1 
// This is the standard set

var moreElements = new MultiConjunto();
// We defined a multiset in Spanish
// because we are extending the domain

moreElements.agregar('hello');
moreElements.agregar('hello');
// 'agregar' is the Spanish word for 'add'

echo moreElements.size() yields 2 // Since it is a multiset

// elements and moreElements are NOT polymorphic
// I cannot exchange their implementation

Right

const elements = new Set();

elements.add(1);
elements.add(1);

echo elements.size() yields 1 
// This is the standard set

var moreElements = new MultiSet();
// We defined a multiset in English

moreElements.add('hello');
moreElements.add('hello');

echo moreElements.size() yields 2 // Since it is a multiset

// elements and moreElements are polymorphic
// I can exchange their implementation anytime

Detection

  • [x]Automatic

Most IDEs and linters have a thesaurus.

We can search for foreign words.

Tags

  • Readability

Conclusion

Don't mix Non-English domain words with English primitives.

Even when Mapping your real-world entities, use plain English.

More Info

Credits

Photo by Anna Vander Stel on Unsplash


A programming language is a tool that has a profound influence on our thinking habits.

Edsger Dijkstra

Software Engineering Great Quotes


Code Smell 129 - Structural Optimizations

We love to improve time and space complexity by guessing not real scenarios

TL;DR: Don't optimize anything until you have a real use scenario benchmark.

Problems

Solutions

  1. Cover your scenarios with tests.
  2. Write readable (and possibly non-performant) code.
  3. Do a real benchmark with real user data. (No, iterating your code 100,000 times might not be a real use case).
  4. If you have conclusive data, you need to improve benchmark found bottlenecks using the Pareto principle.
  5. Attack the worst 20% of problems causing 80% bad performance.

Context

In university and in online courses, we learn algorithms, data structures, and computational complexity before good design rules.

We tend to overestimate the (possible) performance problems and underestimate code readability and software lifetime.

Premature optimization often has no evidence of solving real problems.

We need to surgically improve our code when the facts tell us we have a real issue.

Sample Code

Wrong

for (k = 0; k < 3 * 3; ++k) {
     i = Math.floor(k / 3);
     j = k % 3;
     console.log(i + ' ' +  j);
  }
 
// This cryptic piece of code iterates a
// two dimensional array
// We don't have proofs this will be useful
// In real contexts

Right

for (innerIterator = 0; innerIterator < 3; innerIterator++) {
  for (outerIterator = 0; outerIterator < 3; outerIterator++) {
   console.log(innerIterator + ' ' +  outerIterator);
  }
 }

// This is a readable double for-loop
// 3 is a small number
// No performance issues (by now)
// We will wait for real evidence

Detection

  • [x]Manual

This is a semantic smell.

We might find the code harder to read.

Tags

  • Premature Optimization

Conclusion

We need to stop optimizing for machines and start optimizing for human readers and code maintainers.

We need to avoid programming languages designed for premature optimization and favor robust ones.

Relations

Code Smell 06 - Too Clever Programmer

Code Smell 20 - Premature Optimization

More Info

Credits

Photo by Priscilla Du Preez on Unsplash


Optimism is an occupational hazard of programming: feedback is the treatment.

Kent Beck

Software Engineering Great Quotes


Code Smell 130 - AddressImpl

It is nice to see a class implementing Interfaces. It is nicer to understand what it does

TL;DR: Name your classes after real-world concepts.

Problems

Solutions

  1. Find the correct name using the MAPPER

Context

Some languages bring idioms and common usages against good model naming.

We should pick our names carefully.

Sample Code

Wrong

public interface Address extends ChangeAware, Serializable {

    /**
     * Gets the street name.
     *
     * @return the street name
     */
    String getStreet();
    // ...
}

// Wrong Name - There is no concept 'AddressImpl' in real world
public class AddressImpl implements Address {
    private String street;
    private String houseNumber;
    private City city;
    // ..
}

Right

// Simple
public class Address {
    private String street;
    private String houseNumber;
    private City city;
    // ..
}


// OR
// Both are real-world names
public class Address implements ContactLocation {
    private String street;
    private String houseNumber;
    private City city;
    // ..
}

Detection

  • [x]Automatic

Since this is a naming smell.

We can search using regular expressions and rename these concepts.

Tags

  • Naming

Conclusion

We should pick class names according to essential bijection and not follow accidental implementation.

Do not call “I” to your interfaces.

Relations

Code Smell 65 - Variables Named after Types

Code Smell 38 - Abstract Names

More Info

Credits

Photo by Paula Hayes on Unsplash


Encoded names are seldom pronounceable and are easy to miss-type.

Robert C. Martin

Software Engineering Great Quotes


And that’s all for now…

The next article will explain five more code smells!


Written by mcsee | I’m senior software engineer specialized in declarative designs and S.O.L.I.D. and Agile lover.
Published by HackerNoon on 2022/11/20