Andy in the Cloud

From BBC Basic to Force.com and beyond…

Managing Dependency Injection within Salesforce

34 Comments

When developing within Salesforce, dependencies are formed in many ways, not just those made explicitly when writing code, but those formed by using declarative tools. Such as defining Actions and Layouts for example. This blog introduces a new open source library I have been working on called Force DI. The goal is to simplify and more importantly consolidate where and how to configure at runtime certain dependencies between Apex, Visualforce or Lightning component code.

Forming dependencies at runtime instead of explicitly during development can be very advantageous. So whether you are attempting to decompose a large org into multiple DX packages or building a highly configurable solution, hopefully, you will find this library useful!

So what does the DI bit stand for?

The DI bit in Force DI stands for Dependency Injection, which is a form of IoC (Inversion of Control). Both are well-established patterns for providing the runtime glue between two points, basically the bit in the middle. Let’s start with an Apex example. In order to use DI, you need to forgo the use of the “new” operator at the point where you want to do the injection. For example, consider the following code:-

PaymentEngine engine = new PayPal();

In the above example, you are explicitly expressing a dependency.  Which not only means you have to deploy or package all your payment engines together, but you have hardcoded a finite set you support and thus also forgone extensibility. With Force DI you can instead write

PaymentEngine engine = (PaymentEngine) di_Injector.Org.getInstance(PaymentEngine.class);

How does it know which class to instantiate then?

Whats happening here is the Injector class is using binding configuration (also dynamically discovered) to find out which class to actually instantiate. This binding configuration can be admin controlled, packaged (e.g. “PayPal Package”) and/or defined dynamically via code. Setting up binding config via code enables dynamic binding by reading other configuration (e.g. the user’s payment preference) and binding accordingly.

The key goal of DI is that calling code is not concerning itself with how an instance is obtained, only what it does with it. The following shows how a declarative binding is expressed via the libraries Binding Custom Metadata Type:-

If this all seems a bit indirect, that’s the point! Because of this indirection, you can now choose to deploy/package other payment gateway implementations independently from each other as well as be sure that everywhere your other code needs a PaymentEngine the implementation is resolved consistently. For a more advanced OOP walkthrough see the code sample here.

Can this help me with other kinds of dependencies?

Yes! Let’s take an example of Lightning Component used as an Action Override. Typically you would create a Lightning Component and associate it directly with an action override. However, this means that the object metadata, action override and the Lightning code (as well as whatever is dependent on that) must travel around together. Rather than, for example, in separate DX packages. It also means that if you want to offer different variations of this action you would need to code all of that into the single component as well.

As before let’s review what the Lightning Component Action Override looks like without DI:-

<aura:component implements="lightning:actionOverride,force:hasSObjectName">
   <lightning:cardtitle="Widget">
     <p class="slds-p-horizontal_small">Custom UI to Create a Widget ({!v.sObjectName})</p>
   </lightning:card>
</aura:component>

This component (and all its dependencies) would be directly referenced in the Action Override below:-

Now let us take a look at this again but using the Lightning c:injector component in its place:-

<aura:component implements="lightning:actionOverride,force:hasSObjectName">
   <c:di_injector bindingName="lc_actionWidgetNew">
      <c:di_injectorAttribute name="sObjectName" value="{!v.sObjectName}"/>
   </c:di_injector>
</aura:component>

To make things clearer when reviewing Lightning Components in the org, the above component follows a generic naming convention, such as actionWidgetNew. This component is instead bound to the Action Override, not the above one and now looks like this:-

The binding configuration looks like this:-

Finally, the injected Lightning Component widgetWizard looks like this:-

<aura:component>
   <aura:attribute name="sObjectName"type="String"/>
   <lightning:card title="Widget">
     <p class="slds-p-horizontal_small">Custom UI to Create a Widget ({!v.sObjectName})</p>
   </lightning:card>
</aura:component>

Note: You have the ability to pass context through to the bound Lightning Component just as the sObjectName attribute value was passed above. The c:injector component can be used in many other places such as Quick Actions, Lightning App Builder Pages, and Utility Bar. Check out this example page in the repo for another example.

What about my Visualforce page content can I inject that?

Visualforce used by Actions and in Layouts can be injected in much the same way as above, with a VF page acting as the injector proxy using the Visualforce c:injector component. We will skip showing what things looked like before DI, as things follow much the same general pattern as the Lightning Component approach.

