DEV Community

Cover image for Code Smell 22 - Helpers
Maxi Contieri
Maxi Contieri

Posted on • Edited on • Originally published at maximilianocontieri.com

2 2

Code Smell 22 - Helpers

Do you need help? Who are you gonna call?

TL;DR: Helpers don't help. They are a non cohesive bunch of messy subrutines.

Problems

  • Readability

  • The Least surprise principle

  • Bijection Fault

  • Static methods

Solutions

  1. Find a suitable name

  2. If the helper is a library, break all the services as different methods.

  3. Methods should always be fulfilled by objects. Static methods are another code smell.

  4. Avoid extracting the helpers to Anonymous Functions.

Sample Code

Wrong

export default class UserHelpers {
  static getFullName(user) {
    return `${user.firstName} ${user.lastName}`;
  }

  static getCategory(userPoints) {
    return userPoints > 70 ? 'A' : 'B';
  }
}
Enter fullscreen mode Exit fullscreen mode

Notice static methods.

import UserHelpers from './UserHelpers';

const alice = {
  firstName: 'Alice',
  lastName: 'Gray',
  points: 78,
};

const fullName = UserHelpers.getFullName(alice);
const category = UserHelpers.getCategory(alice);
Enter fullscreen mode Exit fullscreen mode

Right

class UserScore {  
  //This is anemic class and should have better protocol

  constructor(name, lastname, points) {
    this._name = name;
    this._lastname = lastname;
    this._points = points;
  }
  name(){
    return this._name;
  }
  lastname(){
    return this._lastname;
  }
  points(){
    return this._points;
  }
}

class FullNameFormatter {
  constructor(userscore) { 
    this._userscore = userscore;

 }
  fullname() {
    return `${this._userscore.name()} ${this._userscore.lastname()}`;
  }
}

class CategoryCalculator{
  constructor(userscore1){ 
     this._userscore = userscore1;
 }
  display() {
    return this._userscore.points() > 70 ? 'A' : 'B';
  }
}


let alice = new UserScore('Alice', 'Gray', 78);

const fullName = new FullNameFormatter(alice).fullname();
const category = new CategoryCalculator(alice).display();
Enter fullscreen mode Exit fullscreen mode

or we can make the former Helper stateless for reuse...

class UserScore {  
  //This is anemic class and should have better protocol

  constructor(name, lastname, points) {
    this._name = name;
    this._lastname = lastname;
    this._points = points;
  }
  name(){
    return this._name;
  }
  lastname(){
    return this._lastname;
  }
  points(){
    return this._points;
  }
}

class FullNameFormatter {      
  fullname(userscore) {
    return `${userscore.name()} ${userscore.lastname()}`;
  }
}

class CategoryCalculator{
  display(userscore) {
    return userscore.points() > 70 ? 'A' : 'B';
  }
}  

let alice = new UserScore('Alice', 'Gray', 78);

const fullName = new FullNameFormatter().fullname(alice);
const category = new CategoryCalculator().display(alice);
Enter fullscreen mode Exit fullscreen mode

Detection

  • Code naming standards should forbid classes with this name on them.

Tags

  • Namings

Conclusion

This is a well established cultural name and a legacy habit from structured programming.

Most developers are reluctant to let old habits go.

We must be aware of the damage this kind of names are bringing us.

Relations

Also known as

  • Utils

More Info


This article is part of the CodeSmell Series.

Last update: 2021/07/04

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (4)

Collapse
 
alainvanhout profile image
Alain Van Hout

You're showing us 'good' code and 'bad' code, but you're not actually explaining why the one is better than the other or what advantages or disadvantages the two alternatives have. In all, it seems that you've simply rewritten two short functions as multiple longer classes.

Collapse
 
mcsee profile image
Maxi Contieri • Edited

hi Alain.

Besides rewrite them (most refactorings are about rewrites) solution is less coupled, has a real world name, is more readable and has no static methods.
Length is not a big issue when declarativeness is a trade off.
For me, its is more intention revealing a formatter that formats than a helper that.... hmm helps?

Collapse
 
alainvanhout profile image
Alain Van Hout

That does add more detail, thanks. I personally don't see it as less coupled (use a class vs use a function). As to better names, that's a fact but it would work as well if the functions were renames to e.g. formatToFullName and determineCategory (or something better based on the domain). Static or not seems mostly irrelevant to me, since it doesn't really affect transparency (while I would say that the class boilerplate does reduce transparency).

But a class version of the methods of course also works, so to a degree it's a matter of taste I suppose.

Thread Thread
 
mcsee profile image
Maxi Contieri

indeed. it has some taste on it.

According to SOLID principles Class single responsibility is to create instances. Not to be overloaded with static functions. But it is just an opinion.
As long as we don't call them Helpers I think we are in a better position.

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay