Discover the Benefits of Managed 2GP Package Development
Learning Objectives
After completing this unit, you’ll be able to:
- Describe the benefits of using managed 2GP for package development.
- Explain how both package ancestry and branching support agile package development.
Follow Industry Best Practices Using Source Control and Continuous Integration
Get Cloudy is a Salesforce Partner. Get Cloudy’s engineers have published managed 1GP packages before, but for their upcoming Expense Manager app they’ve decided to create a package using managed 2GP. Since managed 2GP uses a source-driven development model, Get Cloudy's package metadata is stored in their version control system. This is a big win over managed 1GP, where their source of truth was the metadata deployed in their packaging org. And using managed 2GP makes it easy for them to reliably track their changes over time.
Note to managed 1GPers out there—managed 2GP doesn’t require packaging or patch orgs. You no longer need to maintain a unique org for each package.
Knowing that managed 2GP uses an API-first and CLI-oriented development model, the engineers at Get Cloudy are automating all packaging operations using Salesforce CLI. They plan to create end-to-end automation using continuous integration (CI) jobs.
Their CI job launches when a pull request against their source repository is created. The job creates a package version, creates a scratch org, and installs the package in the org. The CI job then runs automated tests to validate that the installed package functions correctly and emails the test results to the release manager. By automating these steps, the developers at Get Cloudy save time to keep working on other aspects of their package.
Share Code Among Small Modular Packages
You may choose to assign the same namespace to all your managed 2GPs. In fact, we think you’ll find that using a single namespace makes interactions between packages easier. Here’s why.
Managed 2GPs that share a namespace can share public Apex classes and methods across all packages in the namespace. When you add the @namespaceAccessible annotation to an Apex class, you make the class available to all packages in that namespace. And by using public Apex, you don’t increase your global Apex footprint by exposing a global API.
With managed 2GP you can easily develop small interdependent packages and share logic between them. If you design your app to rely on small modular packages, package creation and package installation is faster, and you’re less likely to hit limits.
This approach also supports reuse of code across applications. A package with common utility code can be used by two or more published packages. There’s no need to repeat the code for each app.
Note: Keep in mind that you can’t change the namespace at a later date. If you envision selling off your package in the future, the package namespace must be unique. In this scenario, a single namespace across all your packages isn’t the right approach for you.
Managed 2GP Package Versioning Is Flexible
We talked about how managed 2GP is a source-driven development model, and how managed 2GP enables you to share Apex code across packages, but the power of flexible package versioning is where managed 2GP becomes really exciting.
Package ancestry is the term that describes the tree-like version structure used in managed 2GP. Package ancestry is one of the reasons managed 2GP versioning is flexible, because ancestry lets you abandon a package version you no longer want to build on.
Example of a Package Ancestry Tree
We’re going to use this illustration to describe some of the advantages of ancestry. To keep this illustration simple, we only display the first two digits of the package version number: the major and minor values.
Say your team creates version 1.0, then 1.1, then 1.2 and oops! 1.2 made a mess of 1.1. Not a problem. When you create a new package version, you specify which package version is the ancestor. So you abandon 1.2, and make 1.1 the parent of 1.3. Voila! All that spaghetti code your cat typed can be ignored! And this process can be repeated. For example, the illustration shows how to abandon 1.5, and build 1.6 off of 1.4.
With managed 2GP, you must specify an ancestor for each new package version. The flexibility inherent in specifying an ancestor helps you as your package changes and grows over time.
There’s more to package ancestry and there are further benefits than we cover in this module. To learn more, see Package Ancestors in the Second-Generation Managed Packaging Developer Guide.
When you combine source driven development and package ancestry, you get the ultimate flexibility to both select which version in your source control you want to build on and to abandon package versions you no longer want. For those of you who have developed packages using managed 1GP, which is a linear versioning model, this new model makes your development process more agile and less fragile.
Develop Package Versions Based on Branches in Your Source Control System
If your development team uses branches in your source control system, you can build package versions based on the metadata in a particular branch. When you create a package version, tag it with the name of the branch in your source control system. This tagging makes it easy to identify which package versions were based on a particular branch.
Multiple Work Streams Can Develop in Parallel
With flexible package versioning, managed 2GP makes it easy for two or more development teams to build new features in parallel for the same package and then merge them when appropriate. Let’s take a look at how the developers at Get Cloudy do parallel package development using managed 2GP.
Get Cloudy has released three package versions to its customers.
- Version 1.0.0.0
- Version 1.1.0.0
- Version 1.2.0.0
To develop new functionality for their app, Get Cloudy creates two development teams (Dev Team A and Dev Team B). Using the code from the latest released package version, 1.2.0.0, both Dev Team A and Dev Team B make their own branch in their source control system. By creating a branch, each team develops and tests their work, without blocking the other team, or interfering with the main branch.
As the diagram illustrates, feature development happens in parallel until the integration phase where the work of the two teams merges to create version 1.3.0.
The flexible versioning approach to package development supports:
- Building and testing without taking over the main branch
- Easily abandoning unreleased versions
- Improved team agility and velocity
It also takes the fear out of trying new things, ultimately leading to better quality and time-to-market for your app.
Why Make the Move from Managed 1GP to Managed 2GP?
If you’ve been developing managed 1GP packages, the source-driven development model of managed 2GP is a big shift from the org-based development model you’ve been using. But as you can see, there are a lot of benefits available in managed 2GP that don’t exist in managed 1GP.
Using managed 2GP takes away a lot of the tedium and confusion that arise when working with many packaging and patch orgs. In managed 2GP there’s very little interaction with orgs. Instead, you spend your time developing in Salesforce CLI and your development environment. Also, as you may be aware, we’re working on developing capabilities to migrate your managed 1GP packages to managed 2GP. However, even when we launch that capability, there’s still work to be done to migrate your managed 1GP packages and customers that are on it from managed 1GP to managed 2GP. By adopting managed 2GP today for your new packages, you avoid the hassle of migration in the future.
Now that we’ve discussed the advantages of using managed 2GP to develop packages, let’s look at the tools you’ll be using in managed 2GP package development.
Resources
-
Second-Generation Managed Packaging Developer Guide: Why Switch to Second-Generation Managed Packaging?
-
Second-Generation Managed Packaging Developer Guide: Comparison of First- and Second-Generation Managed Packages
-
Second-Generation Managed Packaging Developer Guide: Package Ancestors