Sadly, I don't think you are missing anything - when I have asked SF folks, they view this is a feature because customers can update the lists themselves, and these updates should not be overridden by a package update.
There are some ideas on the exchange about having an option in a package to enable picklists to be always overridden, but for now, manual updates are the only option I know of...
Great question. In opening this can of worms, I would like to noodle the premise if you don't mind :-) just to learn if we're solving performance in the right quadrant. What motivates your question exactly?
easy problem ^ hard problem
easy solution | easy solution
|
[start here] | [graduate to here]
|
<--------------------+-------------------->
|
[dragons be here] | [data scientists]
|
easy problem | hard problem
hard solution | hard solution
Definitely performance is important, but the Force.com platform is pretty good at keeping you within reasonable boundaries. You don't have to worry about nginx
vs iis
vs apache
serving XYZ
requests per second. Float above that stuff. Salesforce throws smarts and hardware at those problems so we don't have to.
As a service layer developer, err on the side of inspecting:
- performance of callouts (web services, third party hooks hanging off your controllers, or crazy stuff living in JavaScript code facing your users via custom buttons, etc)
- if you're an ISV developing real product, keep swathes of DML out of tests for your patience/sanity's sake, check large inserts and large deletes aren't anywhere near governor limits,
- check your use of asynchronous tools / set-and-forget methods (like @future, batches, schedules) to detour any heavy lifting away from execution contexts invoked by user interfaces,
Rather than doing legwork for the sake of the Apex runtime, optimize for you the architect, us the developers, them the future maintainers. The Apex runtime will get faster and smarter, you don't need to do it any favours. Principle of least astonishment and semantics wins over tricks every time.
Governor limits are the thoughtful and useful straitjacket that gives us a gentle slap in the face as course correction if code falls outside those reasonable boundaries.
As a client-side developer, invest your valuable time:
taking advantage of speedy (JavaScript Remoting) and reactive (Streaming API) features to offer the snappiness (or perceived snappiness) your users expect, decoupled from Apex performance,
check the expires
attributes of pages holding JavaScript clients, the cache control
attributes of static resources (zips of course, concatenated CSS/JS courtesy a non-overkill build script)
profile first, shoot later!
Best Answer
As I have gotten familiar with others implementations and best practices over time I tend to use both in different situations.
Interfaces:
Interfaces are absolutely fantastic for generalized API's that are re-used in many different contexts. For example: Apex-Lang's ArrayUtils.qsort I have made it a requirement in the past that all sorting outside of SOQL should be implemented using this interface. Why? because of the interface you can sort any object by its properties in a completely predictable manner, every time. No multiple dictionary mutation funny business. It cleanly provides a very clear re-usable approach to sorting objects, much like the Comparator interface in Java.
What are interfaces not good at? I have never had good luck implementing an interface as a controller for a visualforce page. Why? Because visualforce requires getter/setter methods in order to access properties and the idea of having to define each and every getter setter and then implement it defeats the purpose of re-usability.
This brings us to abstract/virtual classes.
Abstract/Virtual Classes:
In Apex abstract classes are great for creating re-usable patterns for implementing controllers (among other things). If you ever implement a visualforce page in a site you'll find that if there is any uncaught runtime error the user will only see a stanard permission exception page (hell to debug). Instead of try catching every single contructor or initalize/action method you can write an abstract class that implements the various constructors and then use a one line method in the child class: (psuedo code)