💃 Code Smells in Apex🕺

How to Sniff Out and Refactor Bad Code

Good morning, Salesforce Nerds! If code could emit an odor, what would Apex smell like?

Hopefully, it’s a fresh, clean pine forest, but let’s face it: sometimes, a little whiff of rot sneaks in. 🦨 

This, my friend, is a “code smell” - that hint that something’s wrong, even if everything seems to work.

In the world of Apex, code smells are the subtle (or not-so-subtle) signs that your code is on a fast track to becoming hard to read, slow to run, and even harder to maintain. 😮‍💨 

But don’t worry! Today, we’ll air out the room and turn that pungent code into a breath of fresh, well-structured logic. 💯 

TABLE OF CONTENTS

WHAT ARE WE EVEN TALKING ABOUT?

What Exactly Is a Code Smell?

Just as an unpleasant smell can warn us of a deeper problem, code smells indicate trouble lurking in your codebase. 😟 

They don’t necessarily break the code, but they suggest something is structurally off, leading to complications, bugs, and maintenance headaches down the line.

Apex, with its governor limits and unique quirks, is especially prone to a few classic smells, but luckily, they’re easy to fix once you know what to look for. 👍️ 

Let’s roll up our sleeves and sniff out the most common code smells in Apex.

With each whiff, I’ll show you not only what’s causing the odor but also how to clean it up.

THE MEAT AND POTATOES

Top Code Smells to Watch Out For (And How to Fix Them!)

1. SOQL Queries in Loops: The Governor Limit Crusher

The Smell: You’ve put a SOQL query inside a for loop. 🫢 

Why It Stinks: SOQL queries inside loops are a one-way ticket to “Too many SOQL queries” errors. In Salesforce, governor limits will stop you from running too many queries in a single transaction, and this smell is a top offender.

The Fix: Refactor the query outside the loop. Instead of querying one record at a time, use a single query to grab everything you need upfront, and use a Map to organize the data for quick reference.

// Smelly Code
for (Account acc : [SELECT Id FROM Account]) {
    // Nested query
    Contact con = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
    // Process contact here
}

// Refactored Code
Map<Id, Contact> contactMap = new Map<Id, Contact>([SELECT Id, AccountId FROM Contact]);
for (Account acc : [SELECT Id FROM Account]) {
    Contact con = contactMap.get(acc.Id);
    // Process contact here
}

2. Hard-Coded IDs: The Reusability Killer

The Smell: Hard-coded record IDs in your Apex classes, like magic numbers for Salesforce. 🪄 

Why It Stinks: Hard-coded IDs tie your code to a single org, making it impossible to deploy across sandboxes and environments without modification.

The Fix: Use Custom Metadata Types, Custom Settings, or dynamic SOQL queries to fetch those IDs based on criteria instead.

// Smelly Code
Id accountRecordTypeId = '0123g000000LnjK';

// Refactored Code
Id accountRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Business Account').getRecordTypeId();

3. Excessive If-Else Chains: The Maintainability Nightmare

The Smell: Long, sprawling chains of if-else statements. You know you’ve seen them. 🚫 

Why It Stinks: Long conditional chains make code cumbersome to read and maintain. Adding another branch just makes the whole structure uglier.

The Fix: Use a strategy pattern or polymorphism when you find yourself with these monsters. You can also store values in Custom Metadata to help centralize business logic that changes often.

4. Duplicate Code: The Anti-DRY Offender

The Smell: Identical code chunks scattered across your classes. Copy-paste, copy-paste …

Why It Stinks: Duplicating code means making multiple changes whenever there’s an update, and it raises the chances of inconsistent logic. 😡 

The Fix: Centralize repeated code in utility methods or helper classes, following the “Don’t Repeat Yourself” (DRY) principle. 🔥 

// Smelly Code in two places
if (opportunity.StageName == 'Closed Won') {
    // some processing
}

// Refactored Code
public class OpportunityHelper {
    public static Boolean isClosedWon(Opportunity opp) {
        return opp.StageName == 'Closed Won';
    }
}

5. Unoptimized Bulk Operations: The Time Bomb

The Smell: Code that doesn’t take bulk operations into account. 😵‍💫 

Why It Stinks: Salesforce processes data in bulk, and if your code only works for single records, it won’t scale and could break in production.

The Fix: Always assume your code will handle multiple records, even if it’s called for just one. This means using collections, avoiding single DML statements in loops, and ensuring you’re “bulkifying” your operations. 🫡 

6. Verbose Code with Long Methods: The Clarity Slayer

The Smell: Long, sprawling methods that try to do everything at once.

Why It Stinks: Large methods are hard to read, maintain, and debug. They also often mix multiple responsibilities, which makes the logic confusing. 👎️ 

The Fix: Apply the “single responsibility principle” by breaking down your methods. Each method should handle one specific task. This modular approach makes code easy to follow and test.  

7. Lack of Test Coverage for Edge Cases: The Testing Oversight

The Smell: Code coverage requirements are technically met, but your test methods barely cover edge cases or governor limits. 🤯 

Why It Stinks: Weak tests mean your code could blow up in production due to untested scenarios, particularly with high data volumes.

The Fix: Write tests that simulate bulk data, enforce governor limits, and explore edge cases. This builds confidence in the code’s scalability and reliability.  

HELP GETTING STARTED

Tools to Help You Detect Code Smells

While we all have an inner detective, sometimes it helps to have backup. Here are some tools to sniff out and squash code smells before they make it to production: 🛠️ 

  • PMD for Apex: A popular static code analysis tool that flags potential problems, like SOQL inside loops.

  • Salesforce CLI and Plugins: Check out the SFDX Scanner plugin for automated rule-based analysis.

  • CodeScan: An Apex-focused code quality tool with rules for detecting code smells and ensuring coding standards.

DON’T SLEEP ON THIS

The Cost of Ignoring Code Smells

If left unattended, code smells build up like plaque, creating technical debt that’s costly and painful to remove. 🤑 

They reduce scalability, increase bugs, and can make future features a headache to implement.

Preventing these smells isn’t just about pristine code; it’s about safeguarding the stability and maintainability of your org. 💯 

WRAPPING IT UP

Conclusion

Code smells are warning signs that help us write better, stronger code. 💪 

By keeping your nose attuned to these smells, you’ll be a more effective, efficient developer, and your org will thank you!

Clean up that code now, and it’ll pay dividends in the future - a scent of success that’s truly refreshing. 🧹 

SOUL FOOD

Today’s Principle

“I’m not a great programmer; I’m just a good programmer with great habits.”

Martin Fowler

and now....Salesforce Memes

What did you think about today's newsletter?

Login or Subscribe to participate in polls.