Salesforce Commerce Cloud (SFCC) is a leading e-commerce platform that allows businesses to create and manage online stores. To ensure that the code used to develop and maintain these stores is of high quality and easy to maintain, SFCC has a set of guidelines and standards for coding. These guidelines and standards cover areas such as naming conventions, organization of code, and best practices for performance and security. Adhering to these guidelines and standards helps to ensure that code is maintainable, efficient, and secure.
Site and custom BM extension cartridges
Site and custom BM extension cartridges taxonomy should follow best practices. Best practices for organizing the data are stored and maintained under customize_business_manager in infocenter
Follow Recommended Naming Conventions
An instance is a server connection path. Give your instance a unique name such as firstInitial_lastName to avoid multiple developers changing the same instance, which can result in code overwrite or code loss. A unique name also identifies which developer is working on an instance.
URL Best Practices:
Create URLs that are 70 characters or less. Use name attributes, rather than ID attributes, as they are more meaningful.Include the name of your business in all URLs.
SEO Best Practices
Best practice for constructing storefront URLs optimized for external search engines is maintained under Search Engine Optimization in infocenter
Don’t use inline JS /CSS handlers your code
While developing or performing code review activities cross-check with recommendations: b2c_content_best_practices
✔ OK to Use if declare variables that are used within the ISML template to print values to the front end.
❌ NOT OK to use if custom business logic is executed in the inline script. When you wish to perform overall assessment use REGEX:
For inline isscripts:
For inline JS;
For inline CSS
Review each implementation to determine the validity of its usage
Inline documentation in custom code
Always add inline documentation to your custom code. Inline documentation should not be used to state what should be obvious. Inline documentation should be used above every function and class above every complicated part of the code. It should be easy to understand what and why code is performing certain logic for the next person to understand the code.
Comments and documentation are comprehensive, easily shareable and extensible to future phases as part of any change. It is important to add appropriate comments
Validate log files
Validate log files while making changes to ensure code quality after the change. Perform assessment against best practices and requirements: Look for uncaught/unhandled exceptions. Timeout scenarios HTTPclient or 3rd party services error or timeout.
Modular Code Structure
- Implement code in a modular, reusable and understandable manner. While developing or performing code review activities pay attention to usage of libraries, utility methods, cartridges, and common functions.
- Follow the DRY (Don’t Repeat Yourself) programming principle and don’t duplicate built-in / custom functions in templates and scripts. While developing or performing code review activities pay attention on template files; ensure that they are using the <is functions and not using JS libraries to implement the required UI
- While designing code, make sure to consider future code evolutions and that refactoring of code will not be required. Avoid SFRA controller overrides. E.g. organize code into prepend, append and replace controllers methods; re-used functions are factored into helper classes.
Error Handling and Exception Handling
📌Develop with adequate error handling (e.g. try-catch for scripts).While developing or performing code review activities cross check code, error logs, and evaluating against best practices; e.g. validations.
📌Returns from dw API are almost correct unless there are Business Logic Exceptions.
📌Determine if there are Business Requirements to handle edge cases apart from technical exceptions.
📌Developer with unhandled pipelet errors, graceful exit conditions with messaging in mind. Best practice is that transactions should always be encapsulated with try-catches.
Custom Session Variables
Session variables must not be used to store arrays but only single key values. For more information on privacy cache click here.
Be mindful of storing sensitive data within Session Variables. While developing or performing code review activities cross check for sensitive data like
- Private data
- National ID
- Payment data
- Credit Card Number
Web Services & timeout
Don’t trigger live calls to external systems on frequently visited pages. Where live calls are needed, specify a low timeout value.While developing or performing code review activities the validation can be done via:
Method #1: Check logs for HTTP calls and any warning of HTTPClient – using a saved search Trace the code for method names of service calls being made and search in the code for their instances
Method #2: Go to CCAC and find the top few controllers. Go into the Include Controllers Search in the code to view if any live calls were made OR run with Code Profiler in development to see if any HTTPClient library is being triggered
Don’t keep Web Services authentication secrets in plain text on Business Manager site preferences or hardcoded in the code or resource files. While developing or performing code review activities the validation can be done via:
👉 Check Services implementation in the code.
👉 Search for services using keywords like parseResponse, createRequest etc.
SFCC Script Development Best Practices
📌Search results can be large sets. Instead, all search criteria must go into the query for efficiency execution. Don’t post-process with custom code. While developing or performing code review activities cross check with recommendations, search for loops and iterators.
📌Post processing happens when after the (Product Search Model) PSM.search() method is called, each individual result is looped through to retrieve an attribute to filter the results.Post processing is not considered if it is being looped through to display the results.
There are different types of Iterators in B2C Commerce:
- Iterator object
Generally an iterator should not be reused as it can trigger an illegal state exception. dw.util.SeekableIterators are used for iterating large datasets. They need to be closed after use. Iterators should be executed within try-catch statements. Each object should be handled in a single transaction before moving to the next object
📌Don’t iterate over variations of a base product on a search result page (or any page where multiple base products appear). This approach can significantly increase the number of touched business objects. Instead, use native Salesforce B2C Commerce features to deal with variation product availability pipelet Search input parameter OrderableProductsOnly to determine available variation values
dw.catalog.ProductSearchHit.getRepresentedVariationValues to determine price ranges dw.catalog.ProductSearchHit.minPrice
📌While developing or performing code review activities the validation can be done via: search in usual places that this is used: PDP when determining the variant swatch Search Results Page/ PLP use storefront toolkit to determine which UI blocks and review the controllers. Do a search using getProducts() to determine if there is such instance
📌Do Break search results into pages before processing or displaying in the storefront: pipelet Paging and class PagingModel
📌While developing or performing code review activities the validation can be done via: Search-Show. Check if PagingModel has been used. Look at the Search Results Page. Check that there are Max 24 results loaded.
Limit the maximum page size, for example, a maximum of 120 products per page, especially if the “View All” functionality is provided.
📌Avoid concurrent changes to the same object. Storefront pipelines should only read shared data (for example, catalogs and prices) and read or write customer-specific data (for example, customer profiles, shopping carts or orders).
📌This practice avoids making concurrent changes. The inventory framework is designed to support concurrent change (for example, two customers buying the same product at the same time or a customer buying a product while the inventory import is running). The storefront pipeline marks the order with EXPORT_STATUS_READY as the last step in order creation.
📌Then order processing jobs can start modifying the order object. Concurrent requests for the same session are serialized at the application server.Use Index Friendly APIs.
📌Replace database intensive or inefficient APIs with appropriate index-friendly APIs. Database intensive APIs:
Use API Methods that are index-friendly as appropriate to replace custom logic:
📌Ensure all direct 3rd-party HTTP calls are leveraging Web Service Framework Don’t trigger live calls to external systems on frequently visited pages (homepage, category, or search result pages and product pages). Where live calls are needed, specify a low timeout value (for example, 1 second).
📌A B2C Commerce application server thread waiting for a response from an external system can’t serve other requests. Many threads waiting for responses can make the entire cluster unresponsive, for any pages.
📌Ensure there isn’t unnecessary creation of custom Session objects, productList objects, or cookies.
📌Ensure a WishList isn’t created for every anonymous user (e.g.created at the end of every product item add to cart calls)
📌Don’t execute any long-running operations in a storefront pipeline (for example, import or export). Instead, use “jobs” for all long running tasks. The web tier closes browser connections after 5 minutes. The pipeline could still be running at this time.While developing or performing code review activities the validation can be done via: Check in Pipeline Profiler for any long running operations/scripts. When you wish to perform overall assessment you can ask Salesforce TAM to validate with Salesforce internal tools (e.g. Grafana and AppDynamics)
📌Make sure that the most visited pages are cacheable and well performing. These controllers and pages are usually category page or search result pages (Search-Show), product detail pages (Product-Show), home pages (Default-Start, Home-Show), Cart Page (Cart-Show) and Checkout.
📌When processing large data sets, keep only currently processed objects in memory, and do not retain references to that object. Stream data to file regularly to prevent holding large structures in memory. Read feeds record by record and not the entire file. If you must create multiple feeds, query the objects once and write records to all feeds as you iterate over the results to prevent creation of the same object multiple times. Calculate the Job Load Factor and ensure that it does not supersede 0.20. Calculate the job load factor: total number of seconds of job execution time on an instance (Staging or Production) on a day divided by 86,400 (number of seconds in a day).
Development Guidelines and Limitation
⇨ Don’t store video files which are more than 20MB.
⇨ Custom rendered email templates should be not more than 3MB.
⇨ Search for “552 Error: message too large” error in Log Center
⇨ Custom generated ISML output should not be more than 10MB. Search for “Page size limit of 10 MB exceeded” error in Log Center.
⇨ Check pipeline and script profiler to ensure the runtime does not get near to 30 seconds (30000ms).
DB Transaction handling
Avoid Transactions wrapping bulk processing of objects
Transaction.wrap should be in the processingFunction and not around the bulk processing of the objects. Limit transaction size. The system is designed to deal with transactions with up to 1,000 modified business objects. A storefront pipeline shouldn’t even come close to this number. Search for all usage of Transaction.wrap().
OnRequest & OnSession Hooks
OnRequest & OnSession Hooks called every time, hence we need to make sure that expensive logic has not been included into them. Limit expensive (> 10 ms) custom server logic on OnSession and OnRequest controllers. (Needed only one time at the start of a code review).
Ensure no hardcoding of text & usage of resource bundles are evident. Separate code and localisable assets using resource / property files. Leverage native platform capability: Templates are separated into different locales with folders name as per the locale. Localized templates are sorted within. Resource properties have file names that are appended with the locale code. Search templates in custom code (*.isml) for hard coded text via regex ([“”]>\w+) in VScode.
Closing IO objects
Make sure that all initialized Readers and Writers are being closed. Stream close() must be in finally blocks to ensure they are always executed. Pay attention that all SeekableIterators are closed when done OR ensure all elements have been fetched.
Comply with proper explicit transaction handling. Omit for superfluous Calculate-Cart calls (causes extra basket churn). Excessive calling of calculate.js would cause performance issues as calculate cart is a heavy process. calculate.js is called as a hook, so go to hooks.json to identify the hook name, and then search for the hook name within the code (.”callHook(“))
Make sure that <isactivedatahead> and <isobject> tags have not been removed and are in the correct places so that Active Merchandising data collection will work.
isactivedatahead is required in <head> and in SFRA called at: checkout.isml – At checkout page.isml – On page view pdstorepage.isml pay attention to where <isprint encoding=”off”> is used and that SecureEncoder class is also used: Guidance of using SecureEncoder class Guidance of using isprint.
In general the following encoding can be turned off: Any HTML/code type output – Encoding will change them to non-code format. Values that are generated by a system with no reliance on a user input in places where forms are used, CSRF Protection class should also be used.
Make sure of the presence and proper setting of <iscache> tags in catalog and static pages. Key pages are: Homepage, PLP, PDP, My Cart, Checkout and My Account.
Check for url parameters in category, product, and product tile pipeline requests that contribute negatively to url diversity and thus will reduce the cache hit rates. Ensure static URLs are generated using URLUtils. Use the exclude search function in VSCode to exclude static JS/CSS files.
Be cautious of using getAllCustomObjects and understand if there is a possible alert (amount of COs). Ensure Custom Object volume is kept in check with purge jobs. Be cautious of using createCustomObject usage, especially on the front-end and check the daily/hour creation of new COs. If queryCustomObject is used, validate if it can be replaced with getCustomObject with some changes to the custom object key structure.
Make sure your changes doesn’t bring performance degradation, hence validate script and controller timing for key shopper flows
Don’t use any deprecated APIs. Don’t introduce any quota violations. Always ensure no enforced quota violations are reported and that Quota Dashboard alerts have been subscribed by all site admins (STG and PROD). Don’t introduce error logs. Exceptions to look out for:
- Optimistic Locking
Get in touch with the Technical Account Manager for health review. Check Reports and Dashboards for the Controller Performance and Cache Performance
External helpful resources:
🔗FCC Job Development Best Practices (read more at Job Development for Performance and Stability)