16 deadly code smells — Part 1

Code smells that are considered fatal during coding interviews

I will not write any more bad code
I will not write any more bad code

Every programming language has one or more coding style guidelines. All developers know that but some of them don’t care. They practice bad programming habits for years without realizing the importance of the issues they caused.

As one of the hiring managers at Zuhlke Hong Kong, I’ve seen a lot of code smells during coding interviews. Here are the top 16 bad coding practices organized into 6 categories: coding style, dirty code, testing, error handling, code complexity, and optimization.

The first 8 code smells are covered in Part 1 and the rest in Part 2.

Coding styles

Ignoring the importance of coding styles usually indicates the lack of experience in creating software and reading other people’s code. It’s hard for inexperienced developers to understand the benefits of using a consistent coding style.

1. Inconsistent coding style

Consistency is one of the most dominant attitudes that good developers have. Being consistent is a result of logical thinking, which is a core element in software development. Every action that a developer chooses to take is because of some reasoning that the developer believes that it is true. Given the same environment, with the same input, we expect the same output. This is the same for coding style.

Let’s compare the following snippets. Only one of them I consider as consistent.

Snippet 1:

if(document.ownerId == user.id) {
doSomething();
}

Snippet 2:

if (document.ownerId == user.id){
doSomething();
}

Snippet 3:

if (document.ownerId == user.id) {
doSomething();
}

Snippet 4:

if(document.ownerId== user.id) {
doSomething();
}

Snippet 5:

if(document.ownerId==user.id){
doSomething();
}

Answer: Snippet 3

Compilers ignore most of the spaces we used in our code, so what are they for? Readability.

If you use a space between ) and { for better readability, then why wouldn’t you also use a space between if and ( as illustrated in snippet 1?

2. Inconsistent naming

Finding good names is not easy. It usually takes me a considerable amount of time. It’s part of the process to create good software. Some people don’t agree and they name their variables or methods like this:

let value = 1;
let curValue = 0;
let previousVal = -1;

“Current” is represented in its short form in curValue, but this is not the case for “previous”. Instead, “value” is shorten as val in previousVal. The flow of the mind of these people is so random that no one can explain the logic behind such naming style.

Dirty code

This is the exact opposite of clean code. When you see dirty code, you can feel its ugliness and want to look away immediately. You feel so uncomfortable that it makes you hard to breath. It stinks and lingers for at least an hour.

3. Duplicate code

Duplicated code almost always indicates a failure in software design. So why does duplication ever exist? Some reasons I’ve heard from coding interviews are:

  • They think they have no choice but the problem to be solved requires duplication
  • They believe the easiest way to solve a certain problem is by duplication
  • Some don’t even realize there is duplication

All of the above are the result of incompetence in software design.

4. Bad naming

Self-explanatory names

Who needs comments when names are self-explanatory and logic is clear?

Examples of bad names I saw in coding interviews:

  • retVal: I cannot find an even less meaningful name for this. All values returned by functions are called return-value. So what is this particular retVal referring to?
  • tmp: Almost every variables within a function scope is short-lived and temporary. So how temporary should one consider it as temporary? Even a temporary variable deserves a more meaningful name.
  • Hungarian notation: Variable or function prefixing to indicate and check for types is no longer needed for all modern IDEs. Type prefixing makes it harder to change type and could lead to type inconsistency. It also reduces readability.

5. Dead code

There are two kinds of dead code:

  • Unreachable code: Code that within a condition that can’t happen
  • Commented code: Code that you are afraid to throw away

Unreachable code is less frequently seen during coding interviews because the problem to be solved isn’t that complicated.

One the other hand, commented code is a bigger issue that usually indicates a lack of understanding of source control.

If you ever want to comment code and think that you may need it at a later time, a better alternative is to use Git. For some IDEs, such as those made by IntelliJ, they provide local source control by default and the full history of your code is committed locally automatically. No one ever needs to comment any code.

Testing

Where are the tests?

Every piece of sufficiently complicated code needs proper tests. Some people test manually, some test their code by logging, and good engineers write unit tests.

6. No tests

More than half of the candidates I’ve met in coding interviews didn’t write any unit tests. Some refused to write unit tests even after they are requested to do so. One simply cannot be sure their code works without any tests. Even if their code appears to work, there is no way to be sure it still works after refactoring.

7. No meaningful tests

Writing unit tests is the first step to become better engineers. The next step is to write meaningful tests. Having tests that cover every single possible outcome is not meaningful and wastes time. Having tests that cover a few random cases is not any wiser.

Good tests should cover a few cases of happy paths and all edge cases. The ability to design good tests is one of the assessments for our technical interviews.

8. Console logging

It is also called Caveman debugging. It is a popular debugging technique decades ago and is the preferred way of debugging in extreme situation such as kernel programming where you don’t have any better alternatives.

Those candidates who print intermediate values to console would argue that console logging is an easier and faster way to debug. It is almost certain that they didn’t know how to write unit tests and it would take longer time to complete the coding test during technical interviews.

Writing unit tests is as easy as printing to console, if not easier, once you learned how to do it. Additionally, unit tests are needed for refactoring in which console logging is often removed because it reduces code readability.

If someone would consider printing anything to console, that means there exists some code that is hard to understand. This is the case when unit tests are exactly for.

Continue with numbers 9 to 16 code smells in Part 2.

Continuously innovates and creates extraordinary impacts on digital businesses through technology excellence | https://www.linkedin.com/in/ayltai/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Take every opportunity to improve legacy code

5 Learnings from the #wirvsvirushack from a developer perspective

Let’s Become a Cloud Security Engineer #2: Web Hosting Basics

New Features in Python 3.10

Making most out of your CI pipeline: Hassle-free and efficient code quality analysis and…

How to Deploy a SpringBoot App to AWS Elastic Beanstalk

The Clean Coder | Book Report

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alan Tai

Alan Tai

Continuously innovates and creates extraordinary impacts on digital businesses through technology excellence | https://www.linkedin.com/in/ayltai/

More from Medium

With Programmers: Week nth

What do managers look for when they hire software engineers?

What to Look for When Hiring a Java Developer

I’m a Software Engineer. What now?