1

We are an ISV with multiple managed packages that build on each other. EXTENSION builds on data in BASE.

We now want to start to add Apex code in EXTENSION that uses and enhances code in BASE.

How should I best establish an API / interface between the two of them?

As options I see a global class or Apex SOAP / REST services. Both are very inflexible when it comes to changes and renaming as they are global.

How would you solve that trade-off between keeping such an interface usable but also minimal (therefore flexible)?

3

Since you say this is for "internal" (inter-package) integration, I think you will do best to just implement a single entry point with a generic signature in your class or interface:

global Map<String,Object> invoke(Map<String,Object> args);

The implementation of this method can unpack the args and determine what concrete method to call in your base package.

{
  if(args.get('method') == 'mergeSomething'){
    return mergeSomething(args.get('something1'), args.get('something2'));
  }
}

You lose your type safety and self-documenting method/arg names in exchange for effectively infinite flexibility.

We have done "both" in our base/extension package architecture -- i.e. implementing what you'd do in Java: a series of method signatures in one or more interfaces. But as you are aware, this is madness as it results in dozens of road kill methods that you can never remove. This might be a necessity in a publicly-documented API, but for internal usage, the ability to truly remove deprecated methods is a severe handicap. Additionally, if you're going the interface route, you can't modify packaged global interfaces so you find yourself creating "PaymentGatewayV1", "PaymentGatewayV2", "PaymentGatewayV3" interfaces as you continue to enhance and expand your 'API' functionality.

Instead, we've opted to use generic arguments and return types so that we can change the implementation freely.

If you haven't yet passed the point of no return on creating the extension package, you might want to consider pulling the plug. On top of the stuff outlined above (and the related thread in Reuse / share functionality between base and extension managed packages), the dev/test/fix cycle of coding against a base package is terrible. You always need to package a new version of the base package and you can't use 'beta' packages since you can never upgrade them in the extension dev org -- so sometimes you end up baking in a half-baked idea that you wish you could undo, but can't.

On top of that, you need to manage upgrades carefully. Push Upgrades don't always go smoothly and a given org might cleanly upgrade to a new version of the base package but get stuck due to some platform bug upgrading the extension package. This leads to a scenario that usually doesn't get tested thoroughly in QA -- an old version of an extension package working with a new version of the base package.

| improve this answer | |
1

An approach taken in the Eclipse platform is to add new functionality via (optional) new interfaces. For example, this TextEditor implements 5 extension interfaces, but a 3rd party text editor written many years ago might support non of the extensions but will still work.

To relate this to your case, the base package would define the interfaces (marking them global) and use instanceof to check which interfaces the extension code supports. New non-API compatible functionality is added to the base by adding a new extension interface and the extension package can opt in at some later date by implementing that new extension interface.

If defining custom web service interfaces, a REST approach including a version number in the URL mapping provides the most flexibility and is also usually easier to understand and consume.

| improve this answer | |
  • Sound very interesting. Could you be so kind to provide some few code fragments so I can better understand how this would look like? – Robert Sösemann Jun 9 '15 at 9:59
  • @RobertSösemann The link I included to the JavaDoc for TextEditor probably illustrates it better than I can; you can see the various extension interfaces. I guess the core point is that even using strongly types mechanisms like interfaces you can leave the door open to evolution. – Keith C Jun 9 '15 at 10:10
  • Yes but I wasn't sure how that would work. Maybe I look for open source Eclipse plugins that use it to see how that works in action. – Robert Sösemann Jun 9 '15 at 10:38
  • In case you mean something like de.slideshare.net/stephenwillcock/apex-plugins...that the wrong direction. My EXTENSION package needs to call BASE code. – Robert Sösemann Jun 9 '15 at 20:31
  • I was assuming calls would be going both ways because I've seen examples where the extension is filling in parts of an overall process controlled by the base code. But if its always calls to the base code, then maybe that makes things a bit simpler. But a factory of some sort and interfaces would still help decouple the base and extension code. – Keith C Jun 9 '15 at 21:01

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.