1

I'm designing an extension package for a managed package to add different integrations to the main package. The objective is to install a specific extension package to enable integration between our main package and another vendors installed managed package. No more than one of our extensions would be installed at once, and it's possible the customer wouldn't have any integration extension installed.

From what I've read the primary issue with using Interfaces in a managed package is that the Global Interface class cannot be modified once added to the package. That would limit flexibility going forward as we build additional integrations that could possibly require other methods/parameter types.

My solution to this is to create a single method in the Interface for Process() that accepts two parameters:

  • String action: Some extension-specific action to take (ex: "post", "retreive", etc.)
  • String jsonParms: A JSON serialized string with the unique parameters specific to the action.

Using the above design, my expectation is that the Global Interface in the main package can be built and (for the most part) not need to be modified going forward if new Extension Package methods are required. In this particular use case, I've only come up with a couple of actions - Post and Unpost - but I can see possibilities where there may be others. The return set in this case is limited as well, given that the extension's purpose is very specific, but I can see where I may need to build a method into the Services class that inherits from the Interface that returns something different. I'm considering a few generic Interface methods for this, such as processReturnString(), processReturnSObjects() and maybe processReturnBoolean() - all accepting the same String action and JSON serialized parameters, and each returning a different type.

The real question here is - will this architecture work and be flexible enough given Salesforce's rather strict rules in Managed Packages?

Extension Design

1

Though for a different use case it sounds like you could benefit from the strategy demonstrated by Dan Appleman's Dreamforce talk on Design Patterns for Asynchronous Apex (7:52-10:22), which he used to workaround the problem where Scheduled Apex gets locked in managed packages from updates.

At the risk of getting opinionated you might also want to consider maintaining your logic all within your main package. Over time managing logic in n number of extension packages can get very cumbersome and possibly lead to inconsistencies with any logic that should be updated across the board.

You could do this in two different ways:

  1. Utilize a custom metadata type to represent the configuration for the current customer and reference that when you need to branch out to specific logic. Unlike custom settings, custom metadata type records can be included in a package, which should work well for your use case.

  2. Create a number of dummy managed packages that contain no logic and then in your main package utilize the UserInfo.isCurrentUserLicensed(namespace) method at points when you want to branch out to specific logic.

  • Thanks @Scott. My working design does roughly follow Dan's pattern (process method instead of execute method) to deal with that issue. Ideally, the interface in the main package would never change, and I can implement changes in the child class at will. – Force2b_Mike Aug 10 '15 at 14:22
  • I've been thinking a lot about your suggestion to push all logic into the main package. There are definitely some complications with this given our use case, but it's not impossible. If the code only needs to insert data into custom objects from another managed package, that can be done with Dynamic SOQL - eliminating the need for an extension that has a package dependency. However, some flexibility will be needed to support calling exposed global methods in other packages when required. I suspect an extension will be needed for those. – Force2b_Mike Aug 10 '15 at 14:25
  • I agree your design appears to be a multi-package version of Dan's pattern so I do think it should work. That said, I would highly recommend using ANT to push the corresponding metadata to an org with a dummy managed package namespace and a corresponding dummy extension org for testing. Yes, since I'm giving advice in the dark without knowing all the ins & outs of your package it's possible you may find the pros outweigh the cons of going with extension packages; I just wanted to mention some other design options available to you. – Scott Covert Aug 10 '15 at 18:51
0

A similar approach that I've been considering is to create a work-alike copy of the Process.Plugin interface in the base package (or even its own small package).

It's a very flexible interface, and has the benefit of being a standard part of the Salesforce API. I wouldn't use Process.Plugin directly, but a copy under my own namespace.

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_process_plugin.htm

To take it a step further, the domain code could call a "boundary controller" placed in front of the globals, so that extensions would not being directly bound to the global API of the base, only to the controller.

Just a thought.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.