1. Buildpacks cannot have dependencies
As things stand today, much of the code for any given component (e.g. Tomcat, Grails, etc.) is shared. This includes bits like logging, dependency resolution, and detection. The buildpack is written in Ruby and could potentially share code via gems, but there’s no point in the buildpack lifecycle where bundle cloud be called because there’s no guarantee that a buildpack is written in Ruby. We toyed around with the stager detecting that a Gemfile.lock exists and calling bundle then but it was an edge case for an unproven buildpack, so it never went anywhere. There's also the penalty to be paid every time a gem needs to be downloaded when an application staged. All things considered, I think the earlier decision to stick to the no-dependencies rule has driven us to be very focused on a minimal buildpack.
2. Only a single buildpack can be run
The Java Buildpack is designed with three
orthogonal component types. A single JRE is selected (OpenJDK by default, but we support Oracle, and the Liberty buildpack supports J9), a single container is selected, and any number of frameworks are selected. Regardless of which JRE is selected, a container must be selected. Regardless of what container is selected, any number of frameworks can be selected (e.g. you might want New Relic, custom
JAVA_OPTS, and Spring Auto-reconfiguration all simultaneously). The current design essentially gives us “multi-buildpack” functionality, for JRE-based applications (that's why the
component API looks
so familiar...). Way back in the beginning, trying to justify "multi-buildpack" functionality was difficult and thus wasn't ever incorporated into the stager. As Mike points out, it has proven valuable and we might want to open discussions about it again.
In general, Heroku’s choice of containers as a dominant decomposition only works because their buildpacks aren’t as sophisticated as ours is. They force users to explicitly configure much of the stuff we do (and want to do more of) automatically; I consider a user doing anything other than a `cf push` to be a failure on our part in most cases. Even if we wanted to aim for a container-based decomposition as they do, the need to duplicate much of the of the functionality is hamstrung by #1.
-Ben Hale
Cloud Foundry Java Experience