© Andrew Davis 2019
A. DavisMastering Salesforce DevOps https://doi.org/10.1007/978-1-4842-5473-8_4

4. Developing on Salesforce

Andrew Davis1 
(1)
San Diego, CA, USA
 

Developing on Salesforce means configuring the platform to meet the needs of your organization. It can take the form of clicks or code, but is frequently a combination of the two. The scope can range from tiny changes to sophisticated applications.

Here, we’ll briefly introduce the Salesforce DX development lifecycle. We’ll then look at development tools, click-based development, and code-based development. In the next chapter, we’ll look at application architecture to introduce important principles to help you structure your development in a flexible and scalable way.

The Salesforce DX Dev Lifecycle

The basic elements of the Salesforce DX development lifecycle are a Salesforce development org, an IDE or code editor, version control, and a CI tool to perform automated tasks like deployments. Version control and CI tools are discussed at length in Chapter 7: The Delivery Pipeline, and the types and purposes of different Salesforce orgs are discussed in Chapter 6: Environment Management.

Salesforce has enabled sandbox development environments for many years. With DX, there are now two additional ways to create development environments: scratch orgs and cloned sandboxes. Scratch orgs are a flagship feature of Salesforce DX. They are short-lived orgs you create “from scratch” based on code and configuration stored in version control. Cloned sandboxes can allow developers to clone an integration sandbox that has work still under development, instead of only being able to clone the production org. The Salesforce CLI now makes it possible to clone a sandbox and automatically log in from the command line.

Changes made in that development environment need to be synced to version control so that automated processes can test and deploy those changes. One of the most helpful features of scratch orgs is the ability to perform a simple source:push and source:pull command to synchronize metadata between version control and your org. That capability will soon also be available when developing on sandboxes. Changes can also be retrieved from sandboxes using either source:retrieve or mdapi:retrieve, depending on whether you are storing metadata in the “Source” format or the original “Metadata API” format mentioned in Chapter 2: Salesforce.

Salesforce developers typically have to modify multiple aspects of Salesforce to create a solution. For example, a typical feature might involve changes to a Lightning Web Component, an Apex class, a custom object, a Lightning record page, and a permission set. To deploy that feature to another environment, it’s necessary to isolate all of the related metadata changes. But it’s entirely possible to make changes in the Salesforce Setup UI without being sure what type(s) of metadata you’re modifying.

If you’re the lone developer in an org, working on a single feature, it’s relatively easy to distinguish the metadata for that feature, especially if you’re using version control. Just retrieve all the metadata and check for changes in that org since you began developing; whatever has changed must pertain to that feature. When dealing with small volumes of changes, small teams, and a moderate pace of innovation, it’s not hard to manage Salesforce changes and deploy them across environments. But as teams begin to scale up, the pre-DX workflow begins to suffer from many limitations.

As soon as you put multiple developers in a single development org, it becomes much harder to isolate and deploy their changes independently. But when developers are working on separate orgs, integration is delayed and it becomes much harder for them to build on the work of others. Scratch orgs address this need by making it trivial to create a fresh new Salesforce environment that is up to speed with the metadata stored in version control. As you update your code repository, you can push those changes to your org, and as you make changes in the org, you can pull them down into version control without having to enumerate each type of metadata. Thus, if possible, you should develop in scratch orgs.

Unfortunately, it’s still not practical for every team to use scratch orgs, and so you may find you need to keep using sandboxes for development. One very promising workflow is to automate the cloning of developer sandboxes from a single integration sandbox and then deploy changes as they’re ready from those developer sandboxes into that integration org using a CI process. Recent updates to the Salesforce CLI make it possible to automate sandbox cloning and login.

One way or another, your job as a developer is to make changes in your development org, to commit them correctly to version control, and then to monitor automated tests and deployments to ensure your feature can be deployed without error. Setting up such automation is the topic of later chapters, but once it’s set up, developers can adopt this rhythm: build, commit, monitor.

Since version control is critical to this process, before beginning development, you must establish a code repository for your team. If a project has already been created, you’ll need to clone that project to your local machine before proceeding.

There are two Salesforce DX development models: the org development model and the package development model. The org development model is the default approach, but the two are complementary. Your team may gradually migrate most of your metadata into packages, but there will always remain the need to manage some org-level metadata through the org development model. You can find a nice introduction to these different models on Trailhead at https://trailhead.salesforce.com/content/learn/modules/application-lifecycle-and-development-models .

The options available for developing on Salesforce are in flux, and most Salesforce developers are still getting up to speed on foundational concepts such as version control. This means that there’s more variety in the development workflow than there was just a few years ago, and the optimal workflow of the future is not yet clear. This book attempts to present a comprehensive picture of the options, but expect things to evolve over the coming years.

If you are using the org development model, you will probably have a single repository representing all aspects of the org’s metadata that are managed by the development team. Chapter 7: The Delivery Pipeline provides recommendations on an appropriate branching structure for this model.

If you are using the package development model, you will probably have one repository for org-level metadata and one or more repositories for managing package metadata. Dividing your code across multiple repositories makes it easier to set up automation for each repository, but can easily get confusing as to which repository contains which metadata.

The package development workflow lends itself to a simpler Git branching structure than the org development workflow. Until you develop tooling that can dynamically determine which packages have changed and should have new versions published, separate packages should be developed in separate code repositories.

The package development model implies that you are using scratch orgs. If you are using scratch orgs, you will need to periodically recreate these scratch orgs to ensure that they are clean and reflect the latest version of the codebase. If you are working with a complex set of metadata and package dependencies, you may find the scratch org creation process takes a long time (up to an hour or more), so you may want to periodically precreate scratch orgs for upcoming work. The forthcoming Scratch Org Snapshots capability allows you to perform scratch org creation in advance and take a Snapshot of that org. The Snapshot can then be used to quickly create new orgs that are fully provisioned.

For those accustomed to working in long-lived sandboxes, it can feel frustrating to have to periodically recreate an entire development org. The purpose of recreating scratch orgs is to ensure that the entire application is fully represented in version control. This allows others on the team to create identical environments, and knowing all your dependencies limits the chances of confusion about why your applications don’t work properly in testing and production environments.

Subtle variations between the orgs used for development and testing are a massive source of risk, confusion, and inefficiency. This is a hidden challenge that often goes unnoticed, and the time spent debugging these variations between orgs is generally not accounted for. But every moment spent debugging out-of-sync orgs is waste. Though it may seem like a radical solution, the regular destruction and recreation of scratch orgs is key to ensuring an efficient overall workflow.

You should commit changes to the code repository after each significant change. If you are making changes on a feature branch in Git, all of those changes will be associated with the name of that branch, and so your branch naming strategy can be a way of linking a work ticket number to a group of many changes.

When your development is complete and you’re ready for review, you will merge it into your shared master branch (or create a merge request if your team requires that). Developing in scratch orgs unlocks the possibility of creating “Review Apps” so that other members of the team can review the developer’s work in a live scratch org.

Review Apps are environments created dynamically from version control that provide an isolated environment to review features that may still be under development. The concept was popularized by Heroku. Review Apps should be used for most QA and testing activities, but they only contain the test data that you deploy and are generally not connected to external systems, so some testing might need to be done in an SIT org instead.

Many of the topics presented in this brief overview are covered in more detail in later chapters.

Development Tools

Some aspects of Salesforce development are done directly inside the Salesforce Setup UI, while other aspects are best handled with developer-specific tools. The critical step of externalizing changes in Salesforce to a version control system is always done outside of Salesforce. This section gives a brief introduction to key Salesforce development tools and how they are used.

The Salesforce CLI

The Salesforce CLI can be downloaded from https://developer.salesforce.com/tools/sfdxcli . This command-line interface is an essential part of your DX toolkit. Many Salesforce CLI commands will only run inside a Salesforce DX project. A Salesforce DX project is one which contains a file called sfdx-project.json. That file is used to store information about the folders and packages in your project.

You can quickly scaffold a new project by using the sfdx project:create command, or you can clone one of the sample repositories from the Salesforce DX Developer Guide to be able to use a CI system like CircleCI. All of these project templates contain sfdx-project.json along with other helpful files.

You can get help for any CLI command by adding the -h or --help parameter. You can also find detailed help in the Salesforce CLI Command Reference. The CLI commands also allow you to export their results in JSON format by adding the --json parameter. This capability unlocks the possibility of automating complex processes by extracting the results from one command and passing them as parameters to other commands. See the section on “Command-Line Scripts” in Chapter 9: Deploying for advice.

What’s an Integrated Development Environment (IDE)?

An IDE is a code editor which brings together all the tools that developers need to write, track, debug, test, and deploy code. Some IDEs are built for a particular language (e.g., PyCharm is specific to Python), whereas others (like Eclipse and IntelliJ) support multiple languages. An IDE provides a code editor, but also offers things like syntax highlighting, code completion, debugging, and more. Most IDEs are extensible, allowing you to install plugins which add new functionality.

The Developer Console