The following example shows the layoutWidgetInfo page, which is again somewhat generically named to indicate its an injector proxy and not a real page. It is this page that is referenced in the Widget objects Layout:-

<apex:page standardController="Widget__c" extensions="di_InjectorController">
   <c:di_injector bindingName="vf_layoutWidgetInfo" parameters="{!standardController}"/>
</apex:page>
The following shows an alternative means to express binding configuration via code. The ForceApp3Module class defines the bindings for a module/package of code where the Visualforce Component that actually implements the UI is stored. Note that the binding for vf_layoutWidgetInfo points to an Apex class in the controller, not the actual VF component to inject. The Provider inner class actually creates the specific component (via Dynamic Visualforce).
public class ForceApp3Module extends di_Module {

    public override void configure() {

        // Example named binding to a Visualforce component (via Provider)
        bind('vf_layoutWidgetInfo').visualforceComponent().to(WidgetInfoController.Provider.class);

        // Example SObject binding (can be used by trigger frameworks, see force-di-demo-trigger)
        bind(Account.getSObjectType()).apex().sequence(20).to(CheckBalanceAccountTrigger.class);

        // Example named binding to a Lightning component
        bind('lc_actionWidgetManage').lightningComponent().to('c:widgetManager');
    }
}

NOTE: The above binding configuration module class is itself injected into the org-wide Injector by a corresponding custom metadata Binding record here. You can also see in the above example other bindings being configured, see below for more on this.

The actual implementation of the injected Visualforce Component widgetInfo looks like this:-

<apex:component controller="WidgetInfoController">
  <apex:attribute name="standardController"
     type="ApexPages.StandardController"
     assignTo="{!StandardControllerValue}" description=""/>
  <h1>Success I have been injected! {!standardController.Id}</h1>
</apex:component>

Decomposition Examples

The examples, shown above and others are contained in the sample repo. Each of the root package directories, force-app-1, force-app-2, and force-app-3 helps illustrate how the point of injection vs the runtime binding can be split across the boundaries of a DX package, thus aiding decomposition. The force-di-trigger-demo (not shown below) also contains a sample trigger handler framework using the libraries ability to resolve multiple bindings (to trigger handlers) in a given sequence, thus supporting the best practice of a single trigger per object.

Further Background and Features

I must confess when I started to research Java Dependency Injection (mainly via Java Guice) I was skeptical as to how much I could get done without custom annotation and reflection support in Apex. However, I am pretty pleased with the result and how it has woven in with features like Custom Metadata Types and how the Visualforce and Lightning Component injectors have turned out. A plan to write future Wiki pages on the associated GitHub repo to share more details on the Force DI API. Meanwhile here is a rundown of some of the more advanced features.

  • Provider Support
    Injectors by default only return one instance of the bound object, hence getInstance. Bindings that point to a class implementing the Provider interface (see inner interface) can override this. Which also allows for the construction of classes that do not have default constructors or types not supported by Type.forName. This feature also works in conjunction with the ability to pass a parameter via the Apex Injector, e.g. Injector.Org.getInstance(PaymentEngine.cls, someData);
  • Parameters
    Each of the three Injectors permits the passing of parameter/context information into the bound class or component. The examples above illustrate this.
  • Modules, Programmatic Binding Configuration and Injector Scopes
    Binding Modules group programmatic bindings and allow you to hook programmatically into the initialization of the Injector. Modules use the Fluent style interface to express bindings very clearly. The force-app-3 package in the repo uses this approach to define the bindings shown in the VF example above. You can also take a look at a worked example here of how local (one-off) Injectors can be used and here for a more complex OO example of conditional bindings works.
  • StandardController Passthrough
    For Visualforce Component injections the frameworks parameter passing capabilities supports passing through the instance of the StandardController from the hosting page into the injected component, as can be seen in the example above.
  • Binding Discovery by SObject vs Name
    The examples above utilize single bindings by a unique name. However, it is becoming quite common to adapt trigger frameworks to support DI and thus allow a single trigger to dynamically reach out to one or more handlers (perhaps installed in separate DX packages). This example shows how Force DI could be used in such a scenario.

Conclusion

This blog has hopefully wet your appetite to learn more! If so, head over to the repo and have a look through the samples in this blog and others. My next step is to wrap this up in a DX package to make it easier to get your hands on it, for now, download the repo and deploy via DX. I am also keen to explore what other aspects of Java Guice might make sense, such as the Linked Bindings feature.

