How to Find The Stinky Parts of Your Code [Part XIV]

Written by mcsee | Published 2022/02/24
Tech Story Tags: code-smells | clean-code | refactoring | pixel-face | programming | software-engineering | software-development | stinky-parts-of-your-code | web-monetization

TLDRMore smells on the way. We improve our knowledge with many more examplesvia the TL;DR App

Infinite code smells!

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.

Previous Parts

Part I

Part II

Part III

Part IV

Part V

Part VI

Part VII

Part VIII

Part IX

Part X

Part XI

Part XII

Part XIII

Let's continue...

Code Smell 66 - Shotgun Surgery

Say it only once

Problems

  • Bad Responsibilities Assignments
  • Code Duplication
  • Maintainability
  • Single Responsibility Violation.
  • Copy-pasted code.

Solutions

  1. Refactor

Sample Code

Wrong

final class SocialNetwork {

    function postStatus(string $newStatus) {
        if (!$user->isLogged()) {
            throw new Exception('User is not logged');
        }
        ///...
    }

    function uploadProfilePicture(Picture $newPicture) {
        if (!$user->isLogged()) {
            throw new Exception('User is not logged');
        }
        ///...
    }

    function sendMessage(User $recipient, Message $messageSend) {
        if (!$user->isLogged()) {
            throw new Exception('User is not logged');
        }
        ///...
    }
}

Right

<?

final class SocialNetwork {

    function postStatus(string $newStatus) {
        $this->assertUserIsLogged();
        ///...
    }

    function uploadProfilePicture(Picture $newPicture) {
        $this->assertUserIsLogged();
        ///...
    }

    function sendMessage(User $recipient, Message $messageSend) {
        $this->assertUserIsLogged();
        ///...
    }

    function assertUserIsLogged() {
        if (!$this->user->isLogged()) {
            throw new Exception('User is not logged');
            //This is just a simplification to show the code smell
            //Operations should be defined as objects with preconditions etc.
        }
    }
}

Detection

Some modern linters can detect repeated patterns (not just repeated code) and also while performing our code reviews we can easily detect this problem and ask for a refactor.

Tags

  • Code Duplication

Conclusion

Adding a new feature should be straightforward it our model maps 1:1 to real world and our responsibilities are in the correct places. We should be alert for small changes spanning in several classes.

More info

Wikipedia

Refactoring Guru

NDpend Blog

Dzone

Credits

Photo by William Isted on Unsplash


Duplication is the primary enemy of a well-designed system.

Robert Martin


Code Smell 67 - Middle Man

Let's break Demeter's Law.

Problems

  • Unnecessary Indirection
  • Empty Classes
  • Readability

Solutions

  1. Remove Middle man.

Sample Code

Wrong

public class Client {
    Address address;
    public ZipCode zipCode() {
        return address.zipCode();
    }
}

public class Address {
    private ZipCode zipCode;
    
    public ZipCode zipCode() {
        return new ZipCode('CA90210');
    }
}

public class Application {   
   ZipCode zipCode = client.zipCode();
}

Right

public class Client {
    Address address;
    //client now has to expose its address
    public address() {
        return address;
    }
}

public class Address {
    private ZipCode zipCode;
    
    public ZipCode zipCode() {
        return new ZipCode('CA90210');
    }
}

public class Application {   
   ZipCode zipCode = client.address().zipCode();
}

Detection

Same as its opposite smell, We can detect this small using parsing trees.

Tags

  • Coupling
  • Declarative
  • Readability

Conclusion

This is exactly the opposite to Message Chain. We make explicit the message chain.

Relations

Code Smell 08 - Long Chains Of Collaborations

Code Smell 114 - Empty Class

More info

Refactoring Guru

Refactoring.com

C2 Wiki

JetBrains

Wikipedia

Credits

Photo by Dan Counsell on Unsplash


Whenever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent.

Martin Fowler


Code Smell 68 - Getters

Getting things is widespread and safe. But it is a very bad practice.

Problems

  • Naming
  • Information Hiding
  • Coupling
  • Encapsulation Violation
  • Mutability
  • Anemic Models

Solutions

  1. Avoid Getters
  2. Use domain names instead
  3. Protect your implementation decisions.

Sample Code

Wrong

<?php

final class Window {
    public $width;
    public $height;
    public $children;

    public function getWidth() {
        return $this->width;
    }

    public function getArea() {
        return $this->width * $this->height;
    }

    public function getChildren() {
        return $this->children;
    }
}

Right

<?php

final class Window {
    private $width;
    private $height;
    private $children;

    public function width() {
        return $this->width;
    }

    public function area() {
        return $this->height * $this->width;
    }

    public function addChildren($aChild) {
        //do not expose internal attributes
        return $this->children[] = $aChild;
    }
}

Detection

Getters coincide in certain scenarios with a true responsibility. It will be reasonable for a window to return its color and it may accidentally store it as color. so a color() method returning the attribute color might be a good solution.