The Dev Console is a web-based IDE that is built into Salesforce. It’s accessible from the gear icon in the upper right of each Salesforce org. It provides a convenient way to edit Apex, Visualforce, or Lightning Components. It also allows you to review debug logs, set checkpoints, and run anonymous Apex or SOQL queries among other capabilities.

It does not provide you a way to track metadata in version control, do deployments, or work with Lightning Web Components, and it’s no longer under active development. For certain tasks, like using logs to analyze performance, optimizing queries using the query plan, or checking Visualforce ViewState, the Developer Console is still my go-to tool, so it’s worth becoming familiar with its capabilities, although it will become less relevant over time.

Workbench

Workbench is an unofficial Salesforce tool hosted at https://workbench.developerforce.com . It provides a user interface for numerous developer-focused tools. In particular, it provides a simple way to navigate Salesforce’s various APIs and to test out API commands. Workbench exposes the Metadata API’s ability to deploy or retrieve metadata and to describe metadata such as custom objects. It exposes the bulk API’s ability to retrieve or modify data. And it allows you to execute SOQL or SOSL queries and anonymous Apex.

Workbench may never become part of your daily workflow, but it’s important to know it exists, as it’s the right tool for a wide variety of jobs.

The Forthcoming Web IDE

If this were a Salesforce conference, I would insert a forward-looking statement slide at this point. The Salesforce DX team is working on a web-based IDE that will encapsulate the capabilities of the Developer Console and Workbench (and thus allow those tools to be retired). At the same time, the Web IDE will allow teams to store complete sets of project files, run Salesforce CLI and Git commands, and interact with both Salesforce orgs and code repositories.

The initial goal is to get feature parity with the Developer Console and Workbench. Eventually this will provide a convenient IDE for teams who aren’t able or don’t wish to use desktop development tools.

Visual Studio Code

Salesforce built the original Force.com IDE on Eclipse, an open source IDE popular among Java developers. In 2018, Salesforce retired that IDE and began building a set of extensions on top of Visual Studio Code.

Visual Studio Code (VS Code) is a rare success story among developer tools. It’s an open source code editor that first appeared in 2015. Within 3 short years, it became the world’s most popular development environment.1

VS Code is the product of Microsoft, a company whose success and wealth have been built around proprietary commercial tools. Microsoft has not historically been well loved by the open source community, but VS Code is one of many such contributions2 made under Satya Nadella’s guidance. VS Code may even be reducing the number of people willing to pay for Microsoft’s commercial code editors.

Whatever the history, Microsoft has built an editor that has won the hearts and minds of millions of developers. And by making the tool open source, they are benefitting from an amazing stream of innovation from hundreds of citizen developers who have contributed features and bug fixes. Not to mention the thousands of companies like Salesforce who have built extensions for VS Code.

So, what is VS Code? Why has it become so popular? And why, in particular, is it the new chosen platform for Salesforce to build their IDE on?

Visual Studio Code is a free, open source, cross-platform, multilingual IDE. VS Code has the speed and simplicity of Sublime Text, with the power and tool set of Eclipse or paid IDEs like IntelliJ. It’s fast, simple, and clean; there’s a fast-growing set of extensions for it; and it’s adding new features every month.

Because it’s popular, it’s attracting innovation. In its short lifetime, VS Code has become the world’s most popular IDE, with more than 50% of developers worldwide adopting it. Salesforce has deprecated the Force.com IDE and is solely focused on building tools for VS Code.
  • Visual Studio Code is fast and can be installed on Windows, Mac, or Linux machines.

  • It has support/extensions for 72+ programming languages out of the box.

  • It gives built-in syntax highlighting and bracket matching in your code, as well as easy code navigation.

  • It has a built-in terminal and a stepwise debugger that supports many languages, including the new Apex Debugger and Apex Replay Debugger.

  • It supports Git natively so you can view diffs, commit, sync, and perform all the essential source control commands without leaving the editor.

  • It has a wise set of defaults but is extensively configurable.

There are many blogs that have done “bake offs” or detailed feature comparisons between other popular editors (like Vim, Eclipse, Sublime Text, Atom, and TextMate). We won’t repeat all of the details here, but instead just summarize some of the main comparisons as follows:
  • It’s more user-friendly than old-school editors like Vim, Emacs, Nano, Pico, and so on (anyone remember Edlin?).

  • It’s faster and more flexible than Eclipse.

  • It has more robust built-in developer tools (like version control and debugging) compared to Sublime or Atom.

  • It’s also faster and handles large files better than Atom.

  • It has far richer capabilities (like syntax highlighting and autoformatting) compared to TextMate, BBedit, or Notepad.

  • It’s free-er than IntelliJ or (the original, commercial) Visual Studio!

While Salesforce itself lives “in the cloud,” professional developers tend to write code for Salesforce using desktop tools. For a long time, the Force.com IDE based on Eclipse was the standard Salesforce development environment. With the preview release of Salesforce DX in 2016, Salesforce launched a Force.com IDE 2.0, also based on Eclipse. But before long, they changed course, deprecated the Force.com IDE and are now exclusively promoting VS Code as their official editor.

One reason for the change of heart is the architecture that VS Code is built on. VS Code is built using Electron, a framework that allows you to build Windows, Mac, and Linux desktop applications using HTML, CSS, and JavaScript. This means that to improve the user interface or add automation to VS Code, you can use the same technologies used to build web sites—the most common IT skillset in the world.3 VS Code also uses the innovative concept of Language Servers—which allowed Salesforce to build a generic language server for Apex and Lightning4 that can in theory be ported to Atom, Eclipse, or any other IDE that supports Language Server Protocol (LSP).

In the meantime, Salesforce was aware that MavensMate (especially in conjunction with Sublime Text) had become the open source editor of choice for many Salesforce developers who preferred its speed and simplicity to the older, rigid structure enforced by Eclipse. Sublime Text’s simplicity was a key inspiration for VS Code’s clean UI.

So by Dreamforce 2017, Salesforce had officially retired the Force.com IDE (including the newer IDE 2.0), in favor of VS Code.

In the meantime, Salesforce has continued to roll out innovation on top of VS code, and the VS Code team themselves have been releasing new features at a phenomenal pace.

VS Code should be your default choice for a Salesforce IDE. You can use it on your existing Salesforce orgs using the new metadata deploy and retrieve commands. This gives you a chance to get used to tools like the Apex Replay Debugger (a superior way to handle debug logs), test management tool, and more.

Despite these developments, VS Code still has frustrating gaps, especially for those developing on sandboxes. As of this writing, it does not provide any warning if you are pushing updates to a sandbox that will overwrite others’ work. Those limitations will eventually go away, but you should also seriously consider one of the IDEs mentioned below in the meantime.

Other Salesforce IDEs

There are currently two commercial IDEs for Salesforce that provide extremely robust capabilities: The Welkin Suite and Illuminated Cloud. The Welkin Suite is based on Microsoft’s Visual Studio (the commercial one, not VS Code) but is downloaded as a standalone application. Illuminated Cloud is a plugin for the IntelliJ and WebStorm IDEs by JetBrains.

Both Visual Studio and IntelliJ are exceptional development environments and are loved by millions of developers. They both now offer free tiers, but their popularity has been eclipsed as VS Code’s has exploded.

Illuminated Cloud and The Welkin Suite fill major gaps in the Salesforce extensions for VS Code. They both charge an annual fee, but will quickly pay for themselves in terms of time and agony saved for each developer. The Welkin Suite is somewhat more expensive, but is supported by a larger team of developers. Illuminated Cloud is the work of Scott Wells, who has supported it tirelessly and has an amazing knowledge of the platform and the challenges faced by developers.

Both of these tools innovate extensively and continue to have promising futures, even as Salesforce evolves their free alternative. The Welkin Suite created a replay debugger several years before this was available in VS Code. And Illuminated Cloud combines IntelliJ’s excellent features such as code completion and task management integration with support for all Salesforce languages, metadata types, and development models.

In addition to these, it’s worth mentioning three other tools. ForceCode5 was one of the earliest VS Code extensions for Salesforce. It was created by John Nelson while working for CodeScience. The project had been deprecated after Salesforce released their extensions for VS Code, but I learned recently that it has come back to life. Among other good qualities, it helps compare your local copy of code with the latest version in your Salesforce org and includes tools to manage the process of building complex single-page apps using JavaScript frameworks and deploying them to the Salesforce platform.

MavensMate is now retired but was largely responsible for convincing the Salesforce developer ecosystem that there were faster and simpler alternatives to the Force.com IDE. Joe Ferraro labored for years to provide MavensMate, doing an enormous service to the Salesforce developer community.

Aside.io is a web-based IDE that was also very popular with my colleagues. It has the benefit of not requiring any local software installation. But as a result, it does not provide a method to interface with version control. Aside.io may be discontinued soon, but its founder has committed to open sourcing the project if possible.

Metadata (Config and Code)

For those new to Salesforce development, it’s useful to reiterate that Salesforce does not allow for local development because changes are necessarily compiled and run on a Salesforce instance and cannot be run locally. Lightning Web Components are some exception to that, and LWC local development capability is now available. The JavaScript used in static resources is also available for local development, but these are typically only small parts of a Salesforce application.

