In this post, we'll look into the performance best practices around CPQ including the back end platform
Performance is one of those areas of a Communications, Media, and Energy & Utilities Cloud project, and really any kind of Salesforce project, that's easy to leave as an afterthought. But, performance is one factor that may make or break the adoption of your implementation by sales reps and other users when you take it to production or even cause revenue loss if your implementation is directly customer-facing. In this blog post, we'll explore different factors and levers that we can pull to improve the performance of Industries CPQ.
Record Triggered Automations
Record triggered automations that are not following best practices can have a major negative impact on performance, and we often see this in implementations on a brownfield org (where Communications Cloud is implemented on an org that is being used in production already), on implementations with poor technical governance, or on teams newer to Industries CPQ.
Record Triggered Automations come in a few flavors: Apex Triggers, Record Triggered Flows, and the soon to be retired Process Builders and Workflow Rules. Salesforce Architects has a great blog post on this topic and it explains the best practice is to use a single automation tool for each object, and put all of your business logic in that tool.
Industries CPQ performance will be impacted by automations on especially the Sales objects such as Opportunity, Quote, Order, and Opportunity Product, Quote Line Item, and Order Product; Asset, and the Account object. Often we see on projects that, for example Order and Order Product have multiple Apex Triggers, Record Trigger Flows, Workflow Rules, and Process Builders, all on the same object!
This causes performance issues because when a user is adding or configuring an item in the cart (or another system is doing so via the CPQ APIs), the CPQ APIs will ultimately insert/update/delete records, which will cause all of these automations to fire. Workflow Rules and Process Builders especially, will cause the automations to fire a second time, and the automations themselves could fire record updates across the same or different objects. This all adds up to more work the platform is doing, longer response times, and more frustration for your customers and sales reps.
Refactoring this by analyzing each of those automations to see if it's even needed and discarding it if not, or refactoring them into a single Apex Trigger + trigger handler can shave seconds off of your CPQ operation response times.
The good news is, this is typically a one-time activity and will help with performance across the board, but you should make sure you have technical governance in place to avoid proliferation of different automations on the same object in the future and ensure best practices are followed.
Product Model
Product model complexity is probably the single biggest item that influences performance. We'll write a blog post in the future to deeper dive on this topic, but the following are items that will negatively impact your performance:
Large number of child line items, especially with default cardinality of 1 or more
Deep product hierarchy, for example more than 3 or 4 levels
Large number of attributes per product
Large number of Context Rules or Advanced Rules
Unfortunately, it's impossible to give firm, generic guidelines like performance will be an issue once you exceed X child products, Y attributes, or Z attributes. This Communications Cloud application constraint document does give some guidelines and figures around rough numbers that are supported in the application. Do note that these aren't hard limits and you can typically exceed them, though if you have a are hitting or exceeding multiple of these limits, you may start hitting governor limit errors.
Please note that even though for example, we can support up to 50 attributes per product, we should not target to have 50 attributes per product, but rather minimize that as much as possible. A product with 1 attribute will perform better than a product with 5 attributes, which will be better than with 10 attributes, and so on, even though we can support up to 50 (or maybe 60 or 70 if we get lucky).
Pricing and Custom CPQ Logic
We often see customers customizing Attribute Based Pricing, writing their own custom Pricing Plan steps, custom Interface Implementation, CPQ Hooks, and so on. One of the beautiful things about Industries CPQ and generally the whole Industry Cloud stack is the ability to inject your own custom business logic throughout the application, for example to create a custom type of pricing that isn't supported out of box. As we know, with great power comes great responsibility, so put extra governance around pricing and custom CPQ logic, to ensure it is following best practices.
Pricing
Out of box, we have 3 flavors of Attribute Based Pricing (standard, source/target, and range). Let's say we introduce an additional 3 flavors of it, so we have 6 all together. Most likely, for a given product or group of product, it will only be possible to price it via one or maybe a couple of these options. This means we can add some conditions into the apex code behind this pricing to check a flag on the product, which specifies what kind of pricing is applicable for it. This can greatly improve performance, as now we are only evaluating 1 type of pricing for each product, instead of 6 types for each product. Doing this kind of analysis and then designing/developing a solution will require someone (or a team of people) with expertise on the product catalog, and on the pricing requirements and code.
Often within a custom Pricing Plan Step, our code will do a query for some data. If this query is on a Large Data Volume and is not a selective query then the performance will suffer. If the code is not following this and other general Apex best practices, we increase our risk of performance issues.
Another common mistake is to implement pricing logic in Salesforce automations such as Apex Triggers, rather than in Pricing Plan Steps. Review your automations to see if they contain pricing logic, and refactor it into Pricing Plan Steps.
Hooks
CPQ Hooks are a way of injecting custom logic before and after the CPQ API logic. This is useful if we want to manipulate the input passed into the API, or manipulate the output of the API. As with pricing, make sure the Apex is following best practices.
As a general tip, try testing with your pricing plan step, hook, implementation interface, or what not enabled and disabled, to see how much overhead it is causing, to see if it's worth doing further analysis. If the difference between enabled and disabled is 500ms to 1s or more, look into it further, whereas if the difference is 100ms or less, probably not worth the time, as in the absolute best case after analyzing you can save at most 100ms.
CPQ Custom Settings
CPQ Configuration Settings are custom settings that impact your CPQ performance (among other things) and can be accessed by going to the App Launcher > Custom Settings > CPQ Configuration Setup. This document is a full reference of the custom settings and below we will point out of a few important ones and the recommended value:
ContextRulesCache: cachemode
CachedQueryMode: true
CacheEnabled: true
DeltaPrice: true
DeltaValidate: true
PricingElementServiceLogging: false
PricingPlanServiceLogging: false
UOWMode: true
While N=not a custom setting, ensure you are using JSONAttribute V2 by going to App Launcher > Custom Settings > Enable Features > V2 Attribute Model.
If you already have these settings configured as per the recommendations, then great. If not, try changing the value, doing regression testing to ensure it doesn't break anything, and measure the performance improvement. Note that this also requires data remediation to update records with V1 attribute to V2.
Out of all these settings, UOWMode, JSONAttribute V2, DeltaPrice, and DeltaValidate are the most likely to cause issues if you change the value, so pay extra attention for those.
Custom Indexes
Custom Indexes are database indexes are do not exist out of box, and are requested by a customer to improve query performance for queries that are using that field in the WHERE clause and are selective. The CPQ engine under the hood, is running Apex code, and that code does queries, among other things. There are some recommended custom indexes that will help improve the CPQ performance, as the underlying code does a query with a WHERE clause on these fields. This article has the list of objects and fields that should be indexed, and you can raise a Salesforce support case to get these custom indexes created in your org.
Closing Thoughts
This post covered only a small subset of things impacting performance, but are some items that can significantly negatively impact your Industries CPQ performance.
Before you start working on improving your CPQ performance, take a baseline of your current performance for different products in different scenarios, and after making any of these improvements, capture the performance, so you are able to see how much improvement each of these areas has made. This will help justify to your business and technology stakeholders on the time and effort spent on this exercise. You can also try implementing some of the low hanging fruits, taking the results back to your stakeholders, and trying to leverage the improvement as justification to spend more effort on the more time-consuming items.
Performance testing is part science, part magic, and at Stratus Carta, we have a Performance Assessment offering to diagnose and analyze your performance issues, org configuration and customization, and more, and provide you actionable recommendations to improve performance.
Beyond this, do make sure you are thinking about performance throughout the implementation, and are planning for single user testing and scale testing, and not just a few weeks before go-live to ensure you have time to identify, analyze, re-design, and fix any issues that come up. At Stratus Carta, we offer both single-user test and scale or load testing as a service. Get in touch to learn more.