Saturday, 21 October 2017

Programming against Apex Interfaces

Programming against Apex Interfaces

Interfaces

Introduction

In the dim and distant past (getting on for 10 years ago now), when I was a Java programmer working in the systems integration and financial services space, the majority of the programming that I did was against interfaces rather than concrete class instances. This isn’t something that I see very often in the Salesforce world (at least on the SI side - I’d imagine ISVs go in for it a lot more) for a variety of reasons including:

  • Lots of Salesforce work is a point solution on an existing implementation, so it doesn’t always merit abstraction via interfaces.
  • Customers don’t want to the extra cost and accept that additional development effort may be required in future.
  • Many people have ended up as Salesforce developers through non-traditional routes and haven’t been exposed to interfaces.

Simply put, programming against interfaces means that rather than identifying the specific class that carries out an operation in your code, you identify an interface and rely on there being a class that implements that interface at run time. This allows your code to focus on what the operation needs to do rather than how it is accomplished.

Why?

Programming against interfaces introduces flexibility. You can change the implementation of the interface without affecting any of the code that uses the interface. Thus you could start out with a faker implementation that simply returns canned data to allow you to develop the real world interface implementation and the consuming code in parallel. It also means you can have multiple implementations of an interface inside a single system and swap them around via configuration.

Code me. Now.

The scenario for the example is calculating the discount due to an account. The customer has told us that at the moment it is a flat 10%, but this is an area that they will want to change in the future to take into account the account’s industry. This is a classic use case for an interface as we know that we will need to swap out the implementation in the future, and if it changes once it is like to change again in the future.

Concrete classes

My initial implementation of the class to calculate the discount is as follows:

public class SimpleAccountDiscount {
	public double getDiscount(Id accountId) {
        return 10;
    }
}

and I can use this directly in code:

double discount=new SimpleAccountDiscount().getDiscount('00124000004N1TfAAK');
System.debug('Discount = ' + discount);

producing the following output:

07:02:45:045 USER_DEBUG [2]|DEBUG|Discount = 10.0

all well and good. Next I create the more complex version which takes the industry into account - yes, complex is probably over-egging it a bit, but all things are relative.

public class ComplexAccountDiscount {
    public double getDiscount(Id accountId) {
        // default value
        Double discount=10;
        Account acc=[select id, Industry
                     from Account
                     where id=:accountId];

        if (acc.Industry=='Apparel’) {
            discount=15;
        }
        else if (acc.Industry=='Consulting’) {
            discount=5;
        }
        
        return discount;
    }
}

And I can use this in code just as easily :

System.debug('Discount for Burlington (apparel) = '
             + new ComplexAccountDiscount().getDiscount('00124000004RIGFAA4'));

System.debug('Discount for Dickenson (consulting) = '
             + new ComplexAccountDiscount().getDiscount('00124000004RIGHAA4'));

produces the output:

17:14:25:078 USER_DEBUG [1]|DEBUG|Discount for Burlington (apparel) = 15.0
17:14:25:081 USER_DEBUG [4]|DEBUG|Discount for Dickenson (consulting) = 5.0

However, when the customer is ready to move to the more complex version, I need to carry out a deployment in order to start using my new class. Plus if it turned out that a downstream system wasn’t ready for the change, I’d have to carry out another deployment to revert to the simple version. 

Implementing an interface

The following Apex interface reflects the method that must be exposed by any discount implementation:

public interface AccountDiscountInterface
{
    double GetDiscount(Id accountId);
}

Note that I don’t specify an access modifier for the method - as an interface reflects the public interface, the methods in the interface are implicitly public. I then modify may classes (only the complex version shown):

public class ComplexAccountDiscount implements AccountDiscountInterface {

I can then use the interface in place of a concrete class:

AccountDiscountInterface adi=new ComplexAccountDiscount();
System.debug('Discount for Burlington (apparel) = '
             + adi.GetDiscount('00124000004RIGFAA4'));

So my code that gets the discount doesn’t care about the implementation, but the previous line that instantiates the concrete class does. A partial success at most.

Dynamically instantiating a class

The final piece of the puzzle is dynamically instantiating a class based on configuration. If I can do this, my customer can switch implementations simply by changing a custom setting. Dynamical instantiation consists of two parts. First Type.forName() is used to get the type of the Apex class. Then the newInstance() method of the resulting Type is executed to create an instance of the named class. I’ve placed the name of the implementing class into an instance of the Account_Discount_Setting__c custom setting named ‘Default’. This has a field called Implementing_Class__c that I’ve set to ‘ComplexAccountDiscount’:

Account_Discount_Setting__c setting=
    Account_Discount_Setting__c.getInstance('Default');

Type impl = Type.forName(setting.Implementing_Class__c);
AccountDiscountInterface adi=
    (AccountDiscountInterface) impl.newInstance();

System.debug('Discount for Burlington (apparel) = '
             + adi.GetDiscount('00124000004RIGFAA4'));

Now my code has no knowledge of the class that is implementing the discount calculation, it simply creates whatever class has been configured and uses that. If my customer wants to switch the implementation, it’s as simple as changing a field in a custom setting. It also allows me to set up a different version for testing - unit tests should be as simple as possible so if I have a genuinely complex discount implementation I probably don’t want to use that when testing the consuming code in case it has a side effect that my test isn’t expecting - I’d still test that implementation, but in it’s own unit tests.

So these should be used always?

As I mentioned earlier, you don’t always need an interface. They do add a little overhead, as I now have an additional custom setting and interface to create and deploy. If the implementation is never likely to change then there’s no point in abstracting it away like this. We use them a lot in BrightMedia as it allows us to have a selection of implementations for services that customers can chose between. 

 

 

 

 

No comments:

Post a Comment