What is possible, however, is to download your Salesforce configuration as metadata that can be stored, tracked, updated, and deployed back to a Salesforce instance.

What Is Metadata?

Most Salesforce customizations are represented as metadata components. These metadata components are files that can be retrieved from the server (Salesforce instance) and modified locally, then saved back to the server or deployed to another environment. A detailed list of available metadata items can be found in the Metadata API documentation.6

These metadata files are largely stored as XML, although some are code, and some new types are JSON. It’s this metadata representation that can be stored in version control and is the basis for automated processes such as static analysis and automated deployments.

Metadata API File Format and package.xml

As explained in Chapter 9: Deploying, the key technology that enables retrieving and deploying metadata from a Salesforce org is the Metadata API. The Metadata API uses a file called package.xml to enumerate the metadata that should be deployed or retrieved. Some developer tools like MavensMate rely on this file as a representation of the metadata in your org.

The use of package.xml can lead to confusing results if there’s a mismatch between its contents and the metadata files you’re working with. So an increasing number of tools are doing away with this file and instead automatically generating it as needed. For example, the Salesforce DX source format does not include this file at all. Nevertheless, it’s dynamically generated behind the scenes when communicating with the Metadata API.

The Metadata API explicitly deals with files using an src/ directory that contains the package.xml file itself as well as the individual metadata for the project. These files are organized into folders based on the type of metadata as shown in Listing 4-1. Each metadata item is its own file within that folder.
  src
  ├── applications
  │   └── DreamHouse.app
  ├── layouts
  │   ├── Broker__c-Broker Layout.layout
  │   └── Property__c-Property Layout.layout
  ├── classes
  │   ├── ClassA.cls
  │   ├── ClassA.cls-meta.xml
  │   ├── ClassA_Test.cls
  │   └── ClassA_Test.cls-meta.xml
  ├── pages
  │   ├── PageA.page
  │   └── PageA.page-meta.xml
  └── package.xml
Listing 4-1

The native Metadata API file and folder structure

Note that some metadata types like applications and layouts have a single metadata file to represent a single item, while other types like classes and pages use two or more files. Files like ClassA.cls contain the actual metadata body (in this case an Apex class), while files like ClassA.cls-meta.xml are called “sidecar files” and store some accompanying metadata. Sidecar files are typically very small XML files.

One of the innovations of the Salesforce DX source format is the ability to group related metadata into subfolders that can eventually be published as packages. That is not possible in the native Metadata API format and is a key benefit of moving to Salesforce DX.

Converting Between Salesforce DX and Metadata API Source Formats

There are special commands to convert between the Salesforce DX metadata format and the Metadata API format. The Salesforce DX Developer Guide and some Trailhead modules7 and video tutorials8 describe this process in more detail. Here we provide just a brief overview.

sfdx force:project:create allows you to create a new set of project files in the Salesforce DX format. But it’s often the case that you want to convert an existing set of metadata files into Salesforce DX “source format.”

sfdx force:mdapi:convert operates on projects stored in the native Metadata API format and converts them to the “source format.” All files in the src directory are converted into files in the default folder specified in sfdx-project.json (typically force-app/main/default/). Large .object files are decomposed into smaller components, zipped static resources are decompressed, and so forth. Initially these files are not grouped into subdirectories, but after being converted, you can create subdirectories to group metadata into packages.

sfdx force:source:convert performs the opposite conversion, taking metadata files in the SFDX source format and converting them into the native Metadata API format. Even if you have grouped your source format metadata into many subfolders, once converted into the Metadata API format, they will all be in a single src/ folder. This process will autogenerate the package.xml file mentioned earlier. Note that this is a “lossy” conversion; if you convert these files back to the DX source format, you will lose the folder structure.

What Metadata Should You Not Track?

The main goal of this book is to provide advice on building a CI/CD pipeline for Salesforce. That pipeline becomes a delivery vehicle for metadata to allow it to be built in a development environment, promoted for testing, and finally delivered to production.

There are however types of metadata such as those shown in Table 4-1 that generally should not be included in the code repository and CI/CD process. There can be temporary and long-term exceptions to this rule depending on the needs of the project team. Think of the things that you include in the CI/CD process as being “controlled by developers and admins,” as opposed to being “controlled by end users.” The essence of continuous delivery is being able to reliably recreate development, testing, and production environments and code. And for this reason all core functionality (custom objects and fields, business logic, even page layouts) should be controlled by this development process. But functionality like reports and dashboards are a great example of metadata that can safely be controlled by business users, since they may need to change frequently and with rare exceptions changing them will not cause side effects elsewhere in the system.

If you exclude these items from your code repository, you should also add them to your .forceignore file to prevent them from sneaking back in.
Table 4-1

Types of metadata that might be excluded from CI/CD

Metadata Type

Reason to Exclude from CI/CD

Certificate

Certificates are generally environment-specific and should be kept secure.

ConnectedApp

Connected Apps are generally environment-specific. If you automate their deployment, you will need to dynamically replace some parameters.

Dashboard

These are often changed frequently by users in production and should not go through the development lifecycle unless they are a dependency for your code or metadata.

Document

These are often changed frequently by users in production and should not go through the development lifecycle unless they are a dependency for your code or metadata.

EmailTemplate

These are often changed frequently by users in production and should not go through the development lifecycle unless they are a dependency for your code or metadata. An exception is VisualForce email templates or other templates that use embedded code and may require a careful development process.

InstalledPackage

You can’t control the installation order. Use sfdx package commands to install packages instead.

Layout

When following the package development model, page layouts can be problematic. They should be managed at the org level for any objects that straddle multiple packages.

NamedCredential

Named Credentials are generally environment-specific. If you automate their deployment, you will need to dynamically replace some parameters.

PlatformCachePartition

These are typically environment-specific.

Profile

Profiles are the fussiest of all metadata types, as explained below. Without special automation, you will find it easier to manage these manually.

Report

These are often changed frequently by users in production and should not go through the development lifecycle unless they are a dependency for your code or metadata.

SamlSsoConfig

SAML SSO Configuration is usually environment-specific. If you automate their deployment, you will need to dynamically replace some parameters.

Site

The Site metadata type represents Communities, but is stored as a binary file and can change unpredictably, making it a poor candidate for CI/CD.

Retrieving Changes

After modifying items in a development org, you need to retrieve those changes and merge them into your local working directory so that you can track changes and deploy them using CI/CD.

The Salesforce CLI and the different IDEs mentioned earlier all provide mechanisms to retrieve metadata. The commercial Salesforce release management tools introduced in Chapter 9: Deploying also provide mechanisms for doing this.

The way the Metadata API behaves can make retrieving metadata very awkward without the help of a specialized tool. This is especially true when working in the native Metadata API format. A single .object file can contain hundreds of child metadata items. If you request to retrieve one of those child items, such as a field, your request will overwrite the entire .object file with just the metadata for that one item.

Profiles are famously awkward to deal with. A profile can contain thousands of permission details such as field-level security. But when you issue a simple retrieve command for a profile, it will retrieve only the small subset called “user permissions.” To retrieve the field-level security part of a profile, you have to retrieve both the profile and the appropriate field. As mentioned earlier, this will overwrite the local metadata file for the object and will also overwrite any other permissions in the profile file. Even more confusingly, to retrieve the page layout assignment for a particular record type, you have to retrieve the profile, the page layout, and the particular record type. I could go on.

Why such bizarre and unfortunate behavior? It’s because the Metadata API was not originally designed to create a single representation of the org that was suitable to be stored in version control. This is one of the key reasons why it’s important to use tools that are specialized for Salesforce development, and one of the key reasons why naively attempting to build a Salesforce CI/CD process without specialized tools will end in tears.

Adopting a specialized Salesforce IDE or release management tool will pay for itself very quickly (especially if you use the free ones!). These tools have solved these problems and allow you to follow a rational workflow for retrieving, tracking, and deploying metadata.

The Salesforce DX source synchronization process for scratch orgs also addresses these challenges. The SFDX source format is designed to store metadata for use in version control and automated deployments. And the source synchronization capability of scratch orgs handles complex retrieves and merges automagically.

Making Changes

Changes to a Salesforce org can be made either using the Salesforce UI or by modifying the metadata in your local IDE and compiling it to the Salesforce org.

Most configuration changes should be made with the UI to ensure that the metadata remains coherent, while most code changes are made from the IDE. The Salesforce-specific IDEs perform a two-step process when saving. They first save your file locally and then attempt to deploy them to your development org. If the deployment is unsuccessful, you will receive an error that prompts you to fix your change. In the case of code files, deploying your metadata files will also compile your code and show you any compile-time errors. If the deployment is successful, your update will be saved to the org.

Note that you have to remain attentive to any errors returned by your IDE. It’s entirely possible to commit local metadata files to version control in an invalid format, which will cause downstream failures if you attempt to deploy them. It’s the developer’s responsibility to ensure that they can make a successful round-trip from their local metadata file to the Salesforce org and back.

