For a long time, In the world of ISVs and Managed Packages, we worked one big overriding principle:
Be careful what you put in a package, because it’ll stay there forever
As you probably know, though, requirements tend to quickly evolve and that often led to code and object baggage that stared us in the face and which we could do nothing about. It’s like not being able to throw the trash out in a house… it piles up and makes things look ugly.
Slowly, we started being able to deprecate and eliminate some things. Until now, however, packages built using 2GP didn’t get any of that love. As of Spring 22, that is no longer the case.
Salesforce has just made GA a feature that lets package developers remove metadata from packages, helping keep packages smaller and tidier. At the same time making it much easier to keep enhancing without making it as hard to do mass re-architecture when warranted. “Remove” is a bit of a misnomer however, as we’ll see below, but it is a much welcome feature nonetheless.
How does this work?
Before you attempt this, you first must ask Salesforce to enable this feature for you. Start by logging a case at the Salesforce Partner Community. Once that is done, then you’re good to go.
Removing metadata is surprisingly easy, mechanically. You just get rid of the things you want and create a new package version. You’re thinking this is too easy to be true? You’re right.
The first thing you need to know is that not everything is deletable, but a surprisingly large number of components are (full list here). I think most of the most common things developers would like to remove from packages are covered, so I won’t spend too much time on this.
Secondly, and here is something you might’ve guessed, most “deletes” are not really deleted, but instead are marked as “deprecated” and left behind in the subscriber org for the admin to delete. This makes sense, if a client has an integration to an Object, a Quick Action on a non-package page layout or needs a Record Type you wouldn’t want to break that org, right? Instead, those items are no longer included in the package, and the admin can now make the necessary changes and delete things when they’re ready.
The next thing is more important. Just because you can delete something on paper doesn’t mean you can actually do it in practice, or easily. Why? Dependencies. Metadata seldom lives in a vacuum, and so when you delete something, you have to ensure nothing that remains in the package needs to be referencing it. This is especially true for if you use dependency injection or any sort of dynamic reference to your objects, since the compiler won’t catch it.
While in some cases you can do it all in one step, best practice is to deprecate things over two cycles, where in the first cycle you remove all the dependencies in your code and ensure the clients get that version. Then, once dependencies are out of the way, deletion of the code as the second cycle is straightforward.
While talking about dependencies, if you have a multi-package environment, you must be extra careful. If you ever want to delete something annotated with @namespaceAccessible make sure to break the other packages’ dependency first. And then proceed to remove the code.
As usual, global things (classes, VF Components, etc) are the most obvious caveat here, as those restrictions are still in place and you cannot delete them from your package at all.
Things to keep in mind
As you just read, removing items from your package can be deceptively simple, but it turns into a rather involved process if you have many dependencies (internal or external).
Also, and this is especially true when deprecating fields and objects, you have to remember that your subscribers might’ve extended your solution beyond what you anticipated, so you should be mindful to provide data migration and upgrade paths, to assist your customers in adjusting their orgs to your changes. It also stands to reason that your support system will see increased volumes of requests to handle this.
Flows deserve their own paragraph. As they are growing in popularity with astonishing speed, you can expect a lot of your global code to be used in some way by Flows in client orgs. Since most people never bother with deleting old flow versions, it is entirely possible that deprecated metadata can’t be permanently deleted from an org because it is referenced by flow versions that are no longer active.
Finally, it’s also worth noting that the admins of your subscriber orgs don’t have to delete deprecated things. This is important because if you decide to recycle the names of those components in the future (by, for example, creating an object with a name identical to an object you deprecated in the past) then your app won’t be installable in orgs where the old metadata still exists.
All of these things lead to a very clear conclusion. Communication is key. If you’re going to deprecate metadata in your org, plan it ahead of time and communicate it to all of your stakeholders (both clients and internal) with plenty of advance notice. Document all you can, and provide that documentation to everybody who might need it, and be sure to warn about the consequences of not following the process outlined. That way, you will not end up in a situation where you have an unexpected number of customers with issues because they didn’t know what needed to be done to stay updated.
I feel I have written this line every time I post an article. Just because you can do something doesn’t mean you should. Deleting metadata from a package is now easier than ever, but it is also very tempting to “just do it” without thinking it through.
As we saw above, if you must do it, plan it carefully, communicate with your clients and stakeholders, document it carefully and announce it with time. Only then, do it. At least when you get to the last part, though, the going just got a lot easier.
We help companies leverage Salesforce to transform their businesses.. If you’re looking for guidance on your product, help supporting your customers, or just need to ask an expert, get in touch today!