💃 A core principal Salesforce devs should know 🕺

Maximize the flexibility of your Apex

Good morning, Salesforce Nerds! Just like the docs declare: Apex is an object-oriented programming language.

We can create our own objects, interfaces, behaviors, properties, etc.

For a Salesforce developer this offers a TON of benefits! 🥳 

Not lost among these benefits is the idea of reusability.

However, this can be a tricky thing to implement in a scalable way. Business needs are fluid and our Org’s codebase needs to be able to ride the waves. 🏄️ 

So let’s learn how to surf with a core principal Salesforce developers should understand …

don’t sweat it, chacha’s got you

TABLE OF CONTENTS

First things first

Quick intro

Software systems are inherently complex. 🫠 

One of the advantages of object-oriented languages (like Apex) is that it helps developers break down that complexity by offering tools they can leverage to reuse code they’ve already written.

Two fundamental techniques dev’s use for this are:

Inheritance

Composition

Think of inheritance as designing our types around what they are. And composition as designing our types around what they do.

Let’s break that down a bit more. 👇️ 

Inheritance

What is Inheritance?

Technically speaking, inheritance is a mechanism where you can to derive a class from another class to form a hierarchy of classes that share a common set of properties and methods.

I know, technical definitions can be scramble the brain sometimes. 😕 

So, let’s consider an example:

Suppose we’re designing an app and we need a Dog that can bark() 🐶 

Easy enough:

public class Dog { public void bark() { System.debug('Woof'); } }

We release to production and everyone is happy. 😀 

Except for the cat-lovers …

So, in our next sprint we release our Cat and it’s meow() functionality. 😻 

public class Cat { public void meow() { System.debug('Meow'); } }

Next thing we know, nature is calling and our Dog and Cat classes need to be able to relieve themselves. So, we add this to each class like so:

public class Dog {
    public void bark() {
        System.debug('Woof');
    }

    public void poop() {
        System.debug('💩');
    }
}

public class Cat {
    public void meow() {
        System.debug('Meow');
    }

    public void poop() {
        System.debug('💩');
    }
}

See that duplicated code? 💩 We can’t have that. 🚫 

Enter inheritance! This allows us to lift our poop() method out of each class and into a shared parent class that we’ll call Animal.

Like this 👇️ 

public virtual class Animal { public void poop() { System.debug('💩'); } }

Now, our Dog and Cat classes can inherit their poop() functionality from the Animal class simply by extending it:

public class Dog extends Animal {
    public void bark() {
        System.debug('Woof');
    }
}

public class Cat extends Animal {
    public void meow() {
        System.debug('Meow');
    }
}

So far, so good. 🤙 

Dogs can bark and 💩. Cats can meow and 💩.

Moving on …

Composition

What is composition?

Let’s start with the technical piece again:

Composition describes a class that references one or more objects of other classes in instance variables. This allows you to model a has-a association between objects.

Time to expand on our example above …

Ever since we’ve released our app to production, we have Dogs and Cats 💩ing all over the place now.

Anyways, the business needs help cleaning it all up. They’d like a Robot to handle the job.

So, we introduce a new class called CleanerRobot that can move() and clean().

public class CleanerRobot {
    public void move() {
        System.debug('Moving');
    }

    public void clean() {
        System.debug('Scoop the 💩');
    }
}

We also want to train our pets where they should be answering natures call. We can’t be damaging our nice carpets and rugs!

We need another robot for this. This one also needs to move() and it needs to train().

public class TrainerRobot {
    public void move() {
        System.debug('Moving');
    }

    public void train() {
        System.debug('🥰');
    }
}

But, hold up, now we have duplication again. 🛑 

Our move() method exists in the both classes! 🤔 

No worries, we can just lift move() up to a shared parent class like we did with the poop() method … like this:

public virtual class Robot {
    public void move() {
        System.debug('Moving');
    }
}

public class CleanerRobot extends Robot {
    public void clean() {
        System.debug('Scoop the 💩');
    }
}

public class TrainerRobot extends Robot {
    public void train() {
        System.debug('🥰');
    }
}

Problem solved, right? 🥳 

Not so fast … remember those waves 🌊 we were talking about riding? Here comes one right now! 🏄️ 

The business now declares:

“We need a TrainerRobotDog … it can train(), move(), and bark(). But it’s a robot so it can’t poop().

👆️ With these rules in mine … we cannot fit our new TrainerRobotDog nicely into our hierarchy model.

If we structure these classes in a way where we’re inheriting functionality from both parent classes (Animal, Robot) then we will giving our TrainerRobotDog functionality that it doesn’t need and can’t execute - poop().

We don’t want this. It’s a violation of the Interface Segregation Principle. 🫢 

Composition to the rescue! 🦸 

Using composition, we need to shift our thinking of the objects making up our app to what they do:

 Dog = 💩er + barker

 Cat = 💩er + meower

 CleanerRobot = mover + cleaner

 TrainerRobot = mover + trainer

 TrainerRobotDog = mover + trainer + barker

With this in mind, we simply extract these behaviors into their own classes.

Check it out 👇️ 

public class Pooper {
    public void poop() {
        System.debug('💩');
    }
}

public class Barker {
    public void bark() {
        System.debug('Woof');
    }
}

public class Meower {
    public void meow() {
        System.debug('Meow');
    }
}

public class Mover {
    public void move() {
        System.debug('Move');
    }
}

public class Cleaner {
    public void clean() {
        System.debug('Scoop the 💩');
    }
}

public class Trainer {
    public void train() {
        System.debug('🥰');
    }
}

With our core functionality split into distinct classes. We can use composition to implement the functionality of our Dog, Cat and Robots:

See below 👇️ 

public class Dog {
    Barker barker;
    Pooper pooper;

    public Dog(Barker barker, Pooper pooper) {
        this.barker = barker;
        this.pooper = pooper;
    }
}

public class Cat {
    Meower meower;
    Pooper pooper;

    public Cat(Meower meower, Pooper pooper) {
        this.meower = meower;
        this.pooper = pooper;
    }
}

public class CleanerRobot {
    Mover mover;
    Cleaner cleaner;

    public CleanerRobot(Mover mover, Cleaner cleaner) {
        this.mover = mover;
        this.cleaner = cleaner;
    }
}

public class TrainerRobot {
    Mover mover;
    Trainer trainer;

    public TrainerRobot(Mover mover, Trainer trainer) {
        this.mover = mover;
        this.trainer = trainer;
    }
}

public class TrainerRobotDog {
    Mover mover;
    Trainer trainer;
    Barker barker;

    public TrainerRobotDog(Mover mover, Trainer trainer, Barker barker) {
        this.mover = mover;
        this.trainer = trainer;
        this.barker = barker;
    }
}

This technique allows us to construct classes with any type of behavior the business needs! 💯 

Composition over Inheritance

Composite Reuse Principal

This principle suggests that dev’s should prioritize the use of composition to achieve both polymorphic behavior and code reuse, instead of relying too much on inheritance. 🔄 

While inheritance allows a class to inherit properties and behaviors from a parent class, composition focuses on constructing complex objects by combining simpler objects.

And as the complexity of your applications grow, this principal will help you achieve maximum flexibility throughout your codebase. 👍️ 

So now what?

Takeaway

Today it’s essential to design our Salesforce applications in a more flexible manner. 💪 

Object composition is a concept that will help get us there.

This does not mean forget about inheritance, though. 🤔 

We can (and should) combine both ideas! This will lead to a resilient codebase capable that’s receptive to change and capable of standing up to a onslaught of change requests.

SOUL FOOD

Today’s Principle

"Controlling complexity is the essence of computer programming."

Brian Kernighan

and now....Salesforce Memes

💪 

follow the white rabbit folks 🐰

composition > inheritance

What did you think about today's newsletter?

Login or Subscribe to participate in polls.