Salesforce DX scratch orgs and source synchronization address these challenges. Scratch orgs are generally designed for a single user or for limited collaboration between one dev, one admin, and maybe people testing or demoing new features. This bypasses the challenge of possibly overwriting others’ work in a shared sandbox.

The source synchronization process also makes deployments to scratch orgs very fast and simple. Local metadata is first analyzed to see if it has changed (using a timestamp and a hash), and only metadata that has been changed is pushed, which makes the deployments much faster. There’s no need to specify which specific files should be pushed to the scratch org; every changed file will be pushed using a single command.

Manual Changes

Almost all of the steps required for a deployment can be automated using metadata and the Salesforce CLI, although it takes time to get familiar with the way that UI changes are represented in metadata. There are however some changes that cannot be tracked or deployed in this way. When manual configuration is needed for functionality to work, developers or admins should track and document the required steps in whatever project tracking tool is being used. The instructions should be as detailed as necessary for whoever will eventually perform those manual steps.

It’s at this point that the dreams of fully automated deployments bump up against a more manual reality. As mentioned in Chapter 9: Deploying, many of the things that people think are manual steps can in fact be automated. And the Salesforce Metadata API teams keep working on addressing gaps in the metadata.

Traditionally, when developing on sandboxes, developers need to have extensive knowledge of many different metadata types and do research to determine if and how that metadata can be downloaded. The source synchronization process available in scratch orgs and soon also in sandboxes addresses this problem by automatically identifying what was changed through the Setup UI and downloading the appropriate metadata. The productivity gains from this cannot be overstated.

Click-Based Development on Salesforce

There are roughly 250 different types of Salesforce metadata that are configured declaratively, using “clicks not code,” on the Salesforce platform. This configuration can be as simple as toggling settings and as complex as using sophisticated “Builders” to create complex UIs, data models, and business logic. The App Builder, Schema Builder, Flow Builder, Process Builder, and Community Builder provide drag-and-drop components for these purposes, each with their own configurable settings.

The degree to which Salesforce can be configured in this way is a defining characteristic of the platform. It means that even code-based Salesforce developers need to be familiar with at least the basic declarative configuration tools. It also means that one can spend their entire career building and customizing Salesforce and never leave the Salesforce UI.

Development—No-Code, Low-Code, and Pro-Code

Salesforce sometimes distinguishes three types of developers—no-code, low-code, or pro-code—based on their skills and preferred tools. The term “developer” implies someone who creates something systematically and by phases. This is certainly true of those who code, since the process involves extensive testing and iteration. But it’s equally true of those who use graphical tools. The initial iteration of a Flow might be quite simple. It then needs to be tested, edge cases need to be identified, logic can be added, and so forth.

It’s worth remembering that code itself is a user interface—it’s just a text-based UI rather than a graphical one. The history of computer science is largely the history of building increasingly high-level abstractions to make logic more clear for humans. Assembly language was created to free people from having to write numeric instructions in machine code. Higher-level languages like C freed people from having to deal with esoteric assembly language. Languages like JavaScript layer on further abstractions and simplifications, eliminate the process of compiling code, and give access to hundreds of thousands of prebuilt modules that encapsulate solutions to common problems.

Each transition to a higher level has made the language more accessible, at the cost of some performance. Those who are familiar with working at lower levels of abstraction can boast of building more optimized solutions. But a performance cost is often a very worthwhile sacrifice for a solution that is easier to understand and maintain over time.

And so in Salesforce, “pro-code” developers are those who are comfortable or prefer working directly with Apex, Visualforce, Lightning, or Salesforce APIs. “Low-code” developers are those who are more comfortable working with declarative tools, but who are nevertheless comfortable creating or maintaining small and strategic bits of code. And “no-code” developers are those who build and maintain customizations entirely using declarative tools.

“No-code” developers are extremely common in the Salesforce world. But the idea of developing without code is still a nascent movement in the IT world. Graphical abstractions for UI and data models are extremely common, for example, with tools that allow you to build web pages without dipping into HTML or build relational databases visually. Graphical abstractions of logic are less common; but even the most sophisticated programmers often crave and create visual representations of complex code like UML diagrams. In this respect, the future is already here on the Salesforce platform.

Salesforce Flows actually use Visualforce or Lightning to generate pages. In that sense, Flows are truly higher-order abstractions built over top Salesforce coding technology. As with other abstractions, Flows and Processes do not perform as well as pure Apex or Lightning solutions, and their metadata format is arcane. But they allow business processes to be visualized and edited by a far larger group of users, which is a massive boon for maintainability. They are one of many examples where Salesforce is democratizing development. While pure coders may be dismissive of solutions that trade efficiency for simplicity, history shows that this can be a massive strategic advantage.

But don’t expect code to go away anytime soon. Salesforce themselves had to retreat from their original “clicks not code” motto. And “pro-code” development options like Web Components, Git, and CI/CD are becoming increasingly easy and popular on Salesforce. Just as I would have been hard-pressed to write this book using graphical tools, there’s often no substitute for the freedom and flexibility of text-based code to express complex scenarios.

Declarative Development Tools

Entire books have been written about Salesforce declarative tools like Community Builder, so I’m making no attempt to cover that topic exhaustively here.

What matters for our purposes is that any declarative changes that are made in Salesforce need to be converted into a textual form if they are to be tracked in version control and migrated to other environments using the tools described in Chapter 9: Deploying. This is the job of the Metadata API, described in detail in that chapter. The Metadata API provides a text-based representation of declarative configuration, mostly in XML, that can be inspected, tracked, and deployed to other environments.

In most cases, the purpose of capturing declarative configuration as text is simply to retrieve it from one Salesforce environment and deploy it to another environment. Along the way, there certainly is manual or automated processing that can be done on that metadata, some of which is described later in this book. But just as the declarative tools themselves range from simple to complex, so too does this metadata representation. I feel extremely comfortable viewing and updating the XML that describes custom objects, fields, and validation rules. But I don’t know anyone who regularly edits the metadata representations of Flows and Processes.

There are countless tips and tricks that could be shared about working with declarative metadata; some of these I know, many of them I don’t. So I’ll constrain this discussion to a few points about a few of the most complex declarative Builders.

Lightning App Builder

The Lightning App Builder is a way to create UIs by assembling Lightning Components. From a metadata point of view, the final result of using the App Builder is a metadata item of type Flexipage. This is an XML representation of the page that includes the page layout, the components on the page, component properties, and some other metadata such as platform actions available for that page. This metadata is stored in a single file and is easy to version and deploy.

Community Builder

Community Builder is similar to Lightning App Builder in that it is used to create and configure user interfaces with drag-and-drop elements. But it adds considerable sophistication in that it can be used to create entire Communities—multipage web sites—and to define the overarching structure of the site as well as individual pages. Community Builder is a massive area of growth and focus for Salesforce, and they’re working on a unified “Experience” model that can also encompass the web site builders associated with Marketing Cloud and Commerce Cloud.

One massive disadvantage of Community pages is that until recently they didn’t have human-readable metadata contents. That’s changing with the release of the ExperienceBundle metadata type, although that’s still in Developer Preview as of this writing. In marked contrast to most Salesforce metadata, ExperienceBundles are stored as JSON files. Salesforce began in 1998 and is mostly written in Java, the most promising programming language from that time. Salesforce also relies heavily on the data storage and exchange formats which were popular at that time, XML and SOAP, which are very well supported by Java. JSON is a newer and simpler standard that has grown in popularity alongside JavaScript, since it allows for smaller and more readable files, which can be parsed natively by JavaScript.

Although it’s currently possible to deploy entire communities using the Site, Network, and SiteDotCom metadata types, the Site is stored as a binary file which changes each time it’s retrieved, and so isn’t suitable for version control or continuous delivery. As ExperienceBundles become widely adopted, it should become possible to selectively deploy aspects of a Community without redeploying the entire thing. Until then, teams must either deploy the entire Site or manually migrate Community configuration from one Salesforce org to another.

Process and Flow Builders

Process Builder is used to create business logic that is triggered by an event such as a record update. Processes are necessarily linear sequences of steps that are performed one after another, although there are an increasing number of available options.

Flow Builder is used to create more complex logic and can also be used to create user interfaces and to define data flow across screens. Processes are built on the same underlying technology as Flows, and they are both retrieved using the metadata type Flow.

For many releases, managing Flow metadata also required managing metadata for FlowDefinition. Each Flow or Process version was stored as a separate Flow file, and a corresponding FlowDefinition file specified which version of the flow was active. Since Winter ’19, only the active Flow version is retrieved, FlowDefinitions are not needed, and Flows can be deployed as active under certain circumstances. Since Flow versions update the same filename, you can keep a clear history of changes in version control.

Flows and Processes are one of a small number of metadata types where Salesforce manages version numbers internally and allows versions to be updated or rolled back from the Setup UI.

This is a very powerful capability for many reasons. First, Flows are asynchronous and may be waiting for user input for many minutes. Flows store the user’s state in a FlowInterview object, along with which version of the Flow is being used. Even if a different version is activated while a user is still progressing through that Flow, they will be able to complete the process using the same Flow version they started with.

