We want to use Metacello to manage smalltalk dependencies in a way that
results in working software using a minimum amount of manual work. At
the moment there are several ways in which Metacello is used, some of
which result in more work and instability than others.
An inherent conflict in managing these dependencies is the level of
repeatability that is wanted and achievable, vs. the amount of manual
work needed. On the one hand we would like perfect repeatability. That
needs an exact description of the order in which specific versions of
packages were loaded in a specific image. In Metacello, we can achieve
this by making sure all package versions are fixed and the dependencies
are fixed to numeric versions.
The problem with this is that that not necessarily results in working
software. There are several reasons for this:
- Metacello only manages the smalltalk level dependencies. It does not
take into account changes in the vm necessitating image-level changes or
operating system and library changes.
- The image itself is not fully managed with Metacello (yet). Bug fixes
made after the creation of the Metacello version might be needed for the
software to work.
- Bugs might have been found and fixed in dependencies.
In the situation of a top-level configuration, i.e. one that no other
configuration depends on, this might be acceptable. Metacello
dependencies are defined one-directional. A configuration knows on which
configuration it depends, not which configurations depend on it.
Configurations that are published should therefore always be regarded as
possibly being used by others, and not only top-level.
If we consider the situation where others (B) are depending on
configurations (A) that are written like this, then the situation gets
worse:
- B might need an update because it is affected by an issue that does
not affect A.
- B might need a different load ordering, e.g. need to only partially
load dependencies of A, then something itself and then the other
dependencies of A.
Nevertheless, sometimes we need near-perfect repeatability. For that, a
snapshot of all loaded packages provides a reasonable alternative to a
Metacello configuration version.
On the other hand the least amount of manual updates results from always
depending on #development or #stable versions of dependencies. This
results in the following problems:
- If the API of a dependency changes, the configuration might break
silently.
- Projects might be slow to promote versions from #bleedingEdge to
#development to #stable, resulting in a slow uptake of improvements.
For configurations of simple packages that have an API that is very
stable or only expands, depending on #stable can be appropriate.
From a modularity point of view, a configuration should be specific on
the packages in its own span of control, and as generous as possible in
what it accepts from its dependencies. In that way a high cohesion and
low coupling is achieved. We can achieve that by defining symbolic
versions that reflect observable change in behaviour. If we make changes
that should not affect users of the configuration, we create a new
numeric version and update the symbolic version in place to use this new
version. By default we only depend on these symbolic versions.
Stephan