I don't think the title and the article really communicates it's case well. Did not understand the goal until 90% through the article when they showed the source code of RCL with the loops.
This isn't syntax vs abstraction. This is how much programming language power do you want to enable in your configuration language. This is a big difference and I think we miss the interesting part of that discussion because we dip into this 'abstraction angle.
To me the solution seems like it's adding complexity that could cause more issues further down the line.
The specific problems in the example could be solved by changing how the data is represented. Consider the following alternative representation, written in edn:
This prevents issues where the region is mistyped for a single bucket, makes the interval more readable by using a custom tag, and as a bonus prevents duplicate bucket names via the use of a map.
Obviously this doesn't prevent all errors, but it does prevent the specific errors that the RCL example solves, all without introducing a Turing-complete language.
> The specific problems in the example could be solved by changing how the data is represented.
Finding the "right" representation for a given set of data is an interesting problem, but most (all) of the time the representation is specified by someone/something else.
In the past I've written a [preprocessor][1] that adds some power to the representation while avoiding general purpose computation. For example,
The intention behind configuration languages is sound but there’s just too many of them. Not having a universally accepted one makes picking one harder. Also, migrating from one to another isn’t as straightforward. Plus,
for database in ["alpha", "bravo"]:
for period, days in period_retention_days:
At this point, you’re better off writing a Python script that spits out some JSON. I‘m aware that even the blog mentions it. The benefit is - having a more expressive language at your fingertips and not having to fight your peers while trying to add yet another idiosyncratic dependency.
I really dislike it when a turing-complete language is used for configuration. It almost always breaks every possibility to programmatically process or analyze the config. You can't just JSON.parse the file and check it.
Also I've been in projects where I had to debug the config multiple levels deep, tracking side-effects someone made in some constructor trying to DRY out the code. We already have these issues in the application itself. Lets not also do that in configurations.
I still have to see a JS project where the config for each tool could not be something simple like `.toolrc`. We could have some markers to delineate plugins config.
Instead, there’s a another software in the configuration of sample projects, instead of just using good code organization and sensible conventions.
This is what's nice about Pkl, you define a schema as a Pkl file, you define a value of that schema as a Pkl file that imports the schema, `pkl eval my file.pkl` will do the type check and output yaml for visual inspection or programmatic processing, but keeping it to one file per module means that I almost never obsessively D-R-Y my Pkl configs.
Actually that's not the biggest benefit (which is tests for schemas) but it's nice to have the “.ts” file actually log the actual config as JSON and then the app consumes it as JSON, rather than importing the .ts file and all its dependencies and having weird things like “this configuration property expects a lambda.”
When Python projects used that approach (setup.py files) that meant to just know what a package's dependencies were, arbitrary code had to be run. Now it's pyproject.toml
pyproject.toml calls into a build backend which is... Python.
It is good to have a simple, declarative entry point to the build system which records declarative elements of the build. The non-declarative elements of the system are configuration-as-code.
And for those that haven't taken a look at it, the "customize" menu and everything it supports is silly impressive. And it just writes out the results out, like a boss.*
* Obviously, it has a lot of "don't edit below this line" complexity to it. But that doesn't change that it is right there.
the answer seems to be both of both worlds - if you're going to do for loops why not just use python?
the answer is both a faux programming language, and really bad ux / really hard to read / scan
maybe what they need is a program that generates better readable text; and somehow you can flip between the determinism of code and ux of readable text?!
The problem with configuration formats, is not syntax, or abstraction, it's the lack of consistent language server integration, it's problem when I can't lookup the definition for a key, the expected type, or quickly jump to definitions that clearly show which keys are available to configure.
To be frank, the clear problem with configuration format is that people have configurations so complex they probably should use something else.
Example: We are programming a backend for a blog. If we were to not use templates, but instead try to get that functionality via the webservice configuration we would have to "invent" some format that gives us the flexibility of templates within let's say a YAML file.
Needless to say that would be a horrible idea. Maybe I am being naive here, but I have yet to be convinced of the fact that it is really configuration formats that are the problem and not what people try to abuse them for. I have yet to work on a project where TOML wasn't enough for actual configuration.
Usually when I need something more complex than what can be done with TOML it is a sign that this needs to be handled differently. Via templates or with a database or making a special DSL-like script file. E.g. if you're using python nothing (except security considerations) stops you from allowing users to use a python file for configuration. If your configuration needs are really that complex, why not use a real programming language for it?
Two examples of complex user facing configurations I can think of are pretty trivial to implement:
- Decision tree, where you only need comparison operators. The leaves are a specified list of actions.
- actions list with macros (variables). You can be fancy and add some conventions for arrays.
Anything more that that should just be a programming language. And if the relationship is adversarial (saas), you should really think hard about needing something that complex.
Code as configuration loses one primary benefit which is being able to read the actual config and know exactly what will apply. In the example in the article you would get the same benefit by disallowing users to edit the config directly and instead require the config to be generated via a cmdline app/service that encodes the same policy?
As someone who's spent most of their career in cloud IAC, and likes to think they are pretty read up on the latest going on in that world, if you didn't know better you'd think YAML is one of the greatest threats facing mankind. There are plenty of things I certainly hate about it, but every configuration syntax I've ever used I have similar gripes about. It's like once a month this kind of "The world is growing tired of yaml" claim is just thrown out there like everyone just agrees with it. Choose something that works for you. This author repeatedly mentions TOML but there are plenty of issues with that one I could point out too. Syntax is one very small part of what makes an ecosystem great or not so great. Most of my exposure to yaml is helm chart templates, which admittedly is not pure YAML, but it works fine enough for me, at least to where I don't feel like writing lengthy blog posts about how much I hate it. I even wrote a library that converts yaml templates to HCL for internal use because I got so sick of people having this exact same argument like it deeply mattered. And guess what? They hate the HCL too.
I also think that a lot of the problems with yaml specifically are overblown, but this post is actually not about that!
It is specifically saying the same problem exists in JSON/YAML/TOML, etc, which is that all these configuration languages don't have any real means of abstraction, and ultimately aren't expressive enough do to the job we require of them.
as soon as you are templating config files with other configs, I agree, I have sorely felt this limitation with helm charts
Serious question: do people who work with these config files frequently, or on large such files, use simple text editors, or are there "smart" editors that do things like prevent you from making typos or inserting the wrong data type, similar to an HTML form that does basic validation or a DB schema that rejects bad data?
There is no single cure-all, of course, but surely we should be relying on computers to do much of the heavy lifting when it comes to validation and verification of these files, not just as linters after the fact but in realtime while we're editing, and with some sort of knowledge (even if derived programmatically) of what is right and what is wrong so we no longer have to worry about simple footguns.
I think one of the problems of those "configuration languages" is that you can extract semantic information without knowing the target, e.g., with has a specific meaning in GitHub Actions but it is otherwise an unremarkable word in the YAML specification.
But when working with real programming languages it is completely different, you can take semantic information from the current code, and you can have things like types to give you safety.
The problem is most configuration languages are declarative vs imperative like most “real” languages are. You could probably levy the same complaint against declarative languages in general - it’s just a different way of thinking
It's like bike shedding. It's a side effect of mixed expertise (and confidence) working together on things that are only partially understood by all. When something is clearly outside one's expertise, they are content to leave it to others. But then you'll get minor questions with low stakes like "what color to paint the shed". And how everyone feels like they can participate, so suddenly there's a huge discussion / debate / argument about a very, very minor thing.
HCL is generally great, but has some issues with clarity of transformation to the underlying data structures.
But anytime someone suggests TOML I have to double check to be sure they are serious because the TOML syntax for anything more complicated than single-layer maps is mind-bogglingly confusing to me. This is not a serious alternative to YAML.
I don't think the title and the article really communicates it's case well. Did not understand the goal until 90% through the article when they showed the source code of RCL with the loops.
This isn't syntax vs abstraction. This is how much programming language power do you want to enable in your configuration language. This is a big difference and I think we miss the interesting part of that discussion because we dip into this 'abstraction angle.
To me the solution seems like it's adding complexity that could cause more issues further down the line.
The specific problems in the example could be solved by changing how the data is represented. Consider the following alternative representation, written in edn:
This prevents issues where the region is mistyped for a single bucket, makes the interval more readable by using a custom tag, and as a bonus prevents duplicate bucket names via the use of a map.Obviously this doesn't prevent all errors, but it does prevent the specific errors that the RCL example solves, all without introducing a Turing-complete language.
> The specific problems in the example could be solved by changing how the data is represented.
Finding the "right" representation for a given set of data is an interesting problem, but most (all) of the time the representation is specified by someone/something else.
In the past I've written a [preprocessor][1] that adds some power to the representation while avoiding general purpose computation. For example,
Macros, basically. Arithmetic would help there, but that might be too much.[1]: https://github.com/dgoffredo/llama
The intention behind configuration languages is sound but there’s just too many of them. Not having a universally accepted one makes picking one harder. Also, migrating from one to another isn’t as straightforward. Plus,
At this point, you’re better off writing a Python script that spits out some JSON. I‘m aware that even the blog mentions it. The benefit is - having a more expressive language at your fingertips and not having to fight your peers while trying to add yet another idiosyncratic dependency.Really wish people would just bite the bullet and do configuration as code instead of trying to make all these config petlangs.
I appreciate that the ts/js ecosystem seems to be moving in this general direction.
Lots of config.json is being replaced by the nicer config.ts.
I really dislike it when a turing-complete language is used for configuration. It almost always breaks every possibility to programmatically process or analyze the config. You can't just JSON.parse the file and check it.
Also I've been in projects where I had to debug the config multiple levels deep, tracking side-effects someone made in some constructor trying to DRY out the code. We already have these issues in the application itself. Lets not also do that in configurations.
I still have to see a JS project where the config for each tool could not be something simple like `.toolrc`. We could have some markers to delineate plugins config.
Instead, there’s a another software in the configuration of sample projects, instead of just using good code organization and sensible conventions.
This is what's nice about Pkl, you define a schema as a Pkl file, you define a value of that schema as a Pkl file that imports the schema, `pkl eval my file.pkl` will do the type check and output yaml for visual inspection or programmatic processing, but keeping it to one file per module means that I almost never obsessively D-R-Y my Pkl configs.
Actually that's not the biggest benefit (which is tests for schemas) but it's nice to have the “.ts” file actually log the actual config as JSON and then the app consumes it as JSON, rather than importing the .ts file and all its dependencies and having weird things like “this configuration property expects a lambda.”
That's why Starlark exists.
You need something between JSON/YAML and Python/JavaScript.
A config language makes the possibility space small.
It also makes it deterministic for CI and repeatable builds.
It also makes it parallelizable and cacheable.
Don't use your language for config. People will abuse it. Use a config language like Starlark or RCL.
My preference is towards simpler formats like:
Easy to edit and manipulate. JSON and YAML is always a nightmare if it's user facing. As for ansible, I'd love to see some scheme/lisp variants.When Python projects used that approach (setup.py files) that meant to just know what a package's dependencies were, arbitrary code had to be run. Now it's pyproject.toml
pyproject.toml calls into a build backend which is... Python.
It is good to have a simple, declarative entry point to the build system which records declarative elements of the build. The non-declarative elements of the system are configuration-as-code.
Exactly. Emacs Lisp is an existence proof that this can be done well.
You beat me to it!
And for those that haven't taken a look at it, the "customize" menu and everything it supports is silly impressive. And it just writes out the results out, like a boss.*
* Obviously, it has a lot of "don't edit below this line" complexity to it. But that doesn't change that it is right there.
This year I started using an SQLite file specifically for config values
Have used everything from Json to Cue and in-between. Tired of the context switch. Need to use SQL anyway. Fewer dependencies overall required.
Curious - how do you version the config?
I'm guessing they version a SQL file
Yes, though languages need to develop and provide restricted execution modes for "configuration as code" for security enforcement.
the answer seems to be both of both worlds - if you're going to do for loops why not just use python?
the answer is both a faux programming language, and really bad ux / really hard to read / scan
maybe what they need is a program that generates better readable text; and somehow you can flip between the determinism of code and ux of readable text?!
(is that possible)
The problem with configuration formats, is not syntax, or abstraction, it's the lack of consistent language server integration, it's problem when I can't lookup the definition for a key, the expected type, or quickly jump to definitions that clearly show which keys are available to configure.
To be frank, the clear problem with configuration format is that people have configurations so complex they probably should use something else.
Example: We are programming a backend for a blog. If we were to not use templates, but instead try to get that functionality via the webservice configuration we would have to "invent" some format that gives us the flexibility of templates within let's say a YAML file.
Needless to say that would be a horrible idea. Maybe I am being naive here, but I have yet to be convinced of the fact that it is really configuration formats that are the problem and not what people try to abuse them for. I have yet to work on a project where TOML wasn't enough for actual configuration.
Usually when I need something more complex than what can be done with TOML it is a sign that this needs to be handled differently. Via templates or with a database or making a special DSL-like script file. E.g. if you're using python nothing (except security considerations) stops you from allowing users to use a python file for configuration. If your configuration needs are really that complex, why not use a real programming language for it?
Two examples of complex user facing configurations I can think of are pretty trivial to implement:
- Decision tree, where you only need comparison operators. The leaves are a specified list of actions.
- actions list with macros (variables). You can be fancy and add some conventions for arrays.
Anything more that that should just be a programming language. And if the relationship is adversarial (saas), you should really think hard about needing something that complex.
Code as configuration loses one primary benefit which is being able to read the actual config and know exactly what will apply. In the example in the article you would get the same benefit by disallowing users to edit the config directly and instead require the config to be generated via a cmdline app/service that encodes the same policy?
As someone who's spent most of their career in cloud IAC, and likes to think they are pretty read up on the latest going on in that world, if you didn't know better you'd think YAML is one of the greatest threats facing mankind. There are plenty of things I certainly hate about it, but every configuration syntax I've ever used I have similar gripes about. It's like once a month this kind of "The world is growing tired of yaml" claim is just thrown out there like everyone just agrees with it. Choose something that works for you. This author repeatedly mentions TOML but there are plenty of issues with that one I could point out too. Syntax is one very small part of what makes an ecosystem great or not so great. Most of my exposure to yaml is helm chart templates, which admittedly is not pure YAML, but it works fine enough for me, at least to where I don't feel like writing lengthy blog posts about how much I hate it. I even wrote a library that converts yaml templates to HCL for internal use because I got so sick of people having this exact same argument like it deeply mattered. And guess what? They hate the HCL too.
I also think that a lot of the problems with yaml specifically are overblown, but this post is actually not about that!
It is specifically saying the same problem exists in JSON/YAML/TOML, etc, which is that all these configuration languages don't have any real means of abstraction, and ultimately aren't expressive enough do to the job we require of them.
as soon as you are templating config files with other configs, I agree, I have sorely felt this limitation with helm charts
Serious question: do people who work with these config files frequently, or on large such files, use simple text editors, or are there "smart" editors that do things like prevent you from making typos or inserting the wrong data type, similar to an HTML form that does basic validation or a DB schema that rejects bad data?
There is no single cure-all, of course, but surely we should be relying on computers to do much of the heavy lifting when it comes to validation and verification of these files, not just as linters after the fact but in realtime while we're editing, and with some sort of knowledge (even if derived programmatically) of what is right and what is wrong so we no longer have to worry about simple footguns.
I think one of the problems of those "configuration languages" is that you can extract semantic information without knowing the target, e.g., with has a specific meaning in GitHub Actions but it is otherwise an unremarkable word in the YAML specification.
But when working with real programming languages it is completely different, you can take semantic information from the current code, and you can have things like types to give you safety.
The problem is most configuration languages are declarative vs imperative like most “real” languages are. You could probably levy the same complaint against declarative languages in general - it’s just a different way of thinking
I'm trying to remember the phrase. Something like, "there is nothing as vicious as low stakes fights."
Trying that on Google gets me https://en.wikipedia.org/wiki/Sayre%27s_law. Is about right. :D
It's like bike shedding. It's a side effect of mixed expertise (and confidence) working together on things that are only partially understood by all. When something is clearly outside one's expertise, they are content to leave it to others. But then you'll get minor questions with low stakes like "what color to paint the shed". And how everyone feels like they can participate, so suddenly there's a huge discussion / debate / argument about a very, very minor thing.
HCL is generally great, but has some issues with clarity of transformation to the underlying data structures.
But anytime someone suggests TOML I have to double check to be sure they are serious because the TOML syntax for anything more complicated than single-layer maps is mind-bogglingly confusing to me. This is not a serious alternative to YAML.
Should be titled “the power spectrum of data” or something similar
the article talks about the trade off between plain data structure versus abstract ones and that’s the main issue
Yes, one more DSL on your Tower of Babel tech stack will save you.
If you want configuration-as-code use Python. Please. Or Tcl if you must. Do not invent N+1 DSL for your engineers to waste time learning.
FOR loops?
YAML has a merge key <<:, which might be helpful.
The merge key is a clever little trick, but it depends of the special hash key, so lists can’t be merged.
Syntax does matter, which is why YAML matters — even if imperfect.