Second, this allows for versions of a Flow to be deployed without being immediately released. As explained in Chapter 10: Releasing to Users, the ability to deploy without releasing is a key capability that enables continuous delivery. While Flow versions do not allow you to release to only a subset of users, they certainly enable you to roll out or roll back a flow version on your own schedule, regardless of when they were deployed to an org.

Finally, Flow versions provide a form of declarative version control. The use of traditional version control is still far from ubiquitous on Salesforce. Declarative developers building Processes and Flows are grappling with complex logic and UIs that might take days or weeks to build. As with code-based development, it’s invaluable to be able to take a snapshot of your work and begin experimenting with a new approach, confident that you can always roll back to a previous version. By dispensing with FlowDefinition metadata, Salesforce is making it easier to manage Flows using traditional version control like Git while still preserving the declarative versioning of Flows.

There’s one final sense in which Flows and Processes are unique among declarative metadata. Salesforce has begun to enforce code coverage requirements on these, just as they do with Apex code. As we’ll discuss in Chapter 8: Quality and Testing, Apex tests are not limited to only validating Apex code. They can validate any form of backend business logic in Salesforce, including validation and workflow rules, Processes, and autolaunched Flows (those which don’t require a UI).

The only case when code coverage is required for Processes and Flows is when they are deployed as Active. By default, they are deployed in a Draft status and have to be manually activated. You can enable the ability to deploy these as active from SetupProcess Automation SettingsDeploy processes and flows as active. If you choose this option, then you must ensure that you have Apex tests that exercise these flows. For example, if a Process is triggered any time you create or update an Opportunity with a particular record type, you must have an Apex test that performs such an action.

This is a fairly soft requirement, in that not every logical execution scenario has to be tested. So it doesn’t require tests that are as detailed as those which test Apex classes or triggers, where 75% of all the lines have to be covered. But you have to at least touch those Flows and Processes.

Data Management

The very core of Salesforce is a relational database that can be easily managed using clicks not code. This is the earliest configurable part of the platform and is still the most heavily used. Admins can use graphical tools to define objects and fields, connect them to other database objects, place them on page layouts, and define who can see them.

A complete explanation of this topic is far outside the scope of this book, but it’s worth mentioning a few points that have an impact on the overall flow of changes from development to production.

Managing the Schema

“Schema” is a fancy name for the data structures in a relational database. In the simplest terms, it defines what data you want to store and how that data is related to other data. In a traditional database, you define spreadsheet-like tables to hold each category of data, in which each “row” is a record, each “column” is a field, and some special columns can be “lookup relationships” to rows in other tables. In Salesforce, tables are referred to as “Objects” (like the Account Object) because the definition of that object includes far more than just the data structure.

Creating a new schema object or field is typically done using multistep wizards, and this is often the first configuration activity that Salesforce admins and devs will learn. For the impatient, Salesforce provides a Schema Builder that allows you to create objects and fields quickly while bypassing nonessential steps in the wizard.

Although this process is relatively quick and easy, it can have big impacts on the rest of the org. UI, reporting, and business logic are built around displaying, analyzing, and manipulating data, and so the schema is fundamental to most other customizations.

When people first begin to set up version control and continuous delivery for Salesforce, it’s tempting to only track code. Code is certainly the most important candidate for version control, but code in Salesforce is largely built for retrieving and manipulating database objects, and so without tracking the schema you don’t have a complete picture stored in version control. If you attempt to automatically deploy code to later environments, your deployments will fail unless the necessary objects and fields are already in place.

For these reasons, you should manage the schema in your testing and production environments using version control and a continuous delivery process. You should not allow any manual changes to the schema in those environments, unless you have a high tolerance for confusion and inefficiency. You can and should modify objects and fields in a development environment and deploy from there along with the rest of your configuration.

As mentioned, there’s a lot more to Salesforce objects than just a data table. This is reflected in the object metadata format, which includes fields, validation rules, compact layouts, and record types among other components. It’s for this reason that critical objects in your data model like Accounts can easily have an object metadata file that grows to tens or hundreds of thousands of lines. Version control tools like Git excel at managing and merging line-by-line changes to code files. But the default diff tool included with Git gets extremely confused when comparing repetitive blocks of XML metadata, making such large files very hard for teams to manage and collaborate on.

The Salesforce DX source format “decomposes” each object file into a folder, with files for each child component organized into subfolders by metadata type. Breaking large XML metadata into many files makes it straightforward for teams to manage and deploy the schema collaboratively.

Changing the Schema

Most schema changes lend themselves well to being propagated from dev to test to production. There is, however, one caveat and two big exceptions. The caveat is that some seemingly innocent schema changes can cause data loss or other problems. The two exceptions where schema changes can’t (or shouldn’t) be propagated automatically are when changing the object/field names and when changing field types.

It is important to emphasize to your developers and admins that their changes can and will have an impact on production data and users, and that it is their responsibility to envision not only the end state that they want to build but also the impact of any changes to existing functionality. It’s important to facilitate the free flow of innovation, but here are just a few examples where schema changes require a skeptical eye:
  • Increasing the length of a field is usually safe, but decreasing its length can truncate data and cause data loss.

  • Increasing the length of a field can cause problems if you’re integrating with external systems and those systems truncate or refuse to accept longer data values.

  • Adding validation rules is part of business logic and must be tested carefully since it can cause Apex tests and integrations to break.

  • Disabling field or object history tracking will delete that historical data unless you’re using Salesforce Shield.

  • Making a field required can also break Apex tests and integrations and is not a deployable change unless that field is populated for every record in the target org.

Don’t Change DeveloperNames

The two types of schema change that are truly problematic in a continuous delivery process are changing object/field names and changing field types. Every type of Salesforce metadata, including objects and fields, has a DeveloperName (aka API name) that uniquely identifies it. That name is usually created dynamically when you specify the label or display name for the metadata. For example, if I create a field labeled “Implementation Manager,” the New Custom Field Wizard will suggest the field name Implementation_Manager__c. When you retrieve the metadata for that new field, the field name appears as the <fullName> property in the XML and the name of the field file if you’re using the Salesforce DX source format.

Let’s say you decide to change the label for that field to “Success Manager.” It’s tempting to also want to change the field name to Success_Manager__c. If you’ve already deployed this field to other environments, DON’T CHANGE ITS NAME. Take a cue from Salesforce, who regularly rebrands their features, but doesn’t change their names on the backend. Einstein Analytics is still known as Wave in the metadata. Communities and Sites were rebranded a decade ago, but are still referenced as Picasso in some parts of the metadata. The list goes on and on.

The problem with changing developer names is that when you deploy the new name, it’s created as an entirely new field, object, and so on. It’s treated as something new and unknown; none of the data is carried over from the old object. Not only that, but you’ll have to update any code, formulas, or external integrations that relied on it. DON’T DO IT, change the field label to update the UI, but leave the underlying field name the way it is. You can add an explanatory note in the field description if you think that will help.

Changing Field Types

What about changing field types? A groan is arising from the depths of my heart when I think about this activity; it’s generally a big pain to propagate these changes. Here are some recommendations about addressing this.

First, the basics: every field in a Salesforce object has a field type. There are currently 23 possible field types including text, picklist, number, lookup relationship, and formula. Field types determine the storage size for fields and provide built-in data validation: you can’t put text in a number field, lookup relationship fields have to point to another record, and so on. Twenty-three types of fields means there are theoretically 23 ∗ 22 = 506 permutations of field type changes. But there are limitations on this, so, for example, it’s not possible to change a field from a formula into any other type or from any other type into a formula. Salesforce provides a help article outlining those restrictions and the cases in which data loss can occur, such as changing from a text field to a number field.9 That article is an important reference when considering a field type change.

Why would you ever need or want to change the type of a field? There’s always uncertainty in the development process. One common example is changing from a text field (which allows any value) to a picklist field (where only certain values are valid) or vice versa. The team may create a text field to store a particular value, but later realize that it’s important to standardize the options to improve data quality and generate better reports.

