The "service" mechanism in Guix System is designed in part as a reaction against those the NixOS module design you're describing: I think the ambient authority, free-style extension mechanism of NixOS modules makes it hard to reason about it (any module can change the config of any other module), and it makes it easy to shoot oneself in the foot (with infinite recursion in particular, as you write).In Guix System, services extend one another, forming a directed acyclic graph of extensions. When a service extends another service, that connection is explicitly declared, there's no surprise.
To see what it means in practice, check out the Explorer:
https://notabug.org/civodul/guix-explorer
t0astbread|2 years ago
The service model in Guix looks pretty neat! I've long been thinking it would be nice to have a configuration system for NixOS that uses isolated components with a defined (type-safe) interface. The current modules are kind of that, except it all gets squashed down into a single nested attribute set, so it's not really isolated and (understandably) can be confusing. How does Guix System handle multiple services competing for the same global resource (port allocation, file in /etc, ...)?
civodul|2 years ago
There are other things that are detected statically and prevent you from instantiating a broken system: missing modules in the initrd, invalid file system label/UUID, references to non-existent Shepherd services, etc. All this is possible because there are well-defined data types and semantics for the different components of the system.