💃 Design Patterns for Salesforce🕺

Codebase strategies you need to consider

Good morning, Salesforce Nerds! I love a good design pattern. 😍 

Reusable software components?

I’m in! 🤙

Today I wanted to dive a little deeper into a design pattern with lots of use cases that can also add a lot of flexibility to your org.

This is one I think every dev out there should not only be aware of, but have in their toolkit on the ready! 🫡 

Read on for more about the Strategy Pattern.

TABLE OF CONTENTS

What’s are these again?

Design Patterns

Design patterns are solutions to software engineering problems found over & over in the wild. 🤠 

Think of them as customizable blueprints available to you when you encounter one of these problems out there.

And if you’re on the developer path - you will at some point. 💯 

Trust me.

We’ve written a high-level overview of these in the past, but didn’t get too in depth. 🤿 

Let’s change that …

Time to get strategic

Strategy Pattern

Kicking it off with one of my fav’s (and most used)!

First, the official definition: 🫡 

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Gang of Four (GoF)

This type of design pattern falls under Behavioral Patterns.

In practical terms, this is what you need to know about Strategy: 👇️ 

  • Specifies a set of classes, each representing a different behavior.

  • Switching between those classes changes the behavior of the application (aka the Strategy).

  • This behavior can be selected at runtime using polymorphism or design time.

  • Capture the abstraction in an interface, bury implementation details in implementing classes.

  • An alternative to the Strategy pattern is to change the application behavior by using conditional logic. This is BAD! 🚫 

  • Using this pattern makes it easier to add, modify, or remove specific behavior, without having to recode and retest, all or parts of the application.

Let’s see an example

Simple Problem

So, the Strategy pattern is all about executing different logic depending on some condition. 🔀 

So, let’s take a simple example.

Imagine you’re building an app that will perform a simple mathematical operation against two numbers. 🧑‍🏫 

Easy, right?

You have a small form with two input boxes and a picklist that allows the user to choose the operation.

The picklist contains three options:

addition

subtraction

✖️ multiplication

When the user enters two numbers, chooses an operation and clicks a button - you do the math for them. 💥 

How would you structure this code? 🤔 

Perhaps because it’s just three basic math operations, it’s safe to create a single method with either an if/then or switch statement that checks the operation and executes the code?

Something like this: 👇️ 

public integer doOperation(integer number1, integer number2, string operation) {
    switch on operation {
        when '+' {
            return number1 + number2;
        }
        when '-' {
            return number1 - number2;
        }
        when '*' {
            return number1 * number2;
        }
    }
}

This may seem tempting … but, in the real world, we all know how fast things can change.

How can we craft code that will elegantly handle these changes? 📐 

This is where the Strategy Pattern shines!

Show me the code!

The Solution

Let’s check out how to structure this code so it scales in just three steps! 🔥 

Step 1 - Create an interface defining a method.

public interface IMathStrategy {
    integer doOperation(integer number1, integer number2);
}

Step 2 - Create concrete classes that implement this 👆️ interface and add their specific logic.

public class OperationAdd implements IMathStrategy {
    public integer doOperation(integer number1, integer number2) {
        return number1 + number2;
    }
}

public class OperationSubtract implements IMathStrategy {
    public integer doOperation(integer number1, integer number2) {
        return number1 - number2;
    }
}

public class OperationMultiply implements IMathStrategy {
    public integer doOperation(integer number1, integer number2) {
        return number1 * number2;
    }
}

Step 3 - Create a context class that accepts the interface as constructor parameter along with a method to execute the operation.

public class MathOperation {
    private IMathStrategy strategy;

    public MathOperation(IMathStrategy strategy) {
        this.strategy = strategy;
    }

    public integer executeStrategy(integer number1, integer number2) {
        return strategy.doOperation(number1, number2);
    }
}

Wrapping it up

Takeaway

That’s really it. 🤷 

Now, any new logic you need to add you just add a new concretion of the IMathStrategy interface & you’re good to go!

Need to handle division? No problem. 💥 

All the client needs to be able to do is choose which concretion to execute.

This is where the concept of Dependency Injection (DI) can REALLY take you to the next level! 🚀 

More on this topic in another post. 😊 

For now, let’s check out how a client can use the code we’ve already written!

public class StrategyClient {
    public void executeStrategyPattern() {
        MathOperation operation;

        //* Three contexts following different strategies below

        //* Outputs '10 + 5 = 15' to log
        operation = new MathOperation(new OperationAdd());
        system.debug('10 + 5 = ' + operation.executeStrategy(10, 5));

        //* Outputs '10 - 5 = 5' to log
        operation = new MathOperation(new OperationSubtract());
        system.debug('10 - 5 = ' + operation.executeStrategy(10, 5));
        
        //* Outputs '10 * 5 = 50' to log
        operation = new MathOperation(new OperationMultiply());
        system.debug('10 * 5 = ' + operation.executeStrategy(10, 5));
    }
}

Just think of the use cases for this in your org!

Do you find yourself executing different logic within nasty conditional statements?

I’ve seen a lot of trigger frameworks built this way. 👆️ 

If you’re new to this pattern, look around the Internet and see where you can implement it.

You won’t regret it! 💃🕺

SOUL FOOD

Today’s Principle

"You can bind up my leg, but not even Zeus has the power to break my freedom of choice."

Epictetus

and now....Salesforce Memes

What did you think about today's newsletter?

Login or Subscribe to participate in polls.