The book Refactoring Databases10 arose from the recognition that data models need to evolve over time and introduced the concept of “evolutionary database development” to address this challenging process. They provide numerous recommendations, not all of which are relevant for Salesforce, but some of which can be summarized here.
  1. 1.

    Delay creating (or at least deploying) objects and fields until you are actually ready to use them. It’s very easy to modify your schema in your development org, but can be challenging to propagate changes, especially if you’re already storing data.

     
  2. 2.

    Think long and hard about whether you actually need to change the type of a field. I’ve facilitated field type changes for developers, only to facilitate changing them back, and then changing them once again. Such indecision can strain your friendships.

     
  3. 3.

    Experiment with the field type change in your development environment to see if it’s even possible. Create a new field of the original type, and then change that field to see if it’s permitted and what warnings are displayed. Delete that field when you’re done.

     
  4. 4.

    Assess the risk of data loss from any field change, and get sign-off from the appropriate business stakeholders on the change.

     
  5. 5.

    Assess whether any external integrations connect to this field, to ensure they won’t break or introduce bad data.

     
  6. 6.

    If you decide to proceed, you can change the field type in your development environment and attempt to deploy it. Some field type changes can be successfully propagated using the Metadata API. If your deployment succeeds, you’re lucky.

     
  7. 7.

    If your deployment does not succeed, you have two options: manually change the field type or create a new field and migrate data.

     
  8. 8.

    You can manually change the field type in all other environments as a way of propagating this change. This is tedious once you become accustomed to continuous delivery, but may be your simplest option. The problem with this is if you have a long lead time to get changes into production, since it may require careful choreography to facilitate a large release and also to make manual changes such as field type changes, especially if those changes are required for work done weeks or months in the past. This is one of many arguments for doing small and frequent releases.

     
  9. 9.

    You can also create a new field of the new type and then migrate or synchronize data from the old field. This is necessary for certain field type changes, especially if the field is heavily referenced by code or other configuration. Migrating data from the old field to the new field can be done using a data management tool or by using batch or anonymous Apex, depending on how much data you need to move. Batch Apex can be used to iterate across thousands or millions of records. You query records which have the old field populated and the new field empty, and you copy values from the old field to the new field, transforming them along the way. The Metadata API allows you to mark the old field as deprecated if you want and eventually to delete it.

     
  10. 10.

    In circumstances where you need to change a heavily used field in a production environment without incurring downtime, you can actually create a data synchronization between the old and new fields. This is the most elegant solution and could involve Apex, Processes, or Workflow rules to update the new field with the old value and the old field with the new value whenever they change. While complicated, this allows for true refactoring and enables you to deploy a complete process from development to production without requiring any manual steps. Needless to say, you should test the heck out of this process before deploying it. Once it’s in place and your refactoring is complete, you can delete the old field.

     

Bulk Database Operations

In addition to field type changes, there may be other bulk database operations you need to perform. Many of my colleagues at Appirio specialized in transforming and migrating data from legacy systems into Salesforce, and for this there are specialized tools and skills you might need. The Salesforce data management applications Odaseva and OwnBackup both provide a wealth of tools that you might use to perform large-scale data operations. The free Salesforce Data Loader and MuleSoft’s dataloader.io are excellent no-frills options to help with this process, especially in combination with clever use of spreadsheets for data transformations.

As mentioned earlier, the use of anonymous Apex and batch Apex are both excellent methods to perform bulk database operations, although you should approach this with due caution. Anonymous Apex allows you to build an Apex script so you can query, transform, and create/update/delete data as needed. Such scripts should generally be stored in version control (so you don’t forget what you did), but are generally run through the developer console or the Salesforce CLI. Test such scripts very carefully. Anonymous Apex allows you to transform up to 10,000 records at a time (the DML limit). Combined with a query that is smart enough to know which records have not been processed, you can script or manually trigger iterations of this code until the job is done.

Batch Apex handles the iterations for you and is designed to process large volumes of data over time. Batch Apex is an Apex class that uses the Database.Batchable interface to define start, execute, and finish methods that iterate across your database 200 records at a time. This can be used either for one-time or ongoing processing as needed.

Data Backup

Unless you’re unusually paranoid, you don’t need to back up your data out of fear that Salesforce will lose it. They have excellent redundant backup systems that distribute the backup across multiple data centers. What you need to worry about is the actions of your users and yourself. Remember those bulk database operations I just mentioned? Remember how I said you should test them extremely well? I think you’re getting the picture.

While unlikely, you could be subject to malicious users or hackers who intentionally delete data. More likely, unwitting users or admins might make sweeping changes that cause data loss or corruption. And it’s also possible for developers to introduce batch Apex, processes, triggers, workflows, or integrations that cause sweeping and undesired changes.

For all of these reasons, data backup is important. Your free option is the monthly export service accessible in SetupDataData Export. That will generate a one-time or scheduled downloadable backup. You should practice and ensure you have the skills on hand to restore some or all of that data in an emergency. Your concierge options are data management services such as AutoRABIT Vault, OwnBackup, or Odaseva who can provide data backup and recovery tools and services.

Configuration Data Management

One of the weakest links in the continuous delivery systems I have built and seen for Salesforce is the management of configuration data. Salesforce release managers and release management tools generally specialize in migrating configuration metadata. The Salesforce Metadata API provides a mechanism for retrieving and deploying this metadata. While there are some complexities in this process, Salesforce actually takes care of most of the complexity for you. When you do a deployment, Salesforce checks the validity of your code and configuration, ensures referential integrity and idempotency, assesses differences, sequences the metadata loads, and more. There’s an enormous amount of intelligence being leveraged behind the scenes.

If you need to migrate complex configuration data, you will need to address those problems of data sequencing and referential integrity on your own. The tools and techniques for this are unfamiliar to most Salesforce release managers and so have been an afterthought for many teams.

Unfortunately, large managed packages such as Rootstock ERP, nCino, Vlocity, FinancialForce, and Salesforce CPQ require extremely complex configuration data to operate. If you use any of these packages, it’s important for your team to establish tools and expertise to facilitate migrating this data, so that you can use your sandboxes to develop this configuration as well. The reason to manage configuration data in your release management process is twofold: first, that configuration data can determine logical pathways that actually affect the behavior of your applications, and second it allows you to develop and test changes to this data before migrating it to production.

To my knowledge, among the packages listed earlier, only Vlocity has built its own configuration data migration tool, Vlocity Build.11 Prodly Moover has carved out a niche for itself as a tool that specializes in migrating such complex data. Some of the Salesforce release management tools like AutoRABIT, Gearset, and Copado have also begun to develop excellent tools to help in this process. Where these release management tools have an advantage over Prodly is that they can choreograph this data load along with releases. I haven’t personally been involved with creating a highly automated configuration data release process from scratch, although it’s certainly possible to do so. If you opt to code such a process yourself rather than relying on a commercial tool, here are some suggested steps you’ll need to undertake to complete that script:
  1. 1.

    Recognize that data migrations require you to address all the steps mentioned earlier that the Metadata API does for you.

     
  2. 2.

    Recognize that the skills and experience for doing this will lie with data migration specialists and that there will need to be some logic built into the process as well.

     
  3. 3.

    Salesforce record IDs and Auto-number fields can vary from org to org, so you can’t rely upon those to represent the lookup relationships between objects when you migrate data to other orgs. Therefore, there must be external IDs on all of the objects in the configuration data model so that you can establish uniqueness and define relationships between records in a way that’s org independent. Configuration objects in managed packages should have external IDs in place already, but if you’ve built your own configuration objects, there needs to be at least one required, unique, external ID field on each of them.

     
  4. 4.

    Assuming the exported configuration data spans multiple objects, the result will be multiple data tables that express their record identity and relationships through external IDs. Those files then need to be loaded in sequence into the target orgs, with parent records being loaded before child records. The Bulk API provides intelligent ways to organize the loading of parent records and child records. But dealing with the Bulk API will require you to do some coding and build some familiarity with its capabilities. The Salesforce CLI introduces the possibility of data:tree:export and data:tree:import to store and transfer structured data, especially configuration and sample data, using the REST API’s Composite resource endpoint. Unfortunately, those commands are limited to 200 records across all trees in one call. This means that to manage large and complex data structures across multiple orgs with minimal overhead, you will need to stitch together many such calls to represent one or more complex data trees. Prepare to do some coding, or retreat to one of the commercial tools mentioned earlier.

     
  5. 5.

    Retrieving and loading these complex trees from one org to another is clearly a challenge in its own right. If you make careful use of external IDs, marking them required and unique, then you can ensure idempotency any time you load this data in. Idempotency means that if you perform the same actions many times, you will always get the same results. In data migration, this is the same as doing an upsert, matching on external IDs, so that you will create any records that need to be created, but you will never create duplicate records, no matter how many times the data load is run.

     
  6. 6.

    The only remaining improvement is a performance improvement, so you’ll need to assess whether this improvement is even beneficial enough to perform. If you’re truly managing large, complex data, it can take a long time to extract, transform, and load that data between orgs. You can make a performance improvement by only retrieving and loading data that has changed since you last checked it. One trick for doing this is to use the REST API’s “Get Updated” calls to see if any configuration has been updated since you last checked. This requires tracking and recalling the last time you ran the retrieval or deployment and then generating a coherent set of record updates based on the results from your query. For example, you can run a “Get Updated” call to check each configuration object for record updates since you last ran the command. You can then update the Git repository or database where you’re storing this data to track the changes or proceed immediately to deploying those changes. When deploying the changes, you need to query your target org to see if configuration changes have been made in that org. You’ll need to have logic to decide whether to preserve the configuration in the target org or in the source org, but if you’re driving your configuration through your delivery pipeline, you’ll always favor the source org. Based on knowing what changed in the target org, you can know what data to reset to the desired values. Based on knowing what changed in the source org, you’ll know what data you need to migrate from source to target. The result of combining these data sets is the data set you need to migrate, which may be significantly smaller than your configuration data set.

     

