Home Programming Salesforce Platform Enterprise Architecture - Fourth Edition

Salesforce Platform Enterprise Architecture - Fourth Edition

By Andrew Fawcett
ai-assist-svg-icon Book + AI Assistant
eBook + AI Assistant $39.99
Print $49.99
Subscription $15.99
ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription.
ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription. $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime! ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription.
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Along with your eBook purchase, enjoy AI Assistant (beta) access in our online reader for a personalized, interactive reading experience.
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription. ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription. BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime! ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription.
eBook + AI Assistant $39.99
Print $49.99
Subscription $15.99
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Along with your eBook purchase, enjoy AI Assistant (beta) access in our online reader for a personalized, interactive reading experience.
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Building and Publishing Your Application
About this book
Salesforce makes architecting enterprise grade applications easy and secure – but you'll need guidance to leverage its full capabilities and deliver top-notch products for your customers. This fourth edition brings practical guidance to the table, taking you on a journey through building and shipping enterprise-grade apps. This guide will teach you advanced application architectural design patterns such as separation of concerns, unit testing, and dependency injection. You'll also get to grips with Apex and fflib, create scalable services with Java, Node.js, and other languages using Salesforce Functions and Heroku, and find new ways to test Lightning UIs. These key topics, alongside a new chapter on exploring asynchronous processing features, are unique to this edition. You'll also benefit from an extensive case study based on how the Salesforce Platform delivers solutions. By the end of this Salesforce book, whether you are looking to publish the next amazing application on AppExchange or build packaged applications for your organization, you will be prepared with the latest innovations on the platform.
Publication date:
March 2023
Publisher
Packt
Pages
712
ISBN
9781804619773

 

Building and Publishing Your Application

The key to turning an idea into reality lies in the execution. Having the inception of an idea and getting it implemented as an application and into the hands of users is an exciting journey and one that constantly develops and evolves between you and your users. One of the great things about developing on the Salesforce Platform is the support you get from the platform beyond the core engineering phase of the production process.

In this first chapter, we will use the declarative and programmatic tools of the platform to quickly build an initial version of an application that we will use throughout this book. This will give you an opportunity to get some hands-on experience with some of the packaging and installation features that are needed to release applications to your target users. For ISV (Independent Software Vendor) developers, we will also look at the facilities available to publish your Salesforce application through Salesforce AppExchange (equivalent to Apple’s App Store) so that your future customers can find and purchase your application, and finally, how you can provide end user support.

The following topics outline what we will achieve in this chapter:

  • Introducing Salesforce DX
  • Required organizations
  • Introducing the book’s sample application
  • Package types and benefits
  • Creating your first managed package
  • Package dependencies and uploading
  • Supporting package upgradability
  • Introduction to AppExchange and creating listings
  • Installing and testing your package
  • Licensing
  • Supporting your application
  • Becoming a Salesforce partner and the benefits of doing so
  • Customer metrics
  • Trialforce and Test Drive features
  • Package considerations for customers building external integrations
 

Introducing Salesforce DX

Throughout this book, we will be using the Salesforce DX tools. Salesforce provides tools for developers to perform many development and time-saving tasks, such as creating developer environments (known as scratch orgs), creating projects, synchronizing code with source control, creating and managing packages, and much more. In fact, it optimizes and helps you automate the entire application life cycle (ALM) process for your application and package. Throughout this book, you will learn key aspects of this process, starting in this chapter.

We will dive straight into using Salesforce’s command line interface (CLI) along with an integrated development environment (IDE), Microsoft Visual Studio Code (VSCode), for which Salesforce has also created many useful extensions. At the time of publication, Salesforce announced a beta release of Code Builder, which allows you to use Salesforce DX via VSCode from your browser without requiring any location installation, which not only speeds up getting started but also avoids hitting any corporate workstation restrictions you might encounter. You do not need to be an expert in Salesforce DX to complete this book but I do recommend you take the time to complete the basic Trailhead trails, Build Apps Together with Package Development: https://trailhead.salesforce.com/en/content/learn/trails/sfdx_get_started.

Salesforce DX brings with it the second generation of packaging technology for ISVs as well as Enterprise customers building on the Salesforce Platform; this is known as “2GP” for short. Previous editions of this book used the first generation technology (1GP). If you were to compare the experience between the two technologies, you would see that the package creation process using 2GP is now fully automated through the CLI and requires no UI interaction. This is also very advantageous in respect of building further automation around your release pipeline, which will be covered in Chapter 14, Source Control and Continuous Integration. This book focuses on creating new second-generation managed and second-generation unlocked packages. It does not focus on migrating between 1GP and 2GP for existing managed packages.

You can read more about 1GP and 2GP managed packages at https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_build_and_release_your_app.htm.

You can read more about 2GP unlocked packages at https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_unlocked_pkg_intro.htm.

Introducing the new Salesforce Task Driven CLI

Back in 2017, Salesforce introduced its first CLI tool and the commands were executed with sfdx. Since then the Salesforce portfolio of products has grown, and so Salesforce has started a journey to unify all of its developer tools under one experience. The first part of this is a new sf CLI that provides an easy-to-navigate task-driven naming convention with an improved interactive and defaulting experience that requires less memorization of parameters. New platform features such as Salesforce Functions (covered later) are adopting this approach immediately, so related commands are only available through this new sf CLI. This book will thus use a mixture of these new commands and existing ones. Some commands have been re-envisioned in this new CLI, such as creating orgs and deploying to them.

You do not need to do anything to install this new sf CLI experience, as it is bundled with the main sfdx CLI install, and existing sfdx CLI commands, including many used in this book, will all still work fine. Just make sure, as always, you are running the latest CLI by performing the command sfdx –update. These new CLI commands are accessible from a new sf executable, and at the time of writing only cover a subset of the functionality of the sfdx executable – but in the future, will continue to extend to cover those from other Salesforce products. For now, you can use both sets of commands together.

Below you can see the navigation panel for the CLI documentation; you can immediately see the difference in how commands are structured by task versus feature. On the left is the new sf command’s top-level structure, and on the right, the existing sfdx structure:

Figure 1.1: Side-by-side comparison of sf and sfdx structure

In Figure 1.1 you can see the organization of the new sf commands is oriented around the tasks developers perform, while sfdx commands are organized by features. For example, all commands to manage and interact with environments (such as your Salesforce orgs) are under the env namespace, and ways to deploy to environments are under the deploy namespace.

 

Required organizations

Several Salesforce organizations are required to develop and test your application. Salesforce DX allows you to manage many of these organizations as environments. If you are an ISV developer, in due course, as your relationship with Salesforce becomes more formal, you will have the option of accessing their Partner Portal website to create organizations of different types and capabilities. We will discuss this in more detail later.

It’s a good idea to have some kind of naming convention to keep track of the different organizations and logins. As stated earlier, these organizations will be used only for the purposes of learning and exploring in this book:

Username

Usage

Purpose

myapp@namespace.my.com

Namespace

In this org, we will define a unique identifier for our application, called a namespace. You can think of this as a web domain as it is also unique to your application across the Salesforce service. The namespace org must be a Developer Edition org and is free to create at https://developer.salesforce.com/.

myapp@devhub.my.com

Salesforce DX

Salesforce DX requires you to first connect to an org known as the Dev Hub. This org helps Salesforce and you to co-ordinate all the orgs you need for development and testing purposes. I recommend that, for this book, you use the free 30-day trial available at https://developer.salesforce.com/promotions/orgs/dx-signup.

Table 1.1: Creating test organizations

You will have to substitute myapp and my.com (perhaps by reusing your company domain name to avoid naming conflicts) with your own values.

If you are an ISV developer, the following are other organization types that you will eventually need in order to manage the publication and licensing of your application. However, they are not needed to complete the chapters in this book:

Usage

Purpose

Production/CRM Org or Partner Business Org (PBO)

