Last week, we covered how to evaluate code that is developed to extend cloud applications. Now we're going to take a look at coding and system modification strategies that can make the system more fragile over time. Since CRM systems have requirements that seem to evolve endlessly, durability of your code is a key success factor to long-run success of these systems.
But before I start, a disclaimer: the examples and terms I use as examples apply to the Salesforce.com environment. Other application environments and platforms use different terms (and even different abstractions), but I simply don't know them as well -- so please don't interpret this as shilling for Salesforce.com.
The Tension Between Declarative Development and Programming
Cloud-based applications have a bias towards what the vendors call "declarative development," because it's unambiguous, easier to learn, and easier to control in a SaaS environment. So most cloud applications will make heavy use of validation rules on fields, constraints on fields and tables, and workflows on objects. This works fine in the early days, and provides a surprising amount of power and functionality.
The trouble comes when you add code, particularly anything that creates new records. When developing that new trigger, class, or integration "listener" service, the coder may be working in a development or sandbox environment that isn't configured identically to the production system. So when pushing the code to production, all kinds of error conditions are thrown -- and they may not be reproducible in the dev environment. Unfortunately, the error messages can be very ugly for users -- and they may not even provide many clues for the troubleshooter.
So, the first set of tips:
1. Make sure that developers work in a recently-refreshed "sandbox," so they aren't surprised by the configuration of the production environment.
2. To the degree possible, enable integration adaptors and other plug-ins in the sandbox, so that developers can see the ramifications of state changes (particularly the "reflection" of error conditions back from outside sources).
3. Once you start developing extensions and functionality around an object, remove all validation rules and re-implement them inside your low-level code so that you can predictably trap and control error conditions.
4. In a similar vein, replace any workflows that do field updates with low-level code implementations.
5. Create an administrative policy that makes it very difficult to create new validation rules or workflow-driven field updates.
6. Make sure you put code in to provide guard-rails in front of field or table constraints, essentially pre-checking the values to ensure they don't hit any walls.
7. Check every field for NULL, and check every set, list, or map for EMPTY before you try to use it in any logic (yes, even any error- checking logic).
8. As mentioned in Error Handling in the Clouds, write classes that handle all application errors in real time send them as messages to centralized error-logging services elsewhere in the cloud.