10

We distribute our app in the form of a managed package. We have found that, in some cases, customers create their own integration (triggers, flows...) that have harmful effects on our application (mostly concurrency issues).

For instance:

  • Our application makes a web service call into Salesforce and creates a task and relates it to a record that the end user is viewing/editing. It's done with a pre-configured Salesforce user.
  • Customer's trigger on task creation finds the record that the task is related to, and updates a custom field on it (like, number of tasks created against it). The record that the user is viewing is now stale. All of this happens in the context of the Salesforce user assigned to us for our integration.
  • End user saves the record.
  • End user gets an error that the record cannot be saved because it's stale (and has been modified by the user assigned to us).

The example above shows that the concurrency issue is caused by the customer's trigger, however the error message shows our user name.

We have other, similar cases in which the customer's customisation will either break our application or have harmful effects. This causes a lot of time spent debugging the customers' integrations and may lead to difficult conversations with our customers.

Is there a set of 'best practices' on how to design your app, or how to make the integrations, to protect our app from those harmful side effects?

This question may be considered too wide or general, but any insight will be helpful.

4

As a customer who customizes and "breaks" some of our managed packages on a regular basis, I would say documentation, documentation, documentation! Find out what your customers are trying to do, and make sure there are configurable, documented ways to accomplish those things in your package. The biggest reason my team ends up writing a bunch of triggers and code that interferes with our managed packages is because they either don't understand how to do what they need to do IN the package (due to poor documentation and lack of examples) or because the package provider doesn't have a way for us to do what we're doing.

Documentation about how customization can be harmful or best practices for testing customizations before reaching out directly to you guys for help may also alleviate the problem. Good luck!

  • We're working on that. Its good to know that it will be useful. Thanks! – mkorman Apr 7 '16 at 10:47
2

As a Salesforce implementer that also "Breaks" existing integrations, I do agree with what Lisa has already stated. You guys are running into, what I understand, as an unfortunate side effect of having a PAAS model, which requires you to be EXTREMELY defensive in your programming. The concurrency issue that you present is definitely a hard one to handle and will continue to be since you have no control over their trigger procedure. I unfortunately have no specific standards or operating procedures that I can give you, only a resource that I have found very valuable. Dan Appleman did a demonstration at last years Dreamforce that has helped to spark some inspiration in examining scenarios that are somewhat specific to Salesforce (or any PAAS I would imagine). He helped me to think outside of my normal box of possible issues we could hit and encompass more issues that happen in this type of environment. He has a bunch of other resource materials on specifically creating managed packages and the issues you could face. This could be a good place to look for some of those best practices. One thing he notes often is that you cannot defend against all MetaData modifications - it is the nature of the beast - we just have to do the best job we can and handle as many scenarios as possible.

http://www.slideshare.net/developerforce/defensive-apex-programming

One possible solution you could look at is using Save Points and the Rollback feature to determine if you should retry your update in a different context (asynchronous) or not process the update at all. This is not going to resolve the specific issue that you stated above but can assist in the other direction - during your code's execution context a user or piece of code modifies the record you want to update.

Hope this helps and sorry I couldn't help more!

  • Hi, Chris, your answer is helpful and insightful. I am familiar with Appleman's work (related to Salesforce, and also some excellent career-related courses he has on Pluralsight). I will check out his devensive coding strategies and try to bring some ideas into the package. – mkorman Apr 7 '16 at 10:50
2

I don't think you'll ever be able to shield your managed package from all the creative interactions it will have with customer orgs. There isn't much you can do if they aren't correctly bulkifying their triggers, guarding against circular updates, fiddling with profiles to restrict access to records and APIs, ...

Certainly +1 for Lisa's honest answer, if you can give them documentation about how the package works and what its requirements are they might pick up on it.

While they aren't required to run the test cases from your managed package for deployments, they could still run them to look for red flags. The more test cases that you can provide that will highlight problems in their org the better. Although I've found it difficult to get all the tests passing in all orgs due to the large variations between orgs. Maybe they could setup an Apex Test Suite with just the tests known to work as a smoke test.

Get good at debugging your managed package. Add useful System.debug statements. However, at the same time, try to keep them to a minimum as they can be detrimental to performance.

Provide hooks in your managed package to disable functionality as required. My triggers and validation rules can be disabled with hierarchy custom settings so that clients doing bulk load operations can bypass certain requirements. Of course, this can cause problems later on, so you will need to be defensive at certain locations in your code base. I wrap all the custom settings in a custom class to provide default values when test cases are running.

Check context details during execution to make sure things are as expected. This will include things like System.isFuture(), System.isBatch() and various Limits methods.

  • Thanks. That requires a bit of redesign in our package, but it might be worth it in the long run. – mkorman Apr 7 '16 at 10:48

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.