Do you need help? Who are you gonna call?
TL;DR: Helpers don't help. They are a non-cohesive bunch of messy subroutines.
-
Readability
-
The Least surprise principle
-
Bijection Fault
-
Static methods
What exactly is a name - Part II Rehab
-
Find a suitable name
-
If the helper is a library, break all the services as different methods.
-
Methods should always be fulfilled by objects. Static methods are another code smell.
-
Avoid extracting the helpers to Anonymous Functions.
export default class UserHelpers {
static getFullName(user) {
return `${user.firstName} ${user.lastName}`;
}
static getCategory(userPoints) {
return userPoints > 70 ? 'A' : 'B';
}
}
// 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);
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);
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();
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);
- Code naming standards should forbid classes with this name on them.
- Namings
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.
Code Smell 18 - Static Functions
Code Smell 21 - Anonymous Functions Abusers
Code Smell 191 - Misplaced Responsibility
Code Smell 38 - Abstract Names
Code Smell 147 - Too Many Methods
- Utils
How to Decouple a Legacy System
This article is part of the CodeSmell Series.