I’ve been using Cue for over a year now, using it as the foundation for a new projet; and will gladly answer questions about our experience.
I’ve been using Cue for over a year now, using it as the foundation for a new projet; and will gladly answer questions about our experience.
For example, for any given application we have several fixed environments--dev, staging, prod--as well as "on demand" environments for things like pull requests or individual developer environments. The configs for these environments are almost the same, but they vary based on a handful of parameters. I want to be able to write a "generic environment" module for each application and then parameterize it accordingly for each environment.
Cue doesn't seem to care much about this problem, but rather it's just trying to make sure your data is type checked. It seems more like an advanced JSONSchema rather than a typed Starlark. I think the latter would be more powerful (albeit Cue's type system is more powerful than an ordinary generic type system with things like range types).
Cue almost has an answer to the DRY problem, but you can't quite emulate functions as far as I can tell (due, I think, to shadowing problems). I wonder what people who are convinced that Cue is the future would say to this? Am I just thinking about the problem wrong?
> I want to be able to write a "generic environment" module for each application and then parameterize it accordingly for each environment.
This is pretty solidly in the target use case range, i'd say - managing variations of the same "object type" over some dimension is a lot of what's targeted by the way that CUE treats directory hierarchies when loading files: https://cuelang.org/docs/concepts/packages/#instances
The main thing you have to consider in designing a layout is that you have to take a compositional approach to how you define individual config instances. That is, you can't start from prod's config, then override a value or two for staging.
If i were to do it - i have not, this is not how i currently use CUE - my first approach would probably be by defining defaults at the "policy" level (per the above link), which effectively allows you to get exactly one "override"-ish behavior.
Lots of possible approaches to this, though.
> but you can't quite emulate functions as far as I can tell
Function-like capability is present, just in a form that's less familiar. I think of them as "function structs." This post has a bunch of examples https://github.com/cuelang/cue/issues/139#issuecomment-55677.... It seems there's a plan to add a more comfortable notation (https://github.com/cuelang/cue/issues/943), but it's fundamentally possible now.
How would you solve this with directory structure and "function structs" respectively? I'm having trouble wrapping my head around the former and ran into shadowing problems with the latter.
test.cue:
#Job: {
command: string
args: string
cli: "\(command) \(args)"
}
#GoJob: #Job & {
command: "go"
}
#GoJobV: #GoJob & {
args: "-v ./..."
}
job: #GoJobV.cli
Results in: $ cue export test.cue
{
"job": "go -v ./..."
}This specifically looks like you want inheritance, which Cue eschews.
You can set up a generic config with default values for everything, and then have more specific configs that override the defaults.
A concrete example would help figure out if Cue can do what you want.
FWIW, I'm not looking for "inheritance".
I was going to say the same thing - this pattern of having an "override" file in add to defaults, is something I've seen in multiple systems and liked. For example, it's used for JSON configuration in .NET, and with Docker Compose's YAML service configuration files.