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

Written by mcsee | Published 2022/05/04
Tech Story Tags: code-smells | common-code-smells | clean-code | refactoring | refactor-legacy-code | pixel-face | programming | software-engineering | 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.via the TL;DR App

Infinite code, smells!

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. They are not required fixed per se… ( You should look into it though.)

Previous Code Smells

Let's continue...


Code Smell 86 - Mutable Const Arrays

Const declares something to be constant. Can it mutate?

TL;DR: Don't rely on languages cheating about directives.

Problems

  • Unexpected side effects
  • Accidental complexity

Solutions

  1. Use better languages
  2. Use spread operator

Sample Code

Wrong

const array = [1, 2];

array.push(3)

//array => [1, 2, 3]
//Wasn't it constant ?
//constant != immutable ?

Right

const array = [1, 2];

const newArray = [...array,3 ]

//array => [1, 2] Didn't mutate
//newArray = [1, 2, 3]

Detection

Since this is a "language feature", we can explicitly forbid it.

Tags

  • Mutability
  • JavaScript

Conclusion

We should always favour immutability on our designs and take extra care with side effects.

More Info

Credits

Photo by Zorik D on Unsplash

Twitter


Correctness is clearly the prime quality. If a system does not do what it is supposed to do, then everything else about it matters little.

Bertrand Meyer


Code Smell 87 - Inconsistent Parameters Sorting

Be consistent with the parameters you use. Code is prose.

TL;DR: Don't confuse you readers. Keep the order.

Problems

  • Readability
  • Consistency

Solutions

  1. Refactor and change parameters order.
  2. Use named parameters

Sample Code

Wrong

function giveFirstDoseOfVaccine(person, vaccine) {
  //
}

function giveSecondDoseOfVaccine(vaccine, person) {
  //
}


giveFirstDoseOfVaccine(jane, pfizer);
giveSecondDoseOfVaccine(jane, pfizer);  //Unnoticed mistake

Right

function giveFirstDoseOfVaccine(person, vaccine) {
  //
}

function giveSecondDoseOfVaccine(person, vaccine) {
  //
}


giveFirstDoseOfVaccine(jane, pfizer);
giveSecondDoseOfVaccine(jane, pfizer);  //Jane is immunized

Detection

  • Some very smart linters may be able to compare arguments and hint for possible mistakes.

Tags

  • Readability

Conclusion

This is a very simple smell.

Readability is very important to avoid mistakes.

Relations

Code Smell 10 - Too Many Arguments

Credits

Photo by Lance Grandahl on Unsplash

Twitter


Computers are good at following instructions, but not at reading your mind.

Donald Knuth


Code Smell 88 - Lazy Initialization

Yet another premature optimization pattern

TL;DR: Do not use lazy initialization. Use an object provider instead.

Problems

  • Surprising Side Effects
  • Premature Optimization
  • Fail Fast Violation
  • Implementative Coupling
  • The Least Surprise Principle Violation
  • Null Usage
  • Mutability
  • Transactional and Multi-threaded applications problems
  • Debugging Problems

Solutions

  1. Inject Responsibilities with First Class Objects

Sample Code

Wrong

class Employee
  def emails
    @emails ||= []
  end
  
  def voice_mails
    @voice_mails ||= []
  end
end

Right

class Employee
  attr_reader :emails, :voice_mails

  def initialize
    @emails = []
    @voice_mails = []
  end
end
#We can also inject a design pattern to externally deal
#with voice_mails so we can mock it in our tests

Detection

Lazy initialization is a common pattern when used checking for a non-initialized variable.

It should be straightforward to detect them.

Tags

  • Premature Optimization

Conclusion

Singletons are another antipattern often combined with lazy initialization.

We must avoid premature optimizations. If we have real performance problems we should use a Proxy, Facade or more independent solution.

Relations

Code Smell 32 - Singletons

Code Smell 12 - Null

More Info

Credits

Photo by Sam Solomon on Unsplash


We have to stop optimizing for programmers and start optimizing for users.

Jeff Atwood


Code Smell 89 - Math Feature Envy

One class calculating formulas for another class.

TL;DR: Leave the formulas to the objects gathering the information.

Problems

  • Declaratively
  • Low reuse
  • Real-world concept missing
  • Encapsulation

Solutions

  1. Move the math formula to the class
  2. Search for real-world abstractions

Sample Code

Wrong

function area(rectangle) { 
  return rectange.width * rectangle.height;
  //Notice we are sending consecutive messages to
  //the same object and doing calculations
}

Right

class Rectangle {
    constructor(width, height, color) { 
         this.height = height;
         this.width = width;
    }
 
    area() {
        return this.width * this.height;
    }
}

Detection

Since many cascading messages are sending to the same object, we can detect a pattern.

Tags

  • Encapsulation
  • Coupling

Conclusion

This is a very basic smell. If we are manipulating another object characteristics, we should let it do it the maths for us.

Relations

Code Smell 63 - Feature Envy

More Info

Credits

Photo by Michal Matlon on Unsplash


Computer science is not about machines, in the same way that astronomy is not about telescopes. There is an essential unity of mathematics and computer science.

Michael R. Fellows


Code Smell 90 - Implementative Callback Events

When creating events, we should decouple the trigger from the action.

TL;DR: Name your functions acording to what happened.

Problems

Solutions

  1. Name the events after "what happened", not "what you should do".

Sample Code

Wrong

const Item = ({name, handlePageChange)} =>
  <li onClick={handlePageChange}>
    {name}
  </li>

//handlePageChange is coupled to what you decide to do
//instead of what really happened
//
//We cannot reuse this kind of callbacks

Right

const Item = ({name, onItemSelected)} =>
  <li onClick={onItemSelected}>
    {name}
  </li>

//onItemSelected will be called just when a item was selected. KISS
//Parent can decide what to do (or do nothing)
//We defer the decision

Detection

This is a semantic smell. We can detect it on peer code reviews.

Tags

  • Coupling
  • Naming

Conclusion

Names are very important. We should delay implementation coupled names until the very last moment.

More Info

Credits

Photo by Ashim D’Silva on Unsplash

Thanks to Maciej for this tip

Twitter


Beyond basic mathematical aptitude, the difference between good programmers and great programmers is verbal ability.

Marissa Mayer


And that’s all for now…

The next article will explain 5 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/05/04