getColor() breaks bijection since it is implementative and has no real counterpart on our mappers.

Most linters can warn us if they detect anemic models with getters and setters.

Tags

  • Information Hiding

Conclusion

Getters and Setters are a bad established practice. Instead of focusing on object behavior (essential), we are desperate to know object guts (accidental) and violate their implementation.

Relations

Code Smell 28 - Setters

Code Smell 01 - Anemic Models

Code Smell 64 - Inappropriate Intimacy

More info

Nude Models - Part II Getters

Credits

Photo by Vidar Nordli-Mathisen on Unsplash


The value of a prototype is in the education it gives you, not in the code itself.

Alan Cooper


Code Smell 69 - Big Bang (JavaScript Ridiculous Castings)

This handy operator is a trouble maker.

TL;DR: Don't mix booleans with non-booleans.

Problems

  • Not Declarative Code
  • Hard to debug
  • Magic Castings
  • Accidental Complexity

Solutions

  1. Be Explicit
  2. Don't mix Booleans with non-booleans.
  3. Fail Fast
  4. Be Smarter than your compiler.
  5. Stay loyal to the bijection.

The One and Only Software Design Principle

Sample Code

Wrong

!true // returns false
!false // returns true

isActive = true 
!isActive // returns false

age = 54
!age // returns false
array = []
!array // returns false
obj = new Object;
!obj // returns false

!!true // returns true
!!false // returns false

!!isActive // returns true
!!age // returns true
!!array // returns true
!!obj // returns true

Right

!true // returns false
!false // returns true

isActive = true 
!isActive // returns false

age = 54
!age // should return type mismatch (or 54 factorial!)
array = []
!array // should return type mismatch
obj = new Object;
!obj // should return type mismatch (what is an obejct negated in a real domain?)

!!true // returns true - it is idempotent
!!false // returns false - it is idempotent

!!isActive // returns true - it is idempotent
!!age // nonsense
!!array // nonsense
!!obj // nonsense

Detection

Since this is a "feature" in some languages it would be hard to test. We can set programming policies or choose more strict languages.

We should detect ! !! usages in non-boolean objects and warn our programmers.

Tags

  • Casting
  • Coercion
  • Javascript

Conclusion

Languages like JavaScript divide their whole universe into true or false values. This decision hides errors when dealing with non booleans.

We should be very strict and keep booleans (and their behavior), far away from non booleans.

Relations

Code Smell 24 - Boolean Coercions

Code Smell 06 - Too Clever Programmer

More info

Reddit

Bennadel.com

Mozilla

Credits

Photo by Greg Rakozy on Unsplash


It is easier to write an incorrect program than understand a correct one.

Alan J Perlis


Code Smell 70 - Anemic Model Generators

TL;DR: Do not create anemic objects. Much less with automatic tools.

Problems

  • Anemic Objects
  • Coupling to Implementation
  • Harder to Debug

Solutions

  1. Create your objects manually.
  2. Focus on essential behavior instead of accidental data storage.

Sample Code

Wrong

AnemicClassCreator::create(
    'Employee',
    [
        new AutoGeneratedField('id', '$validators->getIntegerValidator()'),
        new AutoGeneratedField('name', '$validators->getStringValidator()'),
        new AutoGeneratedField('currentlyWorking', '$validators->getBooleanValidator()')
    ]);

class Employee extends AutoGeneratedObjectEmployee {
}

//We have magic setters and getters
//getId() , setId(), getName()
//Validation is not implicit
//Class are loaded via an autoloader

$john = new Employee;
$john->setId(1);
$john->setName('John');
$john->setCurrentlyWorking(true);

$john->getName(); //returns 'John'

Right

final class Employee {
    private $name;
    private $workingStatus;

    public function __construct(string $name, WorkingStatus $workingStatus) {
        //..
    }

    public function name(): string {
        return $this->name;
        //This is not a getter. It is Employee's responsibility to tell us her/his name
    }
}

//We have no magic setters or getters
//all methods are real and can be debugged
//Validations are implicit

$john = new Employee('John', new HiredWorkingStatus());

$john->name(); //returns 'John'

Detection

Often, anemic models are generated with meta-programming.

We need to track these magic code generators.

Tags

  • Anemic

Conclusion

Code Wizards, Meta-programming, and anemic models are all code smells.

We need to avoid these dark techniques.

Having to write explicitly the code makes us reflect on every piece of data we encapsulate.

Relations

Code Smell 01 - Anemic Models

More info

Lazyness I - Metaprogramming

Lazyness II - Code Wizards

Credits

Photo by Lenny Kuhne on Unsplash


The best smells are something that's easy to spot and most of time lead you to really interesting problems. Data classes (classes with all data and no behavior) are good examples of this. You look at them and ask yourself what behavior should be in this class.

Martin Fowler


And that’s all for now…

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/02/24