Learn

Home

Image represents a media kit with boilerplate, logos and more

Guide

code smells: developer's guide

Code smells are warning signs in your code that hint at deeper issues. These aren't errors and the code will still work, but they can make future development harder and increase the risk of bugs.

Table of Contents

  • What is a code smell?
  • What are examples of code smells?
  • Why are code smells important?
  • What are ways to address code smells?
  • Sonar and code smells

What is a code smell?

Code smells are defined as categories of issues in code that may lead to deeper problems over time. They are similar to warning indicators that arise due to potential bad coding practices. 


While code smells are not errors or bugs per se and do not affect the functionality of the software, they indicate weaknesses in design that can slow down development or increase the risk of bugs or failures down the line.


Some common examples of code smells include issues such as large classes and long methods – i.e. one function, trying to do too much, or methods that are long to understand. 


Another example is duplicated code – where the same piece of code is repeated in multiple places. 


Issues like these can lead to clunky code, increase the cognitive complexity of the codebase, and contribute toward maintainability issues and increased technical debt in software. 

What are examples of code smells?

The below code in Python has a cognitive complexity score of 8 because of how the functions are nested. Although this code functions just fine,  it adds unneeded complexity to the writer, reviewer, and future developer if left unfixed. 


def process_user(user):

    if user.is_active():             # +1 (if)

        if user.has_profile():       # +1 (if) +1 (nested)

            ... # process active user with profile

        else:                        # +1 (else)

            ... # process active user without profile

    else:                            # +1 (else)

        if user.has_profile():       # +1 (if) +1 (nested)

            ... # process inactive user with profile

        else:                        # +1 (else)

            ... # process inactive user without profile

Why are code smells important?

Code smells are crucial indicators to the state of software because they are early warning signs of possible issues that could arise in the codebase. They are important because they can identify places where the code may be vulnerable to problems in the future even though it is working properly now. 


Developers can prevent fundamental design flaws, maintainability issues, and scalability issues before they become more serious issues by catching code smells. 


Detection of code smells can seem intrusive and noisy at development time, but they encourage developers to follow recommended coding standards and best practices, which helps to create a high-quality code culture inside development teams. 


They serve as guiding concepts for developers working on refactoring projects, pointing them in the direction of cleaner, more modular, and maintainable code. 


Along with this, code smells are instructional tools that aid developers in developing a deeper comprehension of software design patterns and ideas.


Developers can refine their abilities, develop an awareness of and appreciation for code quality, and add to the continuous enhancement of the codebase by identifying and fixing code smells. 


By giving developers a shared language to discuss and manage code quality issues, code smells promote cooperation and communication.

 

By consistently detecting and fixing code smells, software projects can reduce technical debt, increase long-term maintainability, and raise overall software quality.

What are ways to address code smells?

Fixing code smells requires a systematic plan that centers on finding the source of the smell and using the right refactoring techniques to address it. Code smells should first be prioritized by developers according to the effect that they have on the codebase and the possible rewards of correcting them.


The code snippet above contributed to code smells because they were unnecessarily complex and contained too many lines of code. 


Issues that can contribute to cognitive complexity or simply put as "brain overload" can lead to developers spending more time reading and understanding code than writing it. 


High cognitive complexity slows down changes and increases the cost of maintenance.


Refactoring the code into smaller functions allows the complexity to spread over multiple functions and the breaks in the flow are no longer nested. 


def process_user(user):

    if user.is_active():             # +1 (if)

        process_active_user(user)

    else:                            # +1 (else)

        process_inactive_user(user)

def process_active_user(user):

    if user.has_profile():           # +1 (if) +1 (nested)

        ... # process active user with profile

    else:                            # +1 (else)

        ... # process active user without profile

def process_inactive_user(user):

    if user.has_profile():           # +1 (if) +1 (nested)

        ... # process inactive user with profile

    else:                            # +1 (else)

        ... # process inactive user without profile



Another example of a common code smell is when a builtin is used as the name of a variable. Although this may not be encountered by a senior developer, this is not a good coding practice as the builtin won’t be accessible through its original name if used this way. 

 def a_function():

    int = 42


The proper way to fix this is to use a proper variable:


def a_function():

    value = 42


Another example from above is files having too many lines of code.


When a source file grows too much, it can accumulate numerous responsibilities and become challenging to understand and maintain. 


To make code more maintainable, files above a specific threshold should be refactored into smaller files whose code focuses on well-defined tasks. 


Those smaller files will be easier to understand and test.


There are thousands of such issues that can lead to code smells and addressing them early promotes good coding practices.  


As soon as code smells have been located, developers can use a variety of refactoring strategies to get rid of them without changing the code's outward behavior. 


Developers can divide lengthy, complicated procedures that result in code smells into smaller, easier-to-manage methods that each handle a specific task.

Code smells and refactoring

Refactoring, which is the process of restructuring code without changing its exterior behavior, is usually used to address code smells with the goal of enhancing readability, modularity, and overall code quality. 


The refactoring process includes strict trade-off analysis because implementing changes hastily can result in unexpected effects or new problems. 


As a result, eliminating code smells calls for a well-rounded strategy that incorporates technical know-how with an understanding of the goals and limitations of the project. 


In the end, software teams may promote a culture of continuous improvement by proactively detecting and fixing code smells, guaranteeing that their codebase 


Is maintainable, reliable, and secure to long-term changes. 


Refactoring must be accompanied by comprehensive testing to guarantee that no defects or regressions are introduced. 


In order to preserve codebase readability and facilitate future maintenance efforts, developers should also include the rationale behind each refactoring step in their documentation. 


Team knowledge sharing and validation of refactoring decisions can be facilitated by code reviews and pair programming.


Sonar and code smells

SonarQube and SonarCloud can help developers identify and prevent code smells along with a variety of other issues (bugs and security vulnerabilities, etc.). 


Both natively integrate into your CI/CD pipelines to find and fix issues early in the development phase before they create difficulties in production. 


SonarLint, a companion tool to SonarQube and SonarCloud, is an IDE plugin that provides real-time feedback within the developer's editor, highlighting code issues (including code smells) as developers write code.