One of the most powerful tools available in managing change and complexity is by sandboxing applications. This is simply achieved by reducing the number of external dependencies to an applications runtime environment, creating the most natural level of isolation as possible.
One common/obvious way to do this is by having your startup scripts create their own CLASSPATH and to keep all your jar libraries in the local directory tree.
Another way is to build out OS images in VMWare or UML and deploy single purpose system stacks (OS to app). Tools like VMWare let you overcome the fiscal (or emotional) need to collocate more than one application within an OS instance by allowing multiple OS instances on a single machine.
What you must strive to do is build and deploy independent applications without shared libraries and configurations.
Many perl (mod_perl, etc) applications suffer from this if you are using CPAN, or with Ruby when using GEM. These tools install libraries so they can be shared by all.
Development environments should also strive to live in isolation. It's not in your favor to use an older library only because it's the library in production and it isn't worth the effort to upgrade since three other production applications depend on it. I've seen an upgrade of Sablotron whack out a whole set of applications since they all relied on the same bug.
At the OS, this level of coupling is expected since you can't partition your OS much more than it is already. But complexity still arises, as can be seen if you've ever used the FreeBSD ports. I still can't get Erlang to compile due to some broken dependency.
By sandboxing applications within an OS, you have the ability to collocate multiple independent applications. If it's not possible to eliminate shared dependencies between applications, consider partitioning them through multiple OS instances.
If global variables in your code are bad form, so should be global libraries.