This whole process is clearly complicated, which is why I believe this is still a nascent idea among most Salesforce development teams. But the same factors that have driven teams to seek a deployment workflow for metadata will increasingly apply to data in complex orgs. Configuration data changes can be too risky to make directly in production orgs, so they should first be done in development orgs. Those changes sometimes need to be complex, spanning multiple objects, which leads to the need to manage and migrate complex data. This is tedious and error prone for an individual to migrate; therefore an automated process is important. Therefore building this capability is important to enable our teams to not just configure but to configure safely and efficiently using a migration process to separate development from deployment.

The Security Model

The Salesforce security model is another complex topic to which I’ll just offer a brief introduction and some tips to help smooth the development workflow. To make things simple, we can divide this into four topics: infrastructure security, login and identity, admin access, and user access.

Infrastructure Security

Infrastructure security refers to securing the underlying servers, networks, and data stores for an organization. This is a massive area of concern for most IT teams, a massive area of risk and liability for most companies, and one of the important areas that Salesforce handles for you. http://trust.salesforce.com can provide you plenty of information on Salesforce’s infrastructure security protocols, certifications, and track record, but needless to say, they do an excellent job of handling this for you.

Login and Identity

Login and identity is handled by Salesforce through a variety of mechanisms. Salesforce provides a wide range of Identity and Access Management (IAM) options such as single sign-on (SSO), various types of OAuth, API access, multifactor authentication (MFA), and so on. Whereas infrastructure security is opaque to Salesforce customers, IAM is highly configurable on Salesforce, and customers take joint responsibility to ensure that this is handled correctly. Salesforce does allow you to track and deploy certain aspects of your IAM configuration between environments, and it can be helpful to manage this in your code repository along with other types of org metadata.

Metadata that defines login and identity is shown in Table 4-2. Notice that there’s some overlap with the list of metadata in Table 4-1 that you might not want to deploy using CI/CD. The reason for this is that this metadata will need to have some variable substitution done if you want to deploy it automatically, and that might not be possible in your first iteration of CI/CD.
Table 4-2

Types of metadata used to manage login and identity

Metadata Type

What It Controls and How to Manage It

SecuritySettings

Includes organization-wide security settings such as trusted IP ranges as well as login session settings such as how soon users are logged out after becoming inactive.

ConnectedApp

Defines your OAuth Connected Apps including their callback URLs and consumer keys. The consumer secret is an important part of this definition, but is not stored in metadata for security reasons.

AuthProvider

Defines social sign-on providers like OpenIdConnect and Facebook that can be used to authenticate users. Social sign-on is typically used to authenticate Community users, as opposed to regular Salesforce users, although OpenIdConnect is becoming increasingly common in the enterprise. For example, Microsoft Azure Active Directory is a cloud-based identity provider which uses OpenIdConnect for SSO.

SamlSsoConfig

Defines your SAML SSO configuration, including the login URLs and validation certificate. SAML 2.0 has traditionally been the enterprise standard for SSO, but OpenIdConnect is increasingly common for enterprise use.

Some aspects of login and identity security are also handled by Profiles, and Login Flows can also affect this. Profiles can be used to specify login IP ranges and times on a per-user basis. Login Flows provide sophisticated authentication options such as calling out to third-party authentication services and assigning temporary session-based permissions.

For teams that are just getting started tracking their Salesforce code and configuration in version control, it may seem like overkill to track this kind of metadata in the repository. In fact in some cases, this metadata needs to vary slightly for different environments. For example, Connected Apps in sandboxes might have different endpoints that point to sandbox versions of other systems. But it is precisely because this configuration is so important that it makes sense to track and deploy it from version control. Many changes to login and identity should be tested in a sandbox first, and in any case, it’s extremely helpful to see a history of changes. An errant admin could readily break integrations, but having version control provides you the ability to roll back and monitor changes. Automating the deployment of some of these metadata types requires that you have the ability to dynamically substitute values as part of your deployment process. This is a native capability of tools like Copado, but we provide an overview of how you can build this yourself in “Managing Org Differences” in Chapter 9: Deploying.

Admin Access

Admin access refers to ensuring that only the appropriate people have permission to make certain changes in your org. Remember that everything in Salesforce is defined by configuration and that even custom code on Salesforce is a form of configuration. You can think of admin access as configuration security, or “what you can/can’t do in the Salesforce Setup UI.”

Salesforce provides a built-in System Administrator profile which possesses “God Mode” privileges in your org. Needless to say, you should be very selective in who is given this profile. Most users would be assigned the out-of-the-box “Standard User” profile, which typically provides the ability to use Salesforce and see data, but not to change configuration.

Admin access and user access are the two areas where admins have the most ability to tune Salesforce to meet their organizational needs. Most organizations will eventually find the need to make a copy of the System Administrator profile and the Standard User profile and begin to customize these according to the needs of their organization.

The traditional method of providing access to control configuration has been through the use of Profiles. But as mentioned earlier, Profiles are a nightmare to manage in version control and typically don’t provide the right level of granularity that teams need. Permission Sets should be your preferred method to manage permissions. You should keep profile permissions extremely thin and instead use permission sets to determine both “admin”- and “user”-level access. If possible, limit your use of profiles to defining things like login IP ranges which can’t be defined in Permission Sets. More details on this are provided in Chapter 11: Keeping the Lights On.

User Access

Whereas admin access determines who can do what in the Salesforce Setup UI, user access refers to what end users can access or modify inside the Salesforce application itself. Data security defines which users have create, read, update, or delete (CRUD) permissions on Salesforce data objects. User access also defines who can use particular Apex classes, applications, Visualforce pages, and standard Salesforce applications like Service Cloud and Knowledge. Permissions in Salesforce are always additive, meaning that the default is for users to have no permissions, but they gain permissions as a result of their profile, user settings, permission sets, and permission set licenses.

As mentioned, all of the admin and user access privileges are defined using profiles or (preferably) permission sets. Permission sets can and should be tracked in version control and deployed as part of your release management process. This provides history tracking on changes to these and ensures that permissions can be tested thoroughly before being deployed to production.

One of the most common failure modes for custom Salesforce applications is for developers to not deploy appropriate permissions along with other metadata. Developers can and should have System Administrator privileges in their own development environment. Such unobstructed access allows them to build capabilities without restriction. But it also makes it easy for developers to forget that end users will need explicit permissions to use what the developer has built.

Developers and testers should use the “Login As” capability to log in to their development and testing environments as one of the target users to ensure those users will have access. If a developer creates a custom application, a new object, with new fields, a tab for that object, a Visualforce page, and an Apex controller for that page, users will need permissions for each of those components. Thus as the complexity of an org increases, so too does the complexity of user permissions.

If you use profiles to manage permissions and you want to give all profiles access to this custom application, then you will need to assign those permissions to every profile. Permission sets thus help you follow the DRY maxim, “don’t repeat yourself.” You can define permissions for this new custom application in a single permission set and then assign that permission set to all users in the org.

Profiles and Permission Sets are both metadata and can be deployed between environments. But which users are assigned those profiles and permission sets cannot be deployed in the same way. This means that when deploying a new permission set to production, you will either need to manually assign this to all users or preferably write a bit of anonymous Apex to query all User IDs and create PermissionSetAssignment records for each user to assign the new permission set to them.

Salesforce is working on the concept of “Permission Set Groups,” which is currently in Pilot. This provides a much more elegant alternative. You attach multiple permission sets to a permission set group and then assign a large group of users to that single Permission Set Group. Permission set groups provide a simple way to bulk assign permissions consistently to a group of users. They can be updated by adding or removing permission sets to a group, and those permission sets can be used across multiple permission set groups.

Permission Set Groups are not accessible via the Metadata API in the pilot, and so you would still need to add any new permission sets to the group manually. If this is eventually made accessible through the Metadata API, then developers will have the ability to create new permission sets in a development environment, add them to the appropriate permission set group, and deploy those permissions all the way to users in production.

A new type of Permission Set called a “Muting Permission Set” is also in pilot. Muting Permission Sets can be added to a Permission Set Group and provide the ability to “Mute” permissions. To my knowledge, this is the first example of Salesforce enabling a negative permission on the platform. The explicit purpose of this is to inhibit permissions that would otherwise be given to members of the group by other Permission Sets in that same group. It might be possible to use this for security purposes to ensure that members of the group are never given powerful admin privileges such as “Modify All Data,” but this use case is not mentioned in the documentation.

Code-Based Development on Salesforce

Salesforce allows for both server-side programming and client-side programming on Salesforce. Apex triggers, Apex classes, and Visualforce are all server-side programming options. Although Visualforce pages include dynamic JavaScript, they are compiled and sent from the server like PHP. Client-side programming includes Lightning Web Components and Lightning Aura Components, but might also include the use of complex JavaScript inside of Visualforce.

This section is very brief, since there are so many other references on how to write high-quality code for Salesforce. You should also refer to the discussions about static analysis and unit testing in Chapter 8: Quality and Testing and to the discussion of “Monitoring and Observability” in Chapter 11: Keeping the Lights On.

Server-Side Programming

Server-side programming in Salesforce allows direct access to the underlying Salesforce data model, and a large part of its purpose is to allow for queries, processing, and transformation on this data that cannot be done through clicks alone. Visualforce provides the ability to build custom user interfaces, although Lightning Web Components are now the preferred method to do this.

Apex

Apex is a strongly typed language, similar to Java, that provides native access to some underlying Salesforce capabilities. The most obvious native capability in Apex is the ability to work with Salesforce data as first-class Objects. So, for example, you can perform a query on Accounts and then perform actions on that data without having to explicitly define an “Account” object. Although Apex compiles down to Java behind the scenes, its most notable limitation is that you can’t use third-party Java libraries or some advanced features of that language.

Salesforce runs Apex on the core platform, and Apex can’t be compiled or run outside of a Salesforce org. The limitations on the language are largely to ensure that it can run safely in a multitenant environment without causing excess load or accessing things that would compromise the security of the platform.

There are actually two kinds of Apex metadata: triggers and classes. Triggers are a concept borrowed from other relational databases and allow custom code to be run as part of a database transaction (insert, update, delete, or undelete). Apex classes are more flexible than triggers, since they allow the use of methods, interfaces, global variables, and so on. Triggers were the first form of custom code allowed on the platform and have a very strictly defined format that does not allow the use of methods or some other capabilities of Apex classes.

Salesforce executes Apex in the context of a transaction. To ensure that no single transaction goes out of control and soaks up excessive system resources, Salesforce strictly enforces governor limits on heap size, CPU time, number of SOQL and DML statements, and so on. These governor limits are uncomfortable for developers accustomed to running code on their own servers, but are a design constraint that encourages code to be performant and balances freedom with the needs of other users on the platform.

Each Apex class or trigger runs using a specified version of the Salesforce API. This wise design decision allows Salesforce to make breaking changes in a new version of Apex without impacting code that was written previously. When downloaded, this API version is shown in a “sidecar file” that has the same name as the class or trigger with an added -meta.xml suffix. As a best practice, classes and triggers should periodically be reviewed and upgraded to the latest API version to ensure optimal runtime performance. In most cases, updating the API version is a trivial change, but it’s possible to face compilation errors, and this is a good reason to write good quality Apex unit tests to ensure behavior remains unchanged even if you update the API version.

It is essential to avoid hardcoding IDs in Apex code or anywhere else. Record IDs are typically different in each environment. Instead, ensure your logic can dynamically identify the proper data to operate against and not fail.

Visualforce

Visualforce allows you to create completely custom user interfaces, using an HTML-like syntax to display information and invite user input and actions. Visualforce also excels in giving access to Salesforce’s internal data model through the use of Standard Controllers or Controller Extensions. A Visualforce page that uses a Standard Controller for Account allows you to create, access, and update Accounts without any other backend code. This page can override the standard record detail or record edit page in Salesforce, thus providing an alternative user interface for working with any Salesforce object.

There are many other capabilities of Visualforce, but it’s fallen out of favor since it’s relatively slow compared to Lightning-based pages. Visualforce pages have to be rendered on Salesforce, and their state is transferred back and forth from the browser each time you perform an action or move to a new page. There are also strict limitations to the size of this Viewstate that make them unsuitable for editing large amounts of data.

Scripting and Anonymous Apex

There are other ways to execute Apex such as creating custom REST and SOAP services. But one form of Apex worth mentioning here is “anonymous Apex,” which is not stored on the server but can nevertheless be run on demand.

Among the many uses of anonymous Apex is the ability to automate predeployment and postdeployment steps in the process of building and delivering an application. Anonymous Apex has the ability to query, transform, and update data, and this includes system-level data such as permission set assignments.

As mentioned earlier, governor limits make anonymous Apex unsuitable to perform massive or long-running data transformations such as migrating data between fields on more than 10,000 records at a time. For this purpose, you can use batch Apex. But there are many practical one-time activities that you can perform using anonymous Apex, such as creating or removing scheduled jobs, triggering batch Apex to run, modifying User Role assignments, and so forth.

Although anonymous Apex is not persisted inside of Salesforce, you can and should save such scripts in your code repositories. This allows for reuse and also provides a clear audit trail should you or someone else need to review the changes that were made.

Client-Side Programming

Client-side programming involves systems where the bulk of processing and state management happens inside the user’s client, either a web browser or the Salesforce mobile app. Lightning Web Components are now the recommended way of creating custom user interfaces, and they provide many benefits over Visualforce. Salesforce’s original Lightning Component technology was based on an open source framework known as Aura. Although it’s a bit confusing and frustrating for developers to have to learn new technologies, it’s par for the course, and there are good reasons why Lightning Web Components have come into being. There are also a variety of other ways to connect to Salesforce from a web client, such as JavaScript Remoting.

Lightning Web Components

Most people who were using the Internet in the late 1990s and early 2000s were aware of the “Browser Wars,” when Internet Explorer competed with Firefox and eventually Chrome for market dominance. But only web developers are familiar with the “Framework Wars” that pitted Angular against React and a hundred other frameworks to provide a more robust way to build applications on the Web.

Web Components are a standards-based alternative to custom JavaScript frameworks that are natively supported by modern web browsers. Unlike custom frameworks like Angular and React, Web Components provide native execution that allows them to run quickly and a consistent syntax that allows developers to reuse their skills more easily. Salesforce was a participant in developing the open standard for Web Components, and Lightning Web Components are an implementation of the standard that is optimized for working with Salesforce.

Lightning Web Components were announced in late 2018, but Salesforce had been quietly rewriting their entire Lightning user interface in LWC for a year or more. This enabled much faster performance and gave Salesforce the confidence that it was possible for customers to mix Lightning Components and Lightning Web Components together on the same page. Salesforce themselves had been refactoring the application in that way for over a year!

Lightning Aura Components

The original Lightning Component framework was based on an open source project called Aura, inspired by AngularJS. Like other code built on custom frameworks, Lightning Aura Components require the browser to do more work, since they have to be compiled into native JavaScript, adding significant amounts of execution overhead.

The vision for Lightning Aura Components is powerful and inspiring, since it allows organizations to build custom UI components using the same technology used to create Salesforce’s own UI. Salesforce Classic is a fundamentally different technology than Visualforce. And Visualforce pages actually run in a separate domain to ensure transaction security and prevent custom Visualforce code from scraping data that it should not have access to.

By creating Lightning Aura Components, Salesforce opened the door to a long-term vision in which developers could seamlessly mix custom components with built-in components, even down to overriding a single field. That vision has not yet been fully realized, and Salesforce is still making incremental improvements to balance flexibility with security. But the Salesforce UI is far more responsive and performant today than before Lightning was rolled out.

JavaScript Remoting, S-Controls, and API Access

There are other client-side coding options on Salesforce that predate Lightning Components. Three official options are JavaScript Remoting, Visualforce Remote Objects, and S-controls. JavaScript Remoting is a technique that allows Visualforce pages to host complex JavaScript applications that can store state on the client side while still sending and receiving data from Salesforce using an Apex controller. Visualforce Remote Objects allow you to create a JavaScript representation of Salesforce objects so you can create, retrieve, and update Salesforce data using client-side JavaScript. S-controls were deprecated many years ago, but were Salesforce’s first foray into allowing custom coding. They allow you to create custom HTML and JavaScript in an iFrame, which can access Salesforce data using the standard Salesforce API.

Salesforce’s API is also what enables a variety of other third-party custom code solutions such as Restforce for Ruby and Simple Salesforce for Python. These prebuilt libraries provide convenient wrappers around the REST API that allow teams familiar with those languages to work with Salesforce data and trigger Salesforce operations. The most significant such library is JSForce for JavaScript. JSForce is now the engine used by the Salesforce CLI to communicate with Salesforce and is also at the heart of many other JavaScript, TypeScript, and Node.js libraries for Salesforce.

Summary

This has been a brief introduction to the process of developing on Salesforce. The Salesforce DX team is responsible for a huge portion of the Salesforce platform, including developer tooling. This developer tooling has been evolving rapidly since the introduction of Salesforce DX, although there are still some key improvements needed. While most Salesforce developers focus on the actual technologies used to build on the platform with clicks and code, we introduced key concepts about the Metadata API that are important for facilitating the entire DevOps process.

We gave a brief summary of the click-based and code-based options for building on the platform, but we intentionally focused on those aspects most relevant to automating deployments to other orgs.

Much has been written about developing on Salesforce, but far less has been said about how to make the release management process easier. Perhaps that’s because the people with the knowledge and skill to manage that process are too busy doing releases to take the time to share that knowledge. Or perhaps they’re so burned out by following manual processes that they don’t want to think or talk about the subject any more. I’ve somehow been fortunate enough to gain release management experience and live to tell about it, especially about how the process can be made easier.

Hidden in between the topics of building and releasing is the topic of architecture. It’s fair to say that you must control your architecture, or it will control you. Salesforce makes it easy to build, which implies that it also makes it easy to build badly. If you’re just beginning down the path of configuring Salesforce, now is the time to study carefully the techniques in the next chapter so you can build your org in a scalable and modular way. If that time has long since passed, then hopefully the techniques in the next chapter can provide you ideas on how to dig yourself out of technical debt.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.154.86