Meanwhile, I would love feedback on the sample code and library thus far. Last but not least I would like to give a shout out to John Daniel and Doug Ayers for their great feedback during the initial development of the library and this blog. Enjoy!

 

34 thoughts on “Managing Dependency Injection within Salesforce

  1. I like the flexibility of late binding injection, but how do you ensure that the binding spec is valid at runtime?
    // Example named binding to a Visualforce component (via Provider)
    bind(‘vf_layoutWidgetInfo’).visualforceComponent().to(WidgetInfoController.Provider.class);

    What if there is a typo in ”vf_layoutWidgetInfo’, it’s just a constant…

    Worse for the lightning component example:
    // Example named binding to a Lightning component
    bind(‘lc_actionWidgetManage’).lightningComponent().to(‘c:widgetManager’);

    How can we ensure that this binding will work?
    How do you test this binding dimension?

    • So yes sadly Apex only permits compile time checks on apex classes, so the lib does support Type references like you see in the other examples via MyClass.class for example. You could use a class to define the string constants e.g. BindingNames.vf_layoutWidgetInfo as well. I might have a look at including that convention and see how it looks. Finally yes from the testing side I literally just added some examples to force-app-1. Thanks for the feedback!

  2. Pingback: Around the Web – 20180720 - WIPDeveloper.com

  3. Hi Andrew, Its a great library to use DI in Salesforce. I have a question about the Lightning component which u have shown above which uses the c:injector and attrbute components.
    So what I understand is that instead of directly linking the component to the Quick Action we create a Wrapper or Proxy component which uses the c:injector to inject the final component at runtime. This is to delink the final component and all child dependencies from the actual button.
    So for every such component, we will end up with 2 components and not 1.
    Is that a current understanding.

    • That is correct. But the so called “proxy component” should really never need to touching once it’s created. I also offered a naming convention to allow to be more visible as that intended purpose. Finally as this is DX you can of course place these in another folder to your main components in that package. Though the bound components and most of the work will of course be occurring in another package dir anyway.

      • Thanks, Andy. Sounds good.

      • Hi Andrew, we just noticed that the DI proxy component to override account object new button works in scratch org with push. But when a package is created and install it to a sandbox environment, it just doesn’t override at all. Any idea why would this happen? Thanks.

      • Did you package the bindings?

  4. Pingback: Test Driven Development, Mocking and Force DI | Andy in the Cloud

  5. Pingback: Parameterised Dependency Injection via Custom Metadata Types – Nebula Consulting

  6. I just saw the new Callable interface in Apex. It looks like that can be used to handle at least the Apex side of this. https://developer.salesforce.com/docs/atlas.en-us.216.0.apexcode.meta/apexcode/apex_interface_System_Callable.htm
    So will your module and descriptions be updated to use the Callable interface? It seems like you’re also providing methods to do this on Lightning and Visualforce … are those capabilities unique to your tool at this point, or are there upcoming built-in ways to do this in VF, Lightning, page layouts, etc.

    • Hi Andrew. So the Callable interface is really just an option depending on the dependency being strongly coupled (via a typed specific interface as shown in the examples here) or a loosely coupled interface (in which case Callable makes sense). The library makes no assumptions or requirements on which approach you want to take since you only express the implementation in the binding not the interface. For the moment i am not aware of any plans to make this native, though tweaks like Callable and others will start emerge to assist in building libraries like this. This is kinda what happened when Apex Mocks first arrived, new base API’s e.g. Test.createStub emerged in the platform while the open source lib continues to leverage and extend around it. My thoughts are my own.

  7. Pingback: Parameterised Dependency Injection via Custom Metadata Types · Nebula Consulting

  8. Hi Andrew,

    Firstly, thank you for this open source library, it’s nice to have a consistent approach to solving DI problems in Salesforce.

    We have specific requirement where I need to resolve the metadata bindings using additional filters on the di_Binding__mdt, for instance i can create a new picklist field to allow for an additional filter criteria on di_Binding__mdt, but for the force-di framework to respect this new field i need to make quite a few changes:
    1. Update Resolver class with new method byNewCustomField
    2. Extend di_module and use a custom version of CustomMetadataModule to query & set new fields
    3. Extend di_binding to support this new field

    An alternate option would be to use a Module binding and have that class lookup another custom metadata with the filter criteria i need & use that to create the specific instance at run time. However this would require us to manage 2 metadata types.

    Basically what we are trying to achieve here is, to have a base package that provides core functionality allowing subscribers to modify some behaviour by letting them override certain functionality without having to touch any of the classes in the core base package.

    Just wanted to check if i am missing something, is there a way i can provide support for additional filter criteria on the di_Binding__mdt by just extending a few classes but not making changes to the core force-di classes?

  9. Hi Andrew,

    Thank you for all the apex knowledge that you are sharing across.

    I started with your Apex Design Patterns Library a few days ago. Now I stumbled upon this library. Both these libraries can work together right ? If needed.

    We are not using DX yet

    • Yes, both work together once deployed. Simply install the force-di unlocked package into your DE or Sandbox org will be the easiest way.

      • Hi,
        Would there be any pointers for deploying in *production*? Are those unlocked packages for development convenience only? Is the best bet:
        1. Referencing a particular commit from the GitHub git repo when packaging (though a version tag would be preferred),
        2. Duplicating the source in our own libraries,
        3. Referencing the unlocked package.
        Could the readme be updated to offer some guidance? Perhaps there’s a Salesforce-packaging-101 answer to this.

      • Those are excellent questions! The authors of this lib and I have decided to remove the package install option for now while we work on it. Meanwhile you can absolutely deploy this to a scratch org and create your own packages (tracking the git hash in the package tag attribute perhaps). Or for a more direct deploy use sfdx force:source:deploy to send direct to a sandbox and note the git hash used at the time elsewhere for future reference.

  10. Hi Andrew. Is there a way to set up module bindings using metadata but pass in a parameter that the modules can access in their configure() implementations? When using di_Injector.Org.getInstance(..., that is. I can see how to pass data to class bindings via getInstance, but not to modules.

    • No not currently. Modules get their configuration from the environment. Records or other custom settings or custom metadata. Passing via getInstance would be a little odd since the modules are cached once loaded in memory so subsequent attempts to pass via getInstance would not work. What’s your use case?

      • Thanks. Use case is conditional run-time binding in configure() that relies on data that we’d like pass in. Initial experiments had the logic directly accessing our sObject data, but in production we’d hoped to have that decoupled a bit.

        public override void configure() {
        RegionTestFlag__mdt[] regions = [SELECT Id, CurrentLegislation__c FROM RegionTestFlag__mdt]; // Prefer to avoid SOQL dependency here.
        if(regions[0].CurrentLegislation__c == 'US') {
        bind(ITrivialProvider.class).to(UsTrivialProvider.class);
        }
        }

      • Have you thought about making that a custom metadata type object vs a custom object? Queries use less limits and are faster

  11. Hi Andrew. Indeed a great library and thank you for sharing your knowledge. I was trying to install the package via the browser but was unable to do as I get the below error.

    Method does not exist or incorrect signature: void startTest() from the type Test di_BindingParamTest: Method does not exist or incorrect signature: void startTest() from the type Test

    Method does not exist or incorrect signature: void stopTest() from the type Test di_BindingParamTest: Method does not exist or incorrect signature: void stopTest() from the the type Test

  12. Could you please update the links mentioned in your article? Your package is extremely useful for DX packages. Thanks for the work.

  13. Pingback: Test Driven Development, Mocking and Force DI - Salesforce News & Tutorials

  14. Pingback: 5 Anti-Patterns In Package Dependency Design and How to Avoid Them - ThemeOr

  15. And how about supporting dependency injection in lwc components – is it possible at all?

    • Actually that is supported at a component level – I assume you mean within the controller code? If so – yeah neat idea 💡 Do you want to contribute – if so totally feel free – all welcome

      • What I mean is whether we could have something similar to c:di_injector tag (used in aura components) for LWC components.
        In other words to be able at LWC markup level inject some LWC component from DI container based on bindings.
        In aura case you are relying on $A.createComponent standard sf function to dynamically create aura component, but AFAIK there is no support at a platform level itself for LWC component dynamic creation from LWC context.
        That the challenge I’ve bumped into when trying to extend this for LWC – no clue how to handle this at all currently.

      • Ah yes I see – I have not checked recently but I also recall that restriction with lwc. My only thought would be some kinda of factory pattern in the lwc complnet but that will need to have prior knowledge of each component of course. Other option maybe is to use a visual force page and try dynamic property when adding lwc to the page

  16. Pingback: Dependency Injection in Salesforce - Ebury LABS

Leave a comment