Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 48

Understanding and Identifying Code Smells

Recommended resources

Hello! Over the past few lessons, we've focused on the principles of good design: SOLID and Composition over Inheritance. These are the tools you use to build clean, maintainable, and flexible software. Today, we'll flip the coin and learn to recognize the symptoms of poor design.

This lesson is about defining and identifying code smells. A code smell isn't a bugโ€”the code might work perfectlyโ€”but it's a surface-level indicator of a deeper structural problem. Learning to spot these smells is a critical step toward developing the "architectural mindset" you're aiming for, as it trains you to look beyond functionality and evaluate the long-term health of a codebase.

Your goal for this lesson is to be able to define 'code smells' and identify common examples like Long Method and Large Class.

1. What Exactly is a "Code Smell"?

The term "code smell" was popularized by Kent Beck and Martin Fowler. It's a powerful metaphor: just like a strange smell in the kitchen might signal that food is going bad, a code smell signals that something in your design might be rotting.

To get a clear definition, let's start with a short video that explains the concept and distinguishes it from bugs.

What is Code Smell?

This video from the Telusko channel provides a great introduction to what code smells are and why they matter for code maintainability, even when the application works as expected.

Watch from the beginning to 03:10. Focus on the distinction between a bug (the code is broken) and a smell (the code works but is poorly structured).

As the video explains, code smells are about readability, maintainability, and the ease of future change. Another excellent, concise way to think about it is that a smell is an indicator that you should investigate further.

A few common code smells to be aware of and how to fix them

This short clip from The Shaggy Dev offers a perfect summary.

Watch the first 23 seconds. The key takeaway is that a smell 'may be indicative of a larger problem' and warrants evaluation.

In summary, a code smell is a hint that a software design principleโ€”like SRP, DRY, or Open/Closedโ€”has likely been violated. It's the symptom, not the disease itself.


2. A Catalog of Common Smells

There are dozens of documented code smells. We'll focus on a few of the most common and impactful ones, especially those that directly relate to the principles we've already studied. Many of these smells fall into a category called Bloaters, where code, methods, and classes have grown so large they become difficult to manage.

The following article is a fantastic, practical guide to several key smells. We will refer to it throughout this section.

Detecting Code Smells: Your First Step Toward Refactoring ...

The article 'Detecting Code Smells' by Mathieu Perroud provides clear definitions and, importantly, code examples that show the smell and a hint of the fix. We will use it as a reference for the smells we discuss.

First, read the introduction of the article, down to the start of the '1. Long Methods' section. It provides excellent context on the link between code smells and design principles.

Now, let's dive into the specific smells.

Smell 1: Long Method

This is one of the most common smells. As a developer, you've likely written or encountered methods that scroll on for pages.

  • Symptom: A function or method that is excessively long. A common rule of thumb is that anything over 10-15 lines should be looked at with suspicion.
  • Problem: Long methods almost always do more than one thing, which is a direct violation of the Single Responsibility Principle (SRP). They are hard to understand, difficult to name accurately, and nearly impossible to reuse or test in isolation.

Detecting Code Smells: Your First Step Toward Refactoring ...

Let's return to the article to see a concrete example.

Read section '1. Long Methods'. Pay attention to how the 'before' code is hard to follow, while the 'after' code, broken into smaller methods, reads almost like a summary of the logic. The fix for this is a refactoring technique called 'Extract Method', which we'll cover in the next lesson.

Selected Code Smell Definitions and Examples
This image visually represents four common code smells. The 'Long Method' is aptly depicted as a long, unrolled scroll, symbolizing a piece of code that has become unwieldy and hard to read at a glance.

Smell 2: Large Class (The "God Object")

The Large Class is the big brother of the Long Method. It's a class that has accumulated too many responsibilities over time.

  • Symptom: A class with a vast number of methods, instance variables, and thousands of lines of code. It often tries to control many other objects and may be central to the entire application.
  • Problem: This is a major violation of the SRP. The class is tightly coupled to many other parts of the system, making it fragile and extremely difficult to change. Testing a God Object is a nightmare because of its many dependencies and states.

A few common code smells to be aware of and how to fix them

The 'God Object' smell often doesn't appear overnight. It grows incrementally. This video gives a perfect narrative of how a simple global object can slowly evolve into an unmanageable mess.

Watch from 02:40 to 04:27. Notice how each 'small, reasonable' addition contributes to creating a class with no single purpose, making the system's state hard to reason about.

The solution to a Large Class is to apply SRP and split its responsibilities into smaller, more cohesive classes, often using principles like Dependency Injection, which we covered earlier.

Smell 3: Duplicate Code

This is another classic smell that directly violates a core principle you've seen before.

  • Symptom: You see the exact same block of code, or a very similar one, in multiple places throughout your codebase.
  • Problem: This violates the Don't Repeat Yourself (DRY) principle. If you need to fix a bug or change the logic in that code block, you have to remember to find and update every single copy. Missing one can lead to subtle and frustrating bugs.

Detecting Code Smells: Your First Step Toward Refactoring ...

Let's look at the 'Duplicated Code' section in our reference article.

Read section '2. Duplicated Code'. The example of calculating totals for a Cart and an Invoice is a very realistic scenario. The fix demonstrates creating a single source of truth for the shared logic.

Smell 4: Long Parameter List

This smell makes your methods feel like you're filling out a complicated form every time you call them.

  • Symptom: A method that takes a large number of parameters (e.g., more than three or four). Often, you'll see a subset of these parameters being passed around together in different method calls. This related group is sometimes called a Data Clump.
  • Problem: Long parameter lists are hard to read and use. It's easy to make mistakes by passing arguments in the wrong order. More importantly, it often indicates that the parameters have a conceptual relationship that isn't being properly modeled.

Detecting Code Smells: Your First Step Toward Refactoring ...

The article's final section provides a great solution to this problem.

Read section '4. Long Parameter Lists'. The fix here, 'Introduce Parameter Object', is a key refactoring technique. It involves creating a new class (like UserProfile) to encapsulate the related data, which makes the code cleaner and creates a new, meaningful concept in your domain.

The image below gives a high-level overview of some of the smells we've discussed and others you may encounter.

Common Code Smells in Software Development
This diagram illustrates eight common code smells, including 'Long Methods', 'Large Classes', and 'Duplicate Code', which we've just covered. It also introduces others like 'Shotgun Surgery' (one change requires many small edits everywhere) and 'Feature Envy' (a method is more interested in another class's data than its own), which are also signs of poor design.
Test your understanding!

You are reviewing the following C#-like pseudocode for an e-commerce application.

public class OrderManager 
{
    public void ProcessOrder(int orderId, string customerName, string customerEmail, string shippingAddress, string billingAddress, List<Product> items, string promoCode)
    {
        // 1. Validate customer data
        if (string.IsNullOrEmpty(customerName) || !customerEmail.Contains("@")) 
        {
            Console.WriteLine("Error: Invalid customer data.");
            return;
        }

        // 2. Calculate subtotal
        double subtotal = 0;
        foreach (var item in items)
        {
            subtotal += item.Price * item.Quantity;
        }

        // 3. Apply discount
        double discount = 0;
        if (promoCode == "SAVE10")
        {
            discount = subtotal * 0.10;
        } 
        else if (promoCode == "SAVE20")
        {
            discount = subtotal * 0.20;
        }
        double finalTotal = subtotal - discount;

        // 4. Save to database
        Console.WriteLine($"Saving order {orderId} with total {finalTotal} to DB.");
        
        // 5. Send confirmation email
        string emailBody = $"Dear {customerName}, your order total is {finalTotal}.";
        Console.WriteLine($"Sending email to {customerEmail}: {emailBody}");

        // 6. Check for large orders and send separate notification
        if (finalTotal > 1000)
        {
            string notificationBody = $"A large order of {finalTotal} was placed by {customerName}.";
            Console.WriteLine($"Sending notification: {notificationBody}");
        }
    }
}

Identify at least three distinct code smells in this ProcessOrder method and name them.

Show answer

Here are the most prominent code smells in the snippet:

  1. Long Method: The ProcessOrder method is doing far too many things: validating data, calculating totals, applying discounts, saving to the database, and sending multiple notifications. This is a clear violation of the Single Responsibility Principle.

  2. Long Parameter List: The method signature ProcessOrder(int orderId, string customerName, ...) has seven parameters. This makes it hard to call and indicates that some of this data should be grouped.

  3. Data Clump: The parameters customerName, customerEmail, shippingAddress, and billingAddress are a classic Data Clump. They belong together in a Customer or CustomerInfo object.

  4. (Bonus) Primitive Obsession: The code uses primitive types like string for everything (e.g., promoCode, customerEmail). A PromoCode could be its own class, and an Email type could contain its own validation logic, rather than checking for "@" inside this method.


Conclusion

In this lesson, we've defined what code smells are and learned to identify some of the most common ones. You now have the vocabulary to describe why a piece of code "feels wrong" even if it works correctly. This is the first and most crucial step in improving code quality.

Key Takeaways:

  • Code smells are symptoms, not bugs. They indicate deeper design problems that can make code hard to maintain, understand, and change.
  • Long Methods and Large Classes often violate the Single Responsibility Principle (SRP). They do too much and should be broken down into smaller, more focused units.
  • Duplicate Code violates the Don't Repeat Yourself (DRY) principle and creates a maintenance nightmare. Logic should exist in a single source of truth.
  • Long Parameter Lists and Data Clumps suggest that data is not being properly structured into meaningful objects.

Preview of the Next Lesson:
Identifying a smell is only half the battle. What do you do once you've found one? In our next lesson, "Apply foundational refactoring techniques (e.g., Extract Method) to improve code quality," we will learn the specific, step-by-step techniques to fix these smells and transform messy code into a clean, well-structured design.