I’ve been training a new group of Salesforce.com Users on how to create change sets in a Sandbox, and deploy simple changes (in this case, Email Templates) to production. When we tried to deploy their change set, we encountered some problems caused by a different user group in the same org:
1.) Validation rules had been implemented by System Administrator users in the other group. The validation rules raised nearly a dozen DmlException errors, because they prevented existing Apex test methods to execute their insert / update operations.
2.) The deployment failed because the organization only had 72% test coverage. I hoped that much of this was caused by those same validation rules, but even after setting the offending validation rules to inactive, the org still had only 74% test coverage.
For this particular org, we have a very loose change management process. Business Owners, who deployed and implemented the instances with the help of a third party consultant, still have free reign in the instance. They don’t understand the impact their changes have on the Apex test methods or underlying applications.
I started reviewing the test classes associated with each DmlException error, and noticed a number of test classes had their “Is Valid” checkbox flag set to false.
I misinterpreted what the Apex Class list view was showing me: I saw the blank checkbox next to the word active and immediately thought “Why is this test class being evaluated, if it isn’t active.” I tweeted the question to the world, and my fellow Salesforce developers came to the rescue.
@dschach reminded me that Apex classes are always active:
So then I started poking around in the online help, I found the following notes about the “is Valid” designator:
"To aid backwards-compatibility, classes are stored with the specified version of the API that was used to compile them. Additionally, classes are stored with an isValid flag that is set to true as long as dependent metadata has not changed since the class was last compiled. If any changes are made to object names or fields that are used in the class, including superficial changes such as edits to an object or field description, or if changes are made to a class that calls this class, the isValid flag is set to false. When a trigger or Web service call invokes the class, the code is recompiled and the user is notified if there are any errors. If there are no errors, the isValid flag is reset to true."
I did a quick review of our Apex classes: 36 were set to Invalid. Ugh, that’s a lot of clean-up, and probably more than I can crank through in a single night.
@greenstork gave some helpful advice:
Alas, not so in our case – each of these 36 apex classes remained invalid, even after being viewed in production.
So what’s next?
1.) Short Term: I need to update the various test classes that flagged the DmlException errors, and modify them to support the recently added validation rules. Beyond that, I’ll need to look at other classes that are weak on test coverage, and move those to 100%. Then I can deploy my user's change sets.
2.) Long Term: The enterprise SFA application is much more complex than when the business owners first deployed and starting using it. Changes, like new validation rules or custom object / field edits can no longer be made in production. The business owners must adopt a more structured change management process, restricting their changes to Sandbox environments and allowing a QA/QC team to review the changes before deploying them to production. (Always a difficult political battle in any organization, but essential!)
3.) I need to update our Salesforce Audit report, with a periodic review of the “IsValid” field on Apex Classes. The purist in me says 36 invalid classes is too high; 0 is about right.
4.) I'm gonna need more coffee.
Great post - I'd noticed some anomalies around classes and active/inactive status recently but didn't have the time to chase it down. It started when I tried to set a test class to inactive and was rebuffed.
ReplyDeleteIf you want to see some real interesting invalid class behavior, try naming an apex class after a standard object. Just don't do it in production, a sandbox or anyplace you need that class to function! Turns out force.com doesn't prevent you from creating such a class/object that conflicts with the existing standard object thus causing errors when the platform can't tell which one is which. Headaches ensue...
Try running all tests too. That oftentimes fixes it.
ReplyDeleteIf not, just edit/save the classes and all should be fine.