Your organization may already be using this org to manage contacts, Leads, Opportunities, Cases, and other CRM objects. Make sure that you have the complete authority to make changes, if any, to this org since this is where you run your business. If you do not have such an org, you can request one via the Partner Program website described later in this chapter by requesting (via a Case) a CRM ISV org. Even if you choose to not fully adopt Salesforce for this part of your business, this type of org is still required when it comes to utilizing the licensing aspects of the platform. Eventually, when you are ready to develop your package for real, this org will also become your Salesforce DX Dev Hub. For this book, we will use a temporary Dev Hub org as described earlier.

AppExchange Publishing Org (APO)

If you are an ISV developer, this org is used to manage your use of AppExchange. We will discuss this in the Introduction to AppExchange and listings section later in this chapter. This org is actually the same Salesforce org you designate as your production org and is where you conduct your sales and support activities from.

License Management Org (LMO)

If you are an ISV developer, within this organization, you can track who installs your application (as Leads), the licenses you grant them, and for how long. It is recommended that this is the same org as the APO described earlier.

Trialforce Management Org (TMO) and

Trialforce Source Org (TSO)

If you are an ISV developer, Trialforce is a way to provide orgs with your preconfigured application data so that prospective customers can try out your application before buying it. It will be discussed later in this chapter.

Table 1.2: Organization types for ISV developers

Typically, the LMO and APO can be the same as your primary Salesforce production org, which allows you to track all your Leads and future Opportunities in the same place. This leads to the rule of APO = LMO = production org. Though neither of them should be your actual developer or test org, you can work with Salesforce support and your Salesforce account manager to plan and assign these orgs.

Introducing Salesforce Hyperforce

Salesforce products and services run in the cloud; updating and securing that software on your behalf is one of the major benefits of using their services. Much of what goes on behind the scenes to deliver and manage all their code and data (including the Salesforce Platform itself) for you and your users to consume is thankfully hidden from you. When Salesforce first started, it provisioned and managed its own dedicated hardware, and took to creating data centers in different regions around the world as the service grew.

Providing this service comes with a range of costs, notably the hardware itself needs to be purchased, set up, and securely managed within the data center premises. This is on top of the costs to manage the billions of lines of code and terabytes of data. Aside from the costs, choosing a region in which to set up a data center becomes an extremely critical decision when choosing new markets and regions to target next.

General purpose public cloud services, such as AWS, GCP, and Azure have matured a great deal since Salesforce first started business. This has enabled Salesforce to re-evaluate the cost benefit of running its own data centers and physical machines versus using services such as those from AWS to host its own services and products, including Salesforce Platform. Additionally, because the regions supported by such cloud services are much broader and continue to grow. This enables Salesforce to support customers with specific data residency requirements, such as the EU Operating Zone.

While there is still a huge amount of work being done to manage Salesforce services and products, building on the investment made by public cloud services is a big advantage to Salesforce. Salesforce has taken this as an opportunity to create a base infrastructure for all its services and products to move to in the future – creating even more consistency in regional needs and indeed efficiency for their own developers building across their portfolio. At the time of publication, Salesforce still has a mixture of traditional data centers and new Salesforce Hyperforce infrastructure.

What is amazing is that the Salesforce products and Salesforce Platform continue to behave in the same way regardless of the hosting approach. As there are no additional features enabled by running an org on Hyperforce, this book will not go into further detail on Hyperforce. However, do be aware not all of Salesforce’s products, services, and in some cases, features are available. This is a changing situation, of course, so you and/or your customers should work carefully with Salesforce on your product and regional needs. This, however, is only an interim situation, in the future all of Salesforce will run on Hyperforce.

 

Introducing the book’s sample application

For this book, we will use the world of Formula 1 motor car racing as the basis for a packaged application that we will build together. Formula 1 is, for me, the motorsport that is equivalent to enterprise application software, due to its scale and complexity. It is also a sport that I follow. My knowledge of both of these fields helped me when building the examples that we will use.

We will refer to our application as FormulaForce throughout this book, though please keep in mind Salesforce’s branding policies when naming your own application, as they prevent the use of the word “Force” in company or product titles.

This application will focus on the data collection aspects of races, drivers, and their many statistics, utilizing platform features to structure, visualize, and process this data in both historic and current contexts.

Consult the Salesforce CLI documentation if you have not authorized a connection to your Dev Hub org, then run the following commands to create a Salesforce DX project for your application and create a special org known as a scratch org for you to perform your development work in. This org is given the alias dev and set as the project default.

These orgs only last 7 days (by default, the maximum is 30 days) so be sure to synchronize regularly, as described later in this chapter:

sf generate project --name formulaforce
cd formulaforce
sfdx force:org:create 
 --definitionfile config/project-scratch-def.json 
  --setalias dev 
  --setdefaultusername
code .

The preceding code command is used as a convenience to quickly open VSCode in the current directory. From here, you can open the integrated terminal and continue to execute Salesforce DX CLI commands from within the IDE. Additionally, at the time of writing, the new sf env create scratch command was in beta so was not used above, but is an example of Salesforce’s strategy to better arrange and unify its commands.

The .forceIgnore file allows you to control which aspects of the scratch org and your local files are synchronized. Later in this book, in Chapter 2, Leveraging Platform Features, we will cover permission sets as a means to configure security rather than using the less flexible profiles feature. In preparation for this, enter the following into the .forceIgnore file and save it. This stops any unwanted profile changes that you might directly or indirectly make from being synchronized with your project:

# Profiles
 *.profile-meta.xml

The project directory layout created by the sf generate project command automatically includes a /force-app folder. As a convention in this book, we will be using a different directory layout for source code that allows us to contain all the source files for the application experiences and open-source libraries used throughout this book.

To modify the project directory to support this convention, first create a new source folder in the root of the project, then rename the force-app folder to formulaforce before then moving this folder as a sub-folder into the new source folder. Note that the formulaforce folder will contain a default folder with empty directories, and my preference is to delete these and allow them to be created organically as the application development progresses. Finally, update your sfdx-project.json as shown below to let the sfdx CLI know where the source folder has moved to:

{
  "packageDirectories": [
    {
      "path": "source/formulaforce",
      "default": true
    }
  ],
  "namespace": "",
  "sfdcLoginUrl": "https://login.salesforce.com",
  "sourceApiVersion": "56.0"
}

We will revisit the source directory layout of the project later in this chapter. For now, we will create some initial Custom Objects and Fields, as detailed in the following table. Do not worry about creating any custom tabs just yet. You can use your preferred approach for creating these initial objects. Also make sure to select the Allow Search checkbox on the initial screen when creating the following objects. Ensure that you have opened your project’s current scratch org by running the following command:

sfdx force:org:open

From within Visual Studio Code and with your project open, you can use the shortcut key combination Cmd + Shift + P on a Mac or Ctrl + Shift + P on Windows to open the Command Palette. Start typing SFDX Open and you will see the SFDX: Open Default Org command to quickly open your scratch org without typing the preceding command. You can also run other Salesforce DX commands this way, such as creating scratch orgs.

Here is a list of objects along with their field names and types:

Object

Field name and type

Season__c

Name (text)

Race__c

Name (text)

Season (Master Detail Lookup to Season)

Driver__c

Name (text)

Contestant__c

Name (Auto Number CONTEST-{00000000})

Race (Master Detail Lookup to Race)

Driver (Lookup to Driver)

Table 1.3: Custom Objects created in this chapter

The following screenshot shows the preceding objects within the Schema Builder tool, available under the Setup menu:

Graphical user interface  Description automatically generated

Figure 1.2: Custom Objects shown in the Schema Builder

Once you have completed creating the preceding objects, you should synchronize them with your project:

sfdx force:source:pull

This is an important command when using Salesforce DX to ensure you always have the latest changes as a permanent record in file form. Once this command completes the Salesforce CLI will place files representing the objects and corresponding UI layout information within new subdirectories within the /source/formulaforce/main/default folder. This is because the CLI is not sure of the desired final location of such files. You can now move the two new /objects and /layouts sub-folders directly under /source/formulaforce/main folder to confirm their final location. You only need to do this once for new files, once they are moved Salesforce CLI will update them automatically in their new location.

The entire project and the files representing your application can then be stored in source control from this point onward if desired. We will review these files further later.

 

Package types and benefits

A package is a container that holds your application components, such as Custom Objects, Apex code, Apex Triggers, Visualforce pages, Lightning Components, and so on. This makes up your application. While there are other ways to move components between Salesforce orgs, a package provides a container that you can use for your entire application or to deliver optional features by leveraging so-called dependent packages.

Salesforce has evolved its packaging technology and now refers to its legacy packaging technology as 1GP (1st Generation Packaging) and its latest technology as 2GP (2nd Generation Packaging). This book uses 2GP exclusively – keep this in mind when reviewing Salesforce documentation on the packaging.

There are two types of second-generation packages – managed and unlocked. Unlocked packages also result in the installation of components in another org; however, the metadata can be readily modified or even deleted by the administrator of that org. While they can be used for upgrades, changes made in an installation org will be overwritten. Given these attributes, they are not particularly ideal from a support perspective, which also makes managed packages more appropriate for ISVs distributing their application to multiple customers. Moreover, unless you use managed packages, the Apex code that you write is also visible for all to see, so your intellectual property is at risk unless you use managed packages.

Unlocked packages can be used for sharing template components that are intended to be changed by the subscriber. If you are not using GitHub or the GitHub Salesforce Deployment Tool (https://github.com/afawcett/githubsfdeploy), they can also provide a means to share open source libraries with developers.

The features and benefits of managed and unlocked packages

This book was inspired by building packaged applications for distribution on AppExchange, as an ISV developer. However, many of the practices and tips equally apply to building robust and scalable applications within a growing or enterprise-size organization using packages. Where aspects are applicable to one or the other types of development this will be called out.

Managed packages have the following features, which are ideal for distributing your application as an ISV. The org where your application package is installed is referred to as a subscriber org since users of this org subscribe to the services your application provides:

  • Intellectual Property (IP) protection: Users in the subscriber org cannot see your Apex source code, although keep in mind code sent to the client when you use LWC, Visualforce pages, or Static Resources will be visible. If this is a concern for your JavaScript code, you may want to consider using a minify process to partially obscure such code.
  • The naming scope: Your component names are unique to your package throughout the utilization of a namespace. This means that, even if you have object X in your application, and the subscriber has an object of the same name, they remain distinct. You will define a namespace later in this chapter.
  • The governor scope: The code in your application executes within its own governor limit scope (such as DML and SOQL governors, which are subject to passing a Salesforce security review) and is not affected by other applications or code within the subscriber org. Note that some governors, such as the CPU time governor, are shared by the whole execution context (discussed in Chapter 4, Apex Execution and Separation of Concerns), regardless of the namespace.
  • Feature management: Allows you to enable, disable, and track the use of features you create in your application.
  • Analytics: Allows you to receive anonymous data from Salesforce relating to the use of components such as pages and objects in your application. You can use this information, for example, to monitor the adoption of new features you release.

There are other benefits to managed packages, but these are only accessible after becoming a Salesforce partner and completing the security review process; these benefits are described later in this chapter. Salesforce provides ISVforce Guide (otherwise known as the Packaging Guide), in which these topics are discussed in depth – bookmark it now! The ISVforce Guide can be found at https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/.

The following features are applicable to both unlocked and managed packages:

  • Upgrades and versioning: Once subscribers have started using your application, creating data, making configurations, and so on, you will want to provide upgrades and patches with new versions of your application.
  • Explicit Dependency Management: Second-generation packages offer a robust, explicit way to manage dependencies between packages.
 

Creating your first managed package

Packages and subsequent versions are created using Salesforce DX CLI commands. The steps to be performed are:

  1. Setting your package namespace
  2. Creating the package and assigning it to the namespace
  3. Adding components to the package

Not all aspects of the Salesforce Platform can be packaged. To help ensure you are fully aware of what is supported and what is not, Salesforce has created an interactive report known as the Salesforce Metadata Coverage report. This can be found here: https://developer.salesforce.com/docs/metadata-coverage.

These steps will be discussed in the following sections.

Setting and registering your package namespace

An important decision when creating a managed package is the namespace; this is a prefix applied to all your components (Custom Objects, Apex code, Lightning Components, and so on) and is used by developers in subscriber orgs to uniquely distinguish between your packaged components and others, even those from other packages. The namespace prefix is an important part of the branding of the application since it is implicitly attached to any Apex code or other components that you include in your package.

The namespace can be up to 15 characters, though I personally recommend that you keep it to less than this, as it becomes hard to remember and leads to frustrating typos if you make it too complicated. I would also avoid the underscore character. It is a good idea to have a naming convention if you are likely to create more managed packages in the future. The following is the format of an example naming convention:

[company acronym - 1 to 4 characters][package prefix 1 to 4 characters]

For example, if ACME was an ISV, the ACME Corporation’s Road Runner application might be named acmerr. You may want to skip prefixing with your company acronym when considering a namespace for an application package internal only to your business.

Log in to the namespace org discussed earlier in this chapter. Navigate to the Packages page (accessed under the Setup menu, under the Create submenu). Click on the Edit button to begin a short wizard to enter your desired namespace. This can only be done once and must be globally unique (meaning it cannot be set in any other org), much like a website domain name.

Assigning namespaces

For the purposes of following along with this book, please feel free to make up any namespace you desire; for example, fforce{yourinitials}. Do not use one that you may plan to use in the future, since once it has been assigned, it cannot be changed or reused.

The following screenshot shows the Packages page:

Graphical user interface, text, application, email  Description automatically generated

Figure 1.3: Packages page accessed from the Setup menu

Once you have set the namespace, the preceding page should look like the following screenshot, with the difference being that it is now showing the namespace prefix that you have used and that managed packages can now also be created. You are now ready to create a managed package and assign it to the namespace:

Graphical user interface, text, application  Description automatically generated

Figure 1.4: Packages page after setting the namespace

You can now log out from the namespace org – it is no longer needed from this point on. Log in to your Dev Hub org and register your namespace with Salesforce DX. This allows you to create scratch orgs that use that namespace, allowing you to develop your application in a way that more closely represents its final form. Salesforce provides an excellent guide on registering your namespace at https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_reg_namespace.htm.

Creating the package and assigning it to the namespace

Return to VSCode and edit your sfdx-project.json file to reference the namespace:

{
    "packageDirectories": [
        {
            "path": "source/formulaforce",
            "default": true
        }
    ],
    "namespace": "fforce",
    "sfdcLoginUrl": "https://login.salesforce.com",
    "sourceApiVersion": "56.0"
}

The sample code associated with each chapter of this book does not reference any namespace in the sfdx-project.json file. If you want to continue using your namespace after you have refreshed your project for a given chapter, you must repeat the preceding edit with your own namespace. It is generally good practice to develop using the namespace of your package as it is closer to the final installed state of your code and thus will ensure any bugs related to namespace handling are identified earlier.

To create your package and register it with your Dev Hub, run the following command:

sfdx force:package:create 
  --name "FormulaForce App" 
  --description "FormulaForce App" 
  --packagetype Managed 
  --path force-app

Once the command completes, review your sfdx-project.json file again; it should look like the example that follows. In the following example, the ID starting with 0Ho will vary:

{
    "packageDirectories": [
        {
            "path": "source/formulaforce",
            "default": true,
            "package": "FormulaForce App",
            "versionName": "ver 0.1"
            "versionNumber": "0.1.0.NEXT",
            "versionDescription": "FormulaForce"
        }
 ],
 "namespace": "fforce",
 "sfdcLoginUrl": "https://login.salesforce.com",
 "sourceApiVersion": "56.0",
 "packageAliases": {
    "FormulaForce App": "0Ho6A000000CaVxSAK"
 }
}

Salesforce DX records your package and package version IDs here with aliases that you can edit or leave as the defaults. These aliases are easier to recall and understand at a glance when using other Salesforce CLI commands relating to packages. For example, the sfdx force:package:install CLI command supports an ID or an alias.

Adding components to the package

In this book, the contents of your project’s /source/formulaforce package directory folder will become the source of truth for the components that are included in each release of your package. The following layout shows what your application should look like in source file form so far:

├── LICENSE
├── README.md
├── config
│   └── project-scratch-def.json
├── sfdx-project.json
└── source
    └── formulaforce
        └── main
            ├── layouts
            │   ├── Contestant__c-Contestant\ Layout.layout-meta.xml
            │   ├── Driver__c-Driver\ Layout.layout-meta.xml
            │   ├── Race__c-Race\ Layout.layout-meta.xml
            │   └── Season__c-Season\ Layout.layout-meta.xml
            └── objects
                ├── Contestant__c
                │   ├── Contestant__c.object-meta.xml
                │   └── fields
                │       ├── Driver__c.field-meta.xml
                │       └── Race__c.field-meta.xml
                ├── Driver__c
                │   └── Driver__c.object-meta.xml
                ├── Race__c
                │   ├── Race__c.object-meta.xml
                │   └── fields
                │       └── Season__c.field-meta.xml
                └── Season__c
                    └── Season__c.object-meta.xml

You can consider creating multiple dependent packages from within one project by using different package directory folders for each package. Each package can share the same namespace or choose another. By default, code is not visible between packages unless you explicitly mark it as global, a concept discussed later in this book. To make code accessible only between your own packages (sharing the same namespace) and not your customers, use the @namespaceAccessible annotation rather than the global keyword. We will discuss dependent packages later in this chapter.

To create the first release of your package, run the following command (all on one line):

sfdx force:package:version:create 
  --package "FormulaForce App" 
  --definitionfile config/project-scratch-def.json 
  --wait 10 –– installationkeybypass
  --codecoverage

Some things to note about the previous command line parameters are as follows:

  • The --package parameter uses the package alias as defined in the sfdx-project.json file to identify the package we are creating this version against. You can avoid using this attribute if you apply default: true to the package as defined in the sfdx-project.json file.
  • The --wait parameter ensures that you take advantage of the ability of the command to update your sfdx-project.json file with the ID of the package version.
  • --installationkeypass is needed to ensure you agree to the fact that the package can be installed by anyone that has the ID. For your real applications, you may want to include a password if you feel there is a risk of this information being exposed.
  • --codecoverage is needed to calculate the minimum of 75% code coverage in order to promote this package to release status. Even though there is no code in the package at this point, this flag is still required. If you are creating a package version only for beta testing purposes, this flag is not required, however, you will not be able to promote the package version to the Release status required to install the package in customers’ or your own production orgs. Beta and Release package types are discussed later in this chapter in more detail.

At this stage in the book, we have simply added some Custom Objects, so the process of creating the package should be completed reasonably quickly. Once the preceding command completes, your sfdx-project.json file should look like the following. Again, the IDs will vary from the ones shown here – each time you create a new version of your package, it will be recorded here:

{
    "packageDirectories": [
        {
            "path": "source/formulaforce",
            "package": "FormulaForce App",
            "versionName": "ver 0.1",
            "versionNumber": "0.1.0.NEXT",
            "versionDescription": "FormulaForce App",
            "default": true
        }
    ],
    "namespace": "fforce",
    "sfdcLoginUrl": "https://login.salesforce.com",
    "sourceApiVersion": "55.0",
    "packageAliases": {
        "FormulaForce App": "0Ho6A000000CaVxSAK",
        "FormulaForce App@0.1.0-1": "04t6A0000038K3GQAU"
    }
}

The NEXT keyword is used in the preceding versionNumber configuration to automatically assign a new version number each time a new package version is created.

Dependent packages

As their name suggests, dependent packages extend or add to the functionality delivered by the existing packages they are based on, though they cannot change the base package contents. They can extend one or more base packages, and you can even have several layers of extension packages, though you may want to keep an eye on how extensively you use this feature, as managing inter-package dependency can get quite complex, especially during development and deployment when using features such as Push Upgrade.

If you want to use dependent packages to control access to features of your application you want to sell as add-ons, for example, then you might want to consider the Feature Management feature. In this case, you would still package all of your application in one package but selectively hide parts of it through Feature Parameters.

Dependent packages are created in much the same way as the process you’ve just completed, except that you must define the dependent package in the sfdx-project.json file (shown as follows) and ensure the scratch org has those base packages installed in it before use. The following is an example sfdx-project.json file showing a package dependency for a new dependent package that is currently in development:

{
    "packageDirectories": [
        {
            "path": "source/formulaforceaddons",
            "package": "FormulaForce - Advanced Analytics Addon",
            "default": true,
            "dependencies": [
                {
                   "package": "FormulaForce App@0.1.0-1"
                }
            ]
        }
    ],
    "namespace": "fforce",
    "sfdcLoginUrl": "https://login.salesforce.com",
    "sourceApiVersion": "56.0",
    "packageAliases": {
        "FormulaForce App@0.1.0-1": "04t6A012003AB3GQAU"
    }
}

The project containing the preceding example configuration only contains the dependent package components, since there is only one packageDirectories entry. In this case, the base package is developed in a separate project. However, as noted earlier, you can have multiple packages within a single Salesforce project. This does have the benefit of being able to work on both base and dependent packages together in one scratch org. However, it requires more careful management of the default package directory setting when performing synchronization operations. As shown later in this chapter, you can manually install any package in a scratch org, either via the browser with the package install URL or via the SFDX CLI. If a package takes a long time to install and configure, you may want to consider using the Scratch Org Snapshots feature, especially if you are building a CI/CD pipeline, as described later in this book, in Chapter 14, Source Control and Continuous Integration. Typically, a scratch org is empty when you create it; however, with this feature, you can have it include pre-installed base packages and related configuration or data.

As the code contained within dependent packages makes reference to other Custom Objects, Custom field, Apex code, and so on that are present in base packages, the platform tracks these dependencies and the version of the base package present at the time the reference was made. When an dependent package is installed, this dependency information ensures that the installation org has the correct version (minimum) of the base packages installed before permitting the installation of the dependent package to complete.

The preceding sections have described the package creation process, including the ability to create other dependent packages to allow you to deploy parts of your application that are applicable to only a subset of your customers, for example, for a given market. The following sections introduce concepts that require more understanding before you release your package to your target customers. Some of these things cannot be reverted.

 

Package platform feature dependencies

Packages can have dependencies on platform features and/or other packages (as previously described). While some features of Salesforce are common, customers can purchase different editions and features according to their needs. Scratch orgs have access to most of these features for free. This means that, as you develop your application, it is important to understand when and when not to use those features (this is done in order to avoid unwanted dependencies that might block or inhibit the adoption of your application).

When referencing a certain Standard Object, field, or component type, you will make a prerequisite dependency on your package, which your customers will need to have before they can complete the installation. Some Salesforce features, for example, Multi-Currency or Chatter, have either a configuration or, in some cases, a cost impact on your users (different org editions). Carefully consider which features your package is dependent on.

As a best practice, to ensure you are targeting the intended features, update your scratch org configuration file and configure it to enable only the desired edition and platform features you wish to be dependent on. You may also want to have multiple scratch org configuration files for different testing purposes, especially if your application code has different code paths depending on a platform feature being enabled or not (as described later in this chapter).

The following example scratch org configuration file enables features relating to Enterprise Edition and, in addition, enables the Multi-Currency feature:

{
    "orgName": "FormulaForce App Testing with Multi Currency",
    "edition": "Enterprise",
    "features": ["MultiCurrency"]
}

You can also configure various settings through scratch org configuration files, such as the Case and Account settings found under the Setup menu. This can help further emulate your customers’ own org configurations and thus improve the accuracy of your testing. For more information, see the Salesforce Help topic at https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_def_file_config_values.htm.

Later in this book, we will be discussing Lightning Components. If you are packaging these, you will be implicitly imposing the need for your customers to utilize the Salesforce My Domain feature. This is not enforced at installation time, so it is an optional dependency. However, users will not be able to use your packaged Lightning Components without first enabling and configuring My Domain.

Release and Beta packages

Once you have created your package, it’s good practice to do further testing (sometimes called regression and/or acceptance testing) internally and/or with a selection of customers. This testing may result in the need to make changes that would normally be blocked if the package version had been installed in production. To give you the ability to do further testing and still make changes, packages are either in Beta or Release state, as described here:

  • Release: Release packages can be installed in production orgs and can also provide an upgrade path from previous releases. The downside is that you cannot delete the previously released components, or change certain things, such as a field’s type. Changes to components that are marked global, such as Apex code methods and Lightning Component attributes, are also restricted. While Salesforce is enhancing the platform to provide the ability to modify certain released aspects, you need to be certain that your application release is stable before selecting this option.
  • Beta: Beta packages cannot be installed in production orgs; you can install them only in other scratch orgs, sandbox, or Partner Portal-created orgs. Also, Beta-managed packages cannot be upgraded once installed; this is the reason why Salesforce does not permit their installation in production orgs. The key benefit is in the ability to continue to change new components of the release, to address bugs and features relating to user feedback, after which, you can create another Beta version. Note that Beta unlocked packages can be upgraded.

Package versions are, by default, in Beta state. In order to promote them to Release, you need to run the following SFDX CLI command:

sfdx force:package:version:promote 
  --package "FormulaForce App@0.1.0-1"

Using the command force:package:version:delete, you can delete your package even if it has been promoted to release.

Optional package dependencies

It is possible to make some Salesforce features and/or base package component references (Custom Objects and Fields) optional aspects of your application. There are two approaches to this, depending on the type of feature.

Dynamic bindings

For example, the Multi-Currency feature adds a CurrencyIsoCode field to standard and Custom Objects. If you explicitly reference this field, for example, in your Apex code, Lightning pages, or components, you will incur a hard dependency on your package. If you want to avoid this and make it a configuration option (for example) in your application, you can utilize dynamic Apex and Visualforce. Lightning value bindings are dynamic in nature, though the aura:attribute element type references will form a compile-time reference to the specified objects.

Dependent packages

If you wish to package component types that are only available in installation orgs of certain editions, you can choose to include these in dependent packages. For example, you may wish to support the Professional Edition, which does not support record types. In this case, create an Enterprise Edition dependent package (as outlined above) for your application’s functionality, which leverages the functionality from this edition.

Note that you will need multiple scratch org configurations and partner testing orgs for each combination of features that you utilize in this way to effectively test the configuration options or installation options that your application requires.

 

Supporting package upgradability

Having just created and released your package, you can start to share it with your customers. Later in this chapter, we will discuss ways to list your package and install it. Before we get too far ahead though, let’s first consider a very important aspect of managing your package – upgradability. As customers embrace your application, they will customize its features and APIs and expect them to continue working even after upgrades to the latest version.

Upgrading a package is as simple as installing the new version over an existing version (we will do this in the next chapter). The Salesforce Platform manages package upgrades for you, without asking users to log out of the system or experience any interruption.

Salesforce second-generation managed and unlocked packages have built-in support for upgradability and also help remove a lot of the traditional pain of ensuring you do not accidentally make breaking changes to your application or even, in most cases, worrying about writing upgrade scripts. For example, it will prevent you from deleting a Custom Object or field that has previously been included in a released package or modifying an Apex global class or method.

Managing package ancestry

Managing ancestry lineage is a feature of second-generation managed packages, if you are not an ISV developer or are using the unlocked package type you can skip to the Installing and testing your package section later in this chapter to understand more about installing your package for testing.

A package version ancestry is the lineage a valid upgrade path takes; in a simple case, this might be v1.0 to v1.1 to v1.2, and so on. In this case, the ancestor of v1.2 is v1.1 and the ancestor of v1.1 is v1.0, meaning that customers can upgrade from v1.0 to v1.1 or even from v1.0 straight to v1.2. We will follow this simple serial ancestry lineage as we build out the package throughout this book. That way, you will see the value of package upgradability. In a more complex scenario, you may decide to split your upgrade paths if you decide to take a radically different direction with the product for new customers. In which case, you might start a new upgrade path like so: v1.1 | v1.2 | v2.0. This obviously needs very careful consideration but does allow you more freedom should you need it.

The ancestorId or ancestorVersion configurations within the sfdx-project.json file define the ancestry for the package version you are currently developing in your scratch orgs. We will explore what effect this has on developing in a scratch org later. This configuration also denotes the desired upgrade path during package creation, as described previously.

You can only define an ancestor of your next version based on an already released version of your package. In this chapter, we will use ancestorVersion with the value of HIGHEST, which is recommended by Salesforce as the simplest approach to following a linear package release path. If you want to base your next package version on a different ancestor, you must use an explicit alias name or ID.

Add the ancestorVersion configuration to the sfdx-package.json file as shown here:

{
 "packageDirectories": [
   {
     "path": "source/formulaforce",
     "package": "FormulaForce App",
     "versionName": "ver 1.1",
     "versionNumber": "1.1.0.NEXT"
     "versionDescription": "FormulaForce App",
     "ancestorVersion": "HIGHEST",
     "default": true
   }
 ],
 "namespace": "fforce",
 "sfdcLoginUrl": "https://login.salesforce.com",
 "sourceApiVersion": "55.0",
 "packageAliases": {
   "FormulaForce App": "0Ho6A000000CaVxSAK",
   "FormulaForce App@0.1.0-1": "04t6A0000038K3GQAU"
 }
}

Each time you release a version of your package, you must check the preceding process to ensure the intended ancestor is the one you want and make sure the versionName and versionNumber reflect the correct values for your next release. This is a significant part of your release process so be sure to document it carefully along with your other release management tasks.

If you want to create a package version that has no link to past releases, because you want to intentionally create a new lineage that allows you to make more changes to your packages not otherwise permitted, such as renaming components, then you can use the --skipancestorcheck parameter when creating the package. However, keep in mind customers will not be able to upgrade to this version from any prior versions – it is effectively a brand-new package lineage.

You can use the following command to display package ancestry for a given package release. An example output after releasing two more package versions is shown below:

sfdx force:package:version:displayancestry --package "FormulaForce App@2.1.0-1"
2.1.0.2 -> 1.1.0.1 -> 0.1.0.2 (root)

Don’t worry if you forget to manage ancestry throughout the rest of this book as you are only building a sample application and aren’t sharing it with users who will care about upgrades.

For package versions created without ancestry, you will have to either use a new test scratch org to install the new release or uninstall a previous version from an existing test org. This is because the platform will not permit an upgrade to a package already installed in an org if the package being installed does have valid ancestry information, even if it shares the same namespace.

Developing in scratch orgs containing ancestry information

Next time you create a scratch org, you will notice that aspects of the Setup menu are now aware that certain components have been previously released to your customers and will block certain operations that would break upgradability, such as changing the API name or deletion. The following screenshot shows an example of such a notification:

Graphical user interface, text, application, email  Description automatically generated

Figure 1.5: Notification that the ability to edit attributes is limited

Of course, there is nothing stopping you from deleting a source file in your local copy of the package that is representing a previously released component, for example, the Team__c folder. If you try this, however, you will get an error during package creation. Either way, when you maintain ancestry information in your sfdx-package.json file, the system protects you from accidental or intentional breaking changes being made to your upgrade path.

If you want to create a scratch org without ancestry information, you can use the --noancestors parameter on the sfdx force:org:create command. This can be useful when creating test orgs (which cannot have the same namespace as installed packages). Finally, keep in mind that the preceding enforcement, when developing in a scratch org with ancestry defined, is advantageous to identify upgrade-breaking changes early in the release cycle. You may want to skip managing ancestry for this book, though it should be considered a good practice when developing for real.

 

Becoming a Salesforce partner and the benefits of doing so

As an ISV, the Salesforce Partner Program has many advantages. The first place to visit is https://partners.salesforce.com/. You will want to focus on the areas of the site relating to becoming an AppExchange Partner. Click on Becoming a Partner to get started. It is free to join, though you will want to read through the various agreements carefully, of course.

Once you wish to start listing a package and charging users for it, you will need to arrange billing details for Salesforce to take the various fees involved. While this book is not equipped to go into the details, do pay careful attention to the Standard Objects used in your package, as this will determine the license type required by your users and the overall cost to them, in addition to your charges.

For example, integrating with CRM objects that existing Salesforce customers are already using, such as Account, Contact, and Opportunity objects can be beneficial to you as a feature of your application, since it’s an appealing, immediate, and seamless integration not found on other platforms without further configuration or even, in some cases, coding effort.

If you’re planning on using Standard Objects, and are in doubt about the costs (as they do vary depending on the type), you can request a conversation with Salesforce to discuss this; this is something to keep in mind in the early stages.

Make sure, when you associate a Salesforce user with the Partner Community, you utilize a user that you use daily (known as your Partner Business Org user) and not one from a development or test org. Once you have completed the signup process, you will gain access to the Partner Community. The following screenshot shows what the current Partner Community home page looks like. From here, you can access many useful services:

Figure 1.6: Navigation options on the Partner Community home page

This is your primary place to communicate with Salesforce and access additional materials and announcements relevant to ISVs, so do keep checking it often. You can raise Cases and provide additional logins to other users in your organization, such as other developers who may wish to report issues or ask questions.

Security review and benefits

The features described in this section are only available once your managed package has gone through a Salesforce-driven process known as a security review, which is initiated via your listing when logged into AppExchange. Unless you plan to give your package away for free, there is a charge involved in putting your package through this process.

While the review is optional and there is nothing stopping you from distributing your package installation URL directly, keep in mind that Salesforce displays a banner during installation and, once installed, it informs admins that the package has not gone through a security review. Furthermore, you will not be able to benefit from the ability to list your new application on AppExchange for others to see and review. More importantly, you will also not have access to the following features to help you deploy, license, and support your application. The following is a list of the benefits you get once your package has passed the security review:

  • Bypass installation org setup limits: Limits such as the number of tabs and Custom Objects are bypassed. This means that if the installation org has reached its maximum number of Custom Objects, your package will still install. This feature is sometimes referred to as Aloha. Without this, your package installation may fail. You can determine whether Aloha has been enabled via the Subscriber Overview page that comes with the LMA application, which is discussed in the next section.
  • Licensing: You are able to utilize the Salesforce-provided License Management Application (LMA) and Feature Management Application (FMA) in your LMO.
  • Subscriber support: With this feature, users of a managed package in the subscriber org can enable, for a specific period, a means for you to log in to their org (without exchanging passwords), reproduce issues, and enable much more detailed debug information, such as Apex stack traces. In this mode, you can also see custom settings that you have declared as protected in your package, which is useful for enabling additional debug or advanced features.
  • Push upgrade: Using this feature, you can automatically apply upgrades to your subscribers without their manual intervention, either directly through the Push UI, on a scheduled basis, or via the Push API. You may use this for applying either smaller bug fixes that don’t affect Custom Objects or APIs or for deploying full upgrades. The latter requires careful coordination and planning with your subscribers to ensure that changes and new features are adopted properly. This feature is also available to unlocked packages.
  • Usage Metrics: This feature provides additional analytics on how customers are using your application, such as the objects they are using and the parts of the user interface they are accessing. Your Product Management team can use this to drive roadmap priorities and track the adoption of new features.

    Salesforce asks you to perform an automated security scan of your software via a web page (http://security.force.com/security/tools/forcecom/scanner). This service can be quite slow depending on how many scans are in the queue. Another option is to obtain the Eclipse plugin from the actual vendor, CheckMarx, at http://www.checkmarx.com, which runs the same scan but allows you to control it locally or via your Continuous Integration (CI) build system. There are a number of code analysis tools now available for Apex, such as the open source project PMD, which includes rules for security and other code quality checks: https://pmd.github.io/latest/pmd_rules_apex.html. There is also the Salesforce Code Analyzer plugin (SFCA) that makes it easier to work with PMD rules for APEX: https://forcedotcom.github.io/sfdx-scanner.

This book focuses on building a fully native application; as such, additional work involved in so-called “hybrid” applications (where parts of your application have been implemented on your own servers, for example) is not considered here. However, keep in mind that if you make any callouts to external services, Salesforce will also most likely ask you and/or the service provider to run a BURP scanner, to check for security flaws.

Make sure you plan a reasonable amount of time to go through the security review process; it is essential that you initially list your package, though if it becomes an issue, you have the option of issuing your package install URL directly to initial customers and early adopters.

Creating test and demo orgs via the Environment Hub

Partners can use the Environment Hub to create orgs for further testing or demo purposes. Orgs can be linked and logins can be managed here as well. Unlike scratch orgs you can get from the Dev Hub, these orgs have additional user licenses. It is also possible to link your Trailforce Source Org (TSO) and create orgs based on templates you define, allowing you to further optimize the base org configuration for your own further testing and demo needs. For more information, review the documentation detailing the Environment Hub (https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/environment_hub_intro.htm).

 

Introduction to AppExchange and listings

Salesforce provides a website referred to as AppExchange, which lets prospective customers find, try out, and install applications built using the Salesforce Platform. Applications listed here can also receive ratings and feedback. You can also list your mobile applications on this site.

In this section, I will be using an AppExchange package that I already own. The package has already gone through the process to help illustrate the steps that are involved. For this reason, you do not need to perform these steps at this stage in the book; they can be revisited at a later phase in your development, once you’re happy to start promoting your application.

Once your package is known to AppExchange, each time you release your package (as described previously), you effectively create a private listing. Private listings are not visible to the public until you decide to make them so. This gives you the chance to prepare any relevant marketing details and pricing information while final testing is completed. Note that you can still distribute your package to other Salesforce users or even early beta or pilot customers without having to make your listing public.

In order to start building a listing, you need to log in to the Partner Community and click the Publishing tab in the header. This will present you with your Publishing Console. Here, you can link and manage Organizations that contain your Packages, create Listings, and review Analytics regarding how often your listings are visited:

Graphical user interface, application  Description automatically generated

Figure 1.7: Creating a listing from the Publishing Console

On the Publishing Console, click the New Listing button and complete the steps shown in the wizard to associate the packaging org with AppExchange; once completed, you should see it listed.

It’s really important that you consistently log in to AppExchange using your APO user credentials. Salesforce will let you log in with other users. To make it easy to confirm, consider changing the user’s display name to something like MyCompany Packaging. The required fields before publishing a listing can be seen below:

Graphical user interface, application  Description automatically generated

Figure 1.8: Editing listing title, tagline, and description before publishing

Though it is not a requirement to complete the listing steps, unless you want to try out the process yourself to see the type of information required, you can delete any private listings that you have created after you complete this book.

 

Installing and testing your package

There are two ways to install your package: through the browser’s user interface with clicks or through the SFDX CLI—a more automated experience. For this chapter, we will use the browser user interface to get a better impression of what your end users will see (assuming you permit them to do the install themselves). In the next section, the SFDX CLI path will be discussed.

When you created your package version earlier in this chapter, you should have received an email with a link to install the package. If not, find the 04t ID that was added to your sfdx-project.json file during the package version build. If you need a list of all of the package versions, you could execute the command sfdx force:package:version:list --package fforce and that will show you all of the package versions for the fforce package. Take that 04t ID and apply it to the end of the following URL:

https://login.salesforce.com/packaging/installPackage.apexp?p0=

Do not attempt to install your package in your project’s current default scratch org where you developed the package. Instead, let’s create a new scratch org for test purposes and open it to perform the install via the browser. Note that we are reusing the same scratch org configuration but you may want to have different configurations for testing:

sfdx force:org:create 
  --definitionfile project-scratch-def.json 
  --setalias test 
  --noancestors
  --nonamespace
sfdx force:org:open -u test

Here are some things to note about the preceding command line parameters:

  • The --setalias parameter defines an alias for this org as test; conversely, we used dev for the alias for the scratch org used to develop the package. This now means that you can easily open either org directly by just using the alias, without having to remember any user name or password. Note that the -s / --setdefaultuser parameter is not used here so the dev scratch org remains the default for synchronization.
  • The --noancestors and --nonamespace parameters disable the standard behavior to have the scratch org inherit the namespace and ancestry behavior we discussed earlier. These are not needed to create scratch orgs for testing package installs.

Once the test scratch org opens, paste the preceding installation link into your browser. The installation process will start. A compact view of the initial installation page is shown in the following screenshot; click on the Continue button and follow the default installation prompts to complete the installation:

Graphical user interface, application  Description automatically generated

Figure 1.9: Installation page for a package

If your package has not gone through a Salesforce Security Review, as described earlier in this chapter, you will see a banner informing the user of this fact. This banner is also visible when users review installed packages under the Setup menu.

Package installation covers the following aspects (once the user has entered the package password, if one was set):

  • Package overview: The platform provides an overview of the components that will be added or updated (if this is an upgrade) to the user. Note that, due to the namespace assigned to your package, these will not overwrite existing components in the subscriber org created by the subscriber.
  • Connected App and Remote Access: If the package contains components that represent connections to the services outside of the Salesforce services, the user is prompted to approve these.
  • Approve Package API Access: If the package contains components that make use of the client API (such as JavaScript code), the user is prompted to confirm and/or configure these. Such components will generally not be called much; features such as JavaScript Remoting are preferred, and they leverage the Apex runtime security configured post-installation.
  • Security configuration: In this step, you can determine the initial visibility of the components being installed (objects, pages, and so on), selecting admin only or the ability to select the profiles to be updated. This option predates the introduction of permission sets, which permit post-installation configuration.

If you package profiles in your application, the user will need to remember to map these to the existing profiles in the subscriber org, as per step 2. This is a one-time option, as the profiles in the package are not actually installed, only merged. I recommend that you utilize permission sets to provide security configurations for your application. These are installed and are much more granular in nature.

When the installation is complete, navigate to the Installed Packages menu option under the Setup menu. Here, you can see confirmation of some of your package details, such as the namespace and version, as well as licensing details, which will be discussed later in this chapter.

It is also possible to provide a Configure link for your package, which will be displayed next to the package when installed and listed on the Installed Packages page in the subscriber org. Here, you can provide a Visualforce page to access configuration options and processes, for example. If you have enabled Seat based licensing, there will also be a Manage Licenses link to determine which users in the subscriber org have access to your package components, such as tabs, objects, and Visualforce pages. Licensing, in general, is discussed in more detail later in this chapter.

Automating package installation

It is possible to automate package installation using the Salesforce CLI. This can be useful if you want to automate the deployment of your packages to scratch orgs and/or other test orgs created as part of a continuous integration (CI) pipeline (as discussed in Chapter 14, Source Control and Continuous Integration). Run the following commands within the project directory (or VSCode Terminal pane).

The first command will first create a new scratch org, as described in the previous section; the next command will run the install command; and finally, the third command will open the test scratch org, where you can confirm via the Setup | Installed Packages menu item that the package has been installed:

sfdx force:org:create 
  --definitionfile project-scratch-def.json 
  --setalias test 
  --noancestors
  --nonamespace
sfdx force:package:install 
  --package "FormulaForce App@0.1.0-1" 
  --publishwait 10 
  --wait 10
  --targetusername test
sfdx force:org:open -u test

Note that the installation will also upgrade a package if the package is already installed. A few things to note about the preceding sfdx force:package:install parameters are as follows:

  • The --publishwait parameter ensures that the command waits for any final background processing to complete before your package can be installed.
  • The --package parameter uses the package alias defined in the sfdx-project.json file. This parameter can take the 04t ID as well (this is useful if the command is not run within the project directory).
  • The --targetusername parameter uses the test scratch org alias to explicitly define which scratch org to install the package in since the creation of the scratch org (via the preceding command) did not overwrite the default scratch org.

The SFX CLI can also list packages installed in an org, for example, if you wanted to determine whether a dependent package needs to be installed or upgraded before running the preceding CLI. Finally, you can also uninstall packages if you wish.

 

Understanding how to license your package

Once you have completed the security review, you are able to request access to the LMA by raising support Cases via the Partner Portal. Once this access is provided by Salesforce, use the installation URL to install it like any other package in your LMO.

If you have requested a CRM for ISVs org (by raising a case in the Partner Portal), you may find the LMA already installed.

The following screenshot shows the License Management Application once installed:

Graphical user interface, text, application  Description automatically generated

Figure 1.10: License Management Application shown on the App Launcher

Since it is not possible to execute this process for the sample package you have created, I will use a package that I have taken through the process in the past, to help illustrate the steps that are involved. For this reason, you do not need to perform these steps.

After completing the installation, return to AppExchange and log in. Then, locate your listing in Publisher Console under Uploaded Packages. Next to your package, there will be a Manage Licenses link. After clicking on this link for the first time, you will be asked to connect your package to your LMO org. Once this is done, you will be able to define the license requirements for your package.

The following example shows the license for a free package, with an immediately active license for all users in the subscriber org:

Graphical user interface, text, application, email  Description automatically generated

Figure 1.11: Option for a default active license in the license settings

In most cases regarding packages that you intend to charge for, you would offer a free trial, rather than setting the license default to active immediately. For paid packages, select a license length, unless perhaps it’s a one-off charge, and then select the license that does not expire. Finally, if you’re providing a trial license, you need to carefully consider the default number of seats (users); users may need to be able to assign themselves different roles in your application to get the full experience.

While licensing is currently expressed at a package level, it is very likely that more granular licensing around the modules or features in your package will be provided by Salesforce in the future. This will likely be driven by the permission sets feature. As such, keep in mind a functional orientation to your permission set design.

If you configure a number of seats against the license, then the Manage Licenses link will be shown on the Installed Packages page next to your package. The administrator in the subscriber org can use this page to assign applicable users to your package. The following screenshot shows how your installed package looks to the administrator when the package has licensing enabled:

Figure 1.12: Installed package with enabled licensing

Note that you do not need to keep reapplying the license requirements for each version you upload; the last details you defined will be carried forward to new versions of your package until you change them. Either way, these details can also be completely overridden on the License page of the LMA application.

You may want to apply a site-wide (org-wide) active license to extensions or add-on packages. This allows you to at least track who has installed such packages, even though you don’t intend to manage any licenses around them since you are addressing licensing on the main package.

The Licenses tab and managing customer licenses

The Licenses tab provides a list of individual license records that are automatically generated when users install your package in their orgs. Salesforce captures this action and creates the relevant details, including Lead information. This also contains the contact details of the organization and the person who performed the installation, as shown in the following screenshot:

Graphical user interface, application  Description automatically generated

Figure 1.13: Lead information shown on the Licenses tab

From each of these records, you can modify the current license details to extend the expiry period or disable the application completely. If you do this, the package will remain installed with all of its data. However, none of the users will be able to access the objects, Apex code, or pages, not even the administrator. You can also re-enable the license at any time. The following screenshot shows the Details section:

Graphical user interface, text, application, email  Description automatically generated

Figure 1.14: Details section for a selected license

The Feature Parameters tab and managing features

Feature Management allows you to hide your application features (programmatically) and/or objects contained in your package until the user wants to use them or you have elected to enable them after purchase. Additionally, it allows you to embed tracking into your application logic to gather statistics such as when the user first used a feature or how often it was used. In order to use this feature, you need to install the Feature Management Application (FMA) (also available via a Salesforce Support Case) in your LMO. Once installed, the Feature Parameters tab allows you to view and manage the values of feature parameters embedded in your package.

The following example from one of my own test packages shows three parameters of varying data types that help track feature usage (Subscriber to LMO). You can read more about this use case at https://github.com/afawcett/fmfc. You can also create feature parameters that allow you to push values to subscriber orgs and thus remotely enable features (LMO to Subscriber) via code paths in your UI and Apex code that reference the same feature parameter:

Graphical user interface, application  Description automatically generated

Figure 1.15: Details shown on the Feature Parameters tab

There is extensive information on how to use Feature Management in the ISVForce Guide, which you can refer to at https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/fma_manage_features.htm.

The Subscribers tab

The Subscribers tab lists all your customers or subscribers (it shows their Organization Name from the company profile) that have your packages installed (only those linked via AppExchange). This includes their Organization ID, Edition (Developer, Enterprise, or others), and also the type of instance (sandbox or production). You can view this here:

Figure 1.16: Searchable list of subscriber organizations on the Subscribers tab

The Subscriber Overview page

When you click on Organization Name from the list in this tab, you are taken to the Subscriber Overview page. This page is sometimes known as the Partner Black Tab. This page is packed with useful information, such as the contact details (also seen via the Leads tab) and the login access that may have been granted (we will discuss this in more detail in the next section), as well as which of your packages they have installed, their current license status, and when they were installed. The following is a screenshot of the Subscriber Overview page:

Table  Description automatically generated

Figure 1.17: Details shown when selecting an organization on the Subscriber Organizations list

How licensing is enforced in the subscriber org

Licensing is enforced in one of two ways, depending on the execution context in which your packaged Custom Objects, field, and Apex code are being accessed from.

The first context is where a user is interacting directly with your objects, fields, tabs, and pages via the user interface or via the Salesforce APIs (Partner and Enterprise). If the user or the organization is not licensed for your package, these will simply be hidden from view, and, in the case of the API, will return an error. Note that administrators can still see packaged components under the Setup menu.

The second context is the type of access made from Apex code, such as an Apex Trigger or controller, written by the customers themselves or from within another package. This indirect way of accessing your package components is permitted if the license is site-wide (or org-wide) or there is at least one user in the organization that is allocated a seat.

This condition means that, even if the current user has not been assigned a seat (via the Manage Licenses link), they are still accessing your application’s objects and code, although indirectly, for example, via a customer-specific utility page or Apex Trigger, which automates the creation of some records or the defaulting of fields in your package.

Your application’s Apex Triggers (for example, the ones you might add to Standard Objects) will always execute, even if the user does not have a seat license, as long as there is just one user seat license assigned to your package in the subscriber org. However, if that license expires, the Apex Trigger will no longer be executed by the platform, until the license expiry is extended.

 

Providing support

Once your package has completed the security review, additional functionality for supporting your customers is enabled. Specifically, this includes the ability to log in securely (without exchanging passwords) to their environments and debug your application. When logged in in this way, you can see everything the user sees, in addition to extended debug logs that contain the same level of detail as they would in a developer org.

First, your customer enables access via the Grant Account Login page. This time, however, your organization (note that this is the Company Name as defined in the packaging org under Company Profile) will be listed as one of those available in addition to Salesforce Support. The following screenshot shows the Grant Account Login Access page:

Graphical user interface, application  Description automatically generated

Figure 1.18: Granting access or tracking access duration for different users

Next, you log in to your LMO and navigate to the Subscribers tab as described. Open Subscriber Overview for the customer, and you should now see the link to Login as that user. From this point on, you can follow the steps given to you by your customer and utilize the standard Debug Logs and Developer Console tools to capture the debug information you need. The following screenshot shows a user who has been granted login access via your package to their org:

Graphical user interface, text, application  Description automatically generated

Figure 1.19: User shown in the Login Access Granted section

This mode of access also permits you to see protected custom settings and Custom Metadata, if you have included any of those in your package. If you have not encountered these before, it’s well worth researching them as they provide an ideal way to enable and disable debug, diagnostic, or advanced configurations that you normally don’t want your customers to see.

 

Customer metrics

For managed packages typically used by ISV developers, Salesforce exposes information relating to the use of your package components in subscriber orgs. This enables you to report what Custom Objects and Visualforce pages your customers are using and, more importantly, those they are not. This information is provided by Salesforce and cannot be opted out of by the customer.

This facility needs to be enabled by Salesforce Support. Once enabled, the MetricsDataFile object is available in your production org and will receive a data file periodically that contains the metric’s records. The Usage Metrics Visualization application can be found by searching on AppExchange and can help with visualizing this information.

 

Trialforce and Test Drive

Large enterprise applications often require some consultation with customers to tune and customize them to their needs after the initial package installation. If you wish to provide trial versions of your application, Salesforce provides a means to take snapshots of the results of this installation and setup process, including sample data.

You can then allow prospective users who visit your AppExchange listing or your website to sign up to receive a personalized instance of a Salesforce org based on the snapshot you made. Potential customers can then use this to fully explore the application for a limited time until they sign up to be a paying customer. Such orgs will eventually expire when the Salesforce trial period ends for the org created (typically after 14 days). Thus, you should keep this in mind when setting the default expiry on your package licensing.

The standard approach is to offer a web form for the prospective user to complete in order to obtain the trial. Review the Providing a Free Trial on your Website and Providing a Free Trial on AppExchange sections of the ISVforce Guide for more on this.

You can also consider utilizing the Signup Request API, which gives you more control over how the process is started and the ability to monitor it, such that you can create the lead records yourself. You can find out more about this in the Creating Signups Using the API section in the ISVforce Guide. As a more advanced option, if you are an ISV with an existing application and wish to utilize Salesforce.com as a backend service, you can use this API to completely create and manage orgs on their behalf. Review the Creating Proxy Signups for OAuth and the API Access section in the ISVforce Guide for more information on this.

Alternatively, if the prospective user wishes to try your package in their sandbox environment, for example, you can permit them to install the package directly, either from AppExchange or from your website. In this case, ensure that you have defined a default expiry on your package license, as described earlier. In this scenario, you or the prospective user will have to perform the setup steps after installation.

Finally, there is a third option called Test Drive, which does not create a new org for the prospective user on request but does require you to set up an org with your application, preconfigure it, and then link it to your listing via AppExchange. Instead of the users completing a signup page, they click on the Test Drive button on your AppExchange listing. This logs them into your test drive org as read-only users. Because this is a shared org, the user experience and features you can offer to users are limited to those that mainly read information. I recommend that you consider Trialforce over this option unless there is some really compelling reason to use it.

When defining your listing in AppExchange, the Leads tab can be used to configure the creation of lead records for trials, test drives, and other activities on your listing. Enabling this will result in a form being presented to the user before accessing these features on your listing. If you provide access to trials through signup forms on your website, for example, lead information will not be captured.

 

Distributing Salesforce Connected Apps

If you plan to build any kind of platform integration, including a dedicated mobile application, for example, using Salesforce APIs or any you build using Apex, you will need to create and package what’s known as a Connected App. This allows you, as the ISV, to set up the OAuth configuration that allows users of these integrations to connect to Salesforce, and thus, your logic and objects running on the platform. You don’t actually need to package this configuration, but you are encouraged to do so since it will allow your customers to control and monitor how they utilize your solution.

 

Summary

This chapter has given you a practical overview of the initial package creation process, from using Salesforce DX through to installing it in another Salesforce org. Packages are a fast and self-contained way to distribute your application regardless of being an ISV developer or a developer within your company. While some of the features discussed cannot be fully exercised until you’re close to your first release phase, you can now head to development with a good understanding of how early decisions, such as references to Standard Objects, are critical to your licensing and cost decisions.

It is also important to keep in mind that, while tools such as Trialforce help automate setup for your application, this does not apply when installing your application in production environments. Thus, when making choices regarding expected org configurations and defaults in your design, keep in mind these dependencies and costs during the implementation cycle when your package is installed.

As an ISV developer, make sure you plan for the security review process in your release cycle (the free online version has a limited bandwidth). Regardless, if you are building an application for your business or to provide to others as an ISV integrate a static analysis tool that supports security scanning into your CI build system as early as possible, since such tools not only monitor security flaws but also help report breaches in best practices, such as a lack of test asserts and SOQL or DML statements in loops.

In the following chapters, we will start exploring the engineering aspects of building an enterprise application as we build upgrades on the package created in this chapter, allowing us to better explore how the platform supports the incremental growth of your application.

As an ISV developer, as you revisit the tools covered in this chapter, be sure to reference the excellent ISVforce Guide at http://www.salesforce.com/us/developer/docs/packagingGuide/index.htm for the latest detailed steps and instructions on how to access, configure, and use these features.

About the Author
  • Andrew Fawcett

    Andrew Fawcett has over 30 years of experience holding several software development-related roles with a focus around enterprise-level product architecture. He is experienced in managing all aspects of the software development life cycle across various technology platforms, frameworks, industry design patterns, and methodologies. He is currently a VP, Product Management, and a Salesforce Certified Platform Developer II at Salesforce. He is responsible for several key platform features and emergent products for Salesforce. He is an avid blogger, open source contributor and project owner, and an experienced speaker. He loves watching movies, Formula 1 motor racing, and building Lego!

    Browse publications by this author
Salesforce Platform Enterprise Architecture - Fourth Edition
Unlock this book and the full library FREE for 7 days
Start now