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


Reply via email to