💃 For best results DIP your code 🕺

The ChaCha's fav dev principle 😍

Good morning, Salesforce Nerds! Today’s a good day! Today we get to dive 🤿 deeper into my favorite software engineering principle! 🤩 

That’s right - we’re peeling back the layers on the Dependency Inversion Principle (DIP) today!

Not to be confused with Dependency Injection - that’s a Inversion of Control (IoC) technique for dynamically supplying instances (aka dependencies) to classes by way of a framework. 🏗️ 

We’ll hit that up on a later date …

In contrast, DIP is a design guideline that recommends classes only have a direct relationship with high-level abstractions. 🤯 

Confused yet? Well then read on … it’s actually easy to get started!

i knew it

TABLE OF CONTENTS

SOLID AS A ROCK

Writing SOLID Code 🪨 

Put simply, these are design principles that encourage us to create more maintainable, understandable, and flexible software. 🔥 

We’ve touched on these principles before. And while today we’re looking 👀 at our fav let’s quickly recap just for context.

☑️ Single Responsibility Principle - This principle states that a class should only do one thing and therefore it should have only a single reason to change.

☑️ Open-Closed Principle - This principle says classes should be open for extension and closed to modification.

☑️ Liskov Substitution Principle - Named after the person that introduced the concept - Barbara Liskov - it states that subclasses should be substitutable for their base classes.

☑️ Interface Segregation Principle - This principle requires that a client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.

☑️ Dependency Inversion Principle - This principle states that our classes should depend upon interfaces or abstract classes instead of concrete classes.

Btw - here’s another good article that explains all this in detail & with pictures! 💪 

Okay, moving on …

DIP YOUR WAY TO BETTER CODE

Dependency Inversion Principle ⬆️ 

First, the technical definition:

High-level modules should not depend on low-level modules. Both should depend on abstractions.

But, what are high-level and low-level modules? 🤔 

When we write software it’s comprised of many small independent components commonly called modules.

👉️ Each module in the system is designed for specific functionality

👉️ Each module has elements that work together to form a single unit

👉️ These modules are considered building blocks of an application

👉️ Modules often interact with other modules in order to execute a critical business task/process

You can think of high-level modules as the orchestration piece of your application.

They interact with (or depend on if done wrong) multiple modules throughout the system we refer to as low-level modules to provide complete functionality.

DIP seeks to keep the dependent code (low-level module) away from the main code (high-level module).

It does this by eliminating the direct dependency between low-level modules and high-level modules to reduce coupling. 🔗 

Because … the modules should rely on an abstraction layer to interact with each other. This make sure any changes done in low-level modules wont break the high-level modules. 🧠 

This reduces the cost of maintenance and fragility of code. 💯 

Here are some of the benefits you’ll see from implementing this pattern:

Loose Coupling

Testability

Maintainability

Scalability

PICTURE IS WORTH A 1000 WORDS

Generalized UML 🖼️ 

Let’s check out some Salesforce-y diagrams shall we? Always helps me to see pictures! 📸 

Our example shows the generalized UML diagram for a Salesforce implementation with Apex Enterprise Patterns.

Without applying any DIP techniques our dependency graph starts to look like this 👇️ 

Non DIP Implementation

Here we have a direct dependency between our Service and our Domain and then our Domain and our Selector.

This isn’t ideal for a number of reasons - remember those benefit we just talked about? 👆️ 

Yep, we pretty much lose all the things. Big sad. 🥹 

So what’s a dev to do? It’s simple really - introduce interfaces and code against them instead.

Check it out now, just a slight change 👇️ 

Add some DIP to your life

As you can see now, some of the arrows in our dependency graph have inverted directions.

This is how you implement dependency inversion! 🤯 

SHOW ME THE CODE

Example 🧑‍💻 

Alright, so let’s keep following the above examples.

Our first code block will not apply and DIP techniques. Meaning whatever class implements this code will be

Tightly Coupled

Difficult to test/mock

Less maintainable

Less scalable

public void doUsefulStuff(List<Account> recs) {
    Set<Id> accountIds = new Map<Id, Account>(recs).keySet();

    OpportunitiesSelector selector = new OpportunitiesSelector();
    List<Opportunity> oppRecs = selector.selectByAccountIds(accountIds);

    Opportunities opps = new Opportunities(oppRecs);

    //* Do some more useful stuff
}

Now, for the DIP code. Notice all we really do is add interfaces to the mix 🤩

Loosely Coupled

Easy to test/mock

More maintainable

More scalable

public void doUsefulStuff(List recs) { Set accountIds = new Map(recs).keySet(); IOpportunitiesSelector selector = OpportunitiesSelector.newInstance(); List oppRecs = selector.selectByAccountIds(accountIds); IOpportunities opps = Opportunities.newInstance(oppRecs); //* Do some more useful stuff }

Hold up though … there’s something new here.  

What are these newInstance() methods? 🤔 

That my friends is a topic for another article. For now, just know that it’s an implementation of the Service Locator Pattern.

Until next time … happy coding and remember USE INTERFACES! 😁 

SOUL FOOD

Today’s Principle

"Program to an interface, not an implementation."

and now....Salesforce Memes

no worries, this will be easy

i’ll never do that again

with good reason

What did you think about today's newsletter?

Login or Subscribe to participate in polls.