Writing software is hard. There’re only a few ways to do it right and there’re many ways to do it wrong and make our lives hard.
In this article, we’ll look at some ways to write bad code by looking at a few codes smells.
Alternative Classes with Different Interfaces
2 classes that do the same thing but with different interfaces aren’t good because of duplication.
We don’t want to have that. Therefore, we may want to create a superclass with the shared code and then have subclasses that have differing methods.
Incomplete Library Class
Reuse isn’t overrated.
Library builders have a tough job. They may make incomplete classes but they don’t let us modify them to do what we want them to do.
Therefore, this makes the library class useless to us unless we can add the functionality that we want.
We may have to add new methods to these classes directly to solve this problem.
For instance, if we have a class that we imported, we can add own methods to it by writing:
const mixin = {
foo() {
//...
},
bar() {
//...
}
}
`
Object.assign(Foo.prototype, mixin);
In the code above, we merged the code from the Foo
class’s prototype with the methods from the mixin
object to incorporate more methods into the class with the Object.assign
method.
Data Class
Data classes are classes that only have fields.
These are classes that are probably manipulated in too much detail by other classes.
Therefore, we should encapsulate the public fields if they’re all exposed as public.
We can also encapsulate collection fields if necessary.
To encapsulate them, we can make the fields private and add methods to access and set them.
Refused Bequest
Subclasses inherit methods that parent classes give access to them.
If we don’t need those classes in the parent, then we can just push them down to the subclasses.
Then not all the subclasses will inherit the methods from the parent class while they can still stay in the subclasses that need to have them.
Comments
Comments are good for some things. We can comment on why we’re doing something, but we don’t need to explain how we’re doing something in the comments since we’re already doing it in the code.
Also commented code is bad. We should take them our since they aren’t run, to begin with.
Conditionals That Aren’t in Their Own Line
We should break conditionals into their own line so that we can read them easier.
So instead of writing:
if (foo) {
//...
} if (bar) {
//...
}
We write:
if (foo) {
//...
}
if (bar) {
//...
}
Annotate Optional Parameters
Optional parameters should have a default value in JavaScript. For instance, we can write the following code to indicate that a parameter is optional:
const foo = (a = 1) => {
//...
}
Watch out for “Dead Stores”
Dead stores are when we assign a value to a variable but it’s reassigned without using the original value.
Therefore, we never actually need the original value, so we can remove that line.
So instead of writing:
let x = 1;
x = 8 * 10;
We write:
let x = 8 * 10;
Don’t Invert Our Booleans
Double negatives are always harder to read than direct conditional expressions.
Therefore, we should write in a more direct way is possible. For instance instead of writing:
if (!(x > 10)) {
//...
}
We write:
if (x <= 10) {
//...
}
As we can see, the second if
statement is much easier to read than the first and it’s also shorter. And they’re both the same.
Use Templates Strings
Template strings are the best kind of JavaScript strings. We can interpolate expressions in it, which we can’t do with any other kind of strings.
Also, we can create multiline strings with it by just typing in the line breaks inside this string.
Since backticks are used as delimiters for template strings, quotations can be used inside strings without escaping them.
Conclusion
Template strings are great. They let us do many more things that we can’t do with old-style strings.
To add more methods to incomplete library classes, we can use Object.assign
to add our own methods to them.
Also, we need to encapsulate data classes so that our code isn’t too tightly coupled with data classes.