> However, when there are breaking changes, random.garbage needs a new version (e.g. 0.6.etc instead of 0.5.etc).
IMO the best way to do that would be to get everyone in the habit of including the version in their modules. module random.garbage.0.6; import random.garbage.0.6; That way, it is explicit, in the code itself, what you need and what the library provides. This also lets the two versions reside next to each other. Say I import cool.stuff.1.0. cool.stuff imports useless.crap.0.4. But I want useless.crap.1.0 in my main app. If they were both called just plain old "useless.crap", the two imports will probably break something when we build the whole application. But if the version is part of the module name, we can both import what we need and use it at the same time. There would be no "import useless.crap" module provided that actually does work. At best, it'd say pragma(msg, "useless.crap.1.0 is the most recent, please use it"); If the thing without version annotation actually compiles, it'll break eventually anyway, so forcing something there ensures long term usefulness. The bug fix version wouldn't need to be in the module name, since they are (ideally) forward and backward compatible. Unit tests could probably confirm that automatically.