HOCON – Human-Optimized Config Object Notation
github.com
github.com
Here is my take on the why not JSON / why not YAML questions: https://blog.ometer.com/2015/09/07/json-like-config-a-spectr...
Short answer is "UX"
There's also a historical reason, Play Framework and Akka had both invented ad hoc formats, HOCON replaced both. The ad hoc formats added things like includes and substitutions but in regex-hack type of ways. So HOCON was cleaning those older parsers up with a single actually-documented format.
Why it's not JSON:
* includes
* substitutions
Why it's not YAML:
* less confusing syntax (e.g. `cannot do that` doesn't need quotes, but `can't do that` does)
* built-in support for overrides via env variables
Why it's not JSON or YAML:
* Built in durations! No more head scratching to figure out if 5 is seconds or milliseconds. It's just `5s`.
---
JSON is a data transfer format. YAML is a markup language (or it claims to be...).
HOCON is a composable configuration language. You always need to change, override, and deduplicate configuration in sensible way, in dev, in production, machine-by-machine.
Despite a wart or two I think HOCON takes a sensible to this ubiquitous problem.
In any case, yaml.org currently describes it as "human friendly data serialization".
I don't think YAML is a bad choice, but HOCON's explicit focus on configuration yields some nice benefits.
The misconception is what might work as a human-readable serialization format is usually tedious as a human-editable configuration format.
Unless your app accepts configuration files as untrusted input, it is really not that hard to write a custom key-value -type parser. Think OpenSSH or Samba config files - I find them well-suited for their respective jobs, as they achieve the required level of expression with minimal necessary complexity.
It's not. But then you want to set up that config automatically. So you template them. Then you discover they have slight differences in what they accept and how they handle unknown/repeated values. Then you discover they have different escaping rules. Then that one needs non-latin characters quoted. etc. etc.
It's not easy to write parser for each one of them. But if you're installing a full server with 10 different config files, you end up with 10 templates which you just hope never run into any edge case of a particular format. And hope that the next service will just use JSON. Or YAML. Or whatever standardised.
It's a really good thing that these days, people use JSON most of the time.
How's that?
> easy to shoot yourself in the foot with, especially with the duplicate keys and concatenation behaviour
Maybe, but that is the entire point of HOCON: to compose configuration.
E.g. you have a defaults.conf file, but then you have a production.json files that includes defaults.conf and overwrites some of the value.
Or, at the end of your config file, you
include "local.conf"
and then you can put temporary local changes in a (gitignored) local.conf file.The way the config composes between reference.conf and application.conf and possibly more confs in the classpath can be a bit confusing, but the API gives you the ability to introspect the source of a config value. It's pretty nifty when you need the overlaying behaviour though.
There's a lot more ports for it available now than when we started using it several years ago, which decreases its previously monolingual risk quite a bit.
- It's a superset of JSON - so you can just write JSON if you don't want to change
- The ability to add comments
- Multi-line strings with the use of Scala's triple-quotes
- Reference other values with the use of in-line variables - https://github.com/typesafehub/config/blob/master/HOCON.md#s...
Both to me seem easily encoded using YAML's support for custom types.
We had an existing config system built around json that was typically machine written from human GUI manipulations.
Our existing system could process json but not HOCON.
HOCON after it parses config file(s) provides a tree that can be written out as json.
I had to I start writing the configs out by hand instead of using the GUI.
So I started refactoring my config as HOCON because it has some moderate boilerplate reduction and DRY helping features. Then I'd load those new configs with the HOCON library in Scala and have it spit out json which the existing system could then parse (in memory did have to write out files fortunately).
I was in a Scala stack so using HOCON was a natural fit. I tried snake-yaml as well first but HOCON was easier for me to get up and I felt had a less wonky syntax. (I use yaml quite a bit for ansible so I am fairly used to it but even ansible extends yaml a bit to make it easier to write).
Writing configs in json is a really big pain because:
1. No comments
2. No comments
3. "Having" "to" "quote" "all" "the" "keys" "and" "strings" "is" "painful"
I understand that perhaps I could relax those rules in the json parser but then I am just a step away from HOCON which adds higher order stuff.
IntelliJ had good HOCON support (ctrl+click to go to key / error highlighting) too so that helped. N.B. their yaml support is also good (via a plugin).
Anyhow keep in mind the way I used HOCON was quite different from how I have seen it used by other devs in the space. Whereas they included it in their jars then let users override stuff at runtime. I was able to use some of those design goals to make a modular slightly higher order json config system where I could share common configs as importable overrideable libraries.
Now if I had to have a system where humans and machines are "editing" the same file which was a case I had considered supporting for my system, I think I'd try to move the problem away from the same file space. And ask the question: Is there any way we can keep them out of the same files? Because that is probably easier than having the machine side keep track of comments in the parse tree and write them out when changing stuff. I'd try to sidestep by having my config system support importing files and merging them together and look more at how the directory.d pattern works in linux.
* Old school Gnome users may recognize its original author Havoc Pennington.
* Although it's a Java library, it's more natural in a Scala; the config objects are immutable, and Scala people like to rewrite the whole world anyway
* It's a very nice way to organize and write configuration files, although for our team we needed a session to understand how the final configuration was being derived since there can be multiple configuration files as well as the fallback/default values in reference.conf.
Not that HOCON solves that.
From the spec:
""" JSON is agnostic about numbers. In any programming language, there can be a variety of number types of various capacities and complements, fixed or floating, binary or decimal. That can make interchange between different programming languages difficult. JSON instead offers only the representation of numbers that humans use: a sequence of digits. All programming languages know how to make sense of digit sequences even if they disagree on internal representations. That is enough to allow interchange. """
It took me back to the days writing reams and reams of xml for JBoss back in the day.
config is code and I see no compelling reason to adopt HOCON over code, or other external DSLs like YML, TOML, JSON and XML.
Configs let you have a container/binary/deliverable that you can test/tag/workflow on as an artifact.
There are other configs like docker file, but they're vender specific.
The kind of person who cares about that sort of thing is the kind of person who hates YAML passionately.
https://github.com/crdoconnor/strictyaml
I also tried to write up a more extensive justification for anybody who scratching their head trying to decide which config format to use (including a "why not HOCON" paragraph):
https://github.com/crdoconnor/strictyaml/blob/master/FAQ.rst
And your FAQ is so well argued that I submitted it to HN: https://news.ycombinator.com/item?id=14318472
When I see JSON, I can sort of remind myself of the syntax: OK, things are comma separated, braces are matched, keys/strings are quoted, and that's it.
When I see YAML, I have to open some manual page with the syntax. (Ditto for anything with "vague" syntax like Wiki, Markdown, etc.)
I personally think that "vague" syntax is a bad thing in computer languages, and it's better to keep syntax to rather obvious minimum. Like in s-expressions, for example.
I wonder if the authors are aware of http://hjson.org/. It has similar features as far as loosening the json syntax rules and a lot of client libraries. HOCON seems to go a lot further in features/complexity.
I wrote HOCON and also the above comparison post.
Then again, Java Script Object Notation supports neither.
JSON superset is a bonus feature which is useful if you don't want to learn new syntax or want to machine-generate part of your config.
I understand that it might constitute a breaking change now to delimit the comments since:
# HOCON is great you can have #comments!
would now be a compile error but I'm interested if there's another issue that prevented optionally delimited comments in the original spec.
Personally, I find this at the very least interesting and possibly useful. The lack of comments in JSON is a problem when it comes to annotating configuration stored as JSON. But we have other formats that do not have this limitation (INI, YAML are two examples).
I really like the idea of "Human-Optimized" config, because it is more important for code and config to be understood by humans than by machines.
No complaints about hocon itself, but Typesafe configs get applied in first-value-wins which is a continual source of ... amusement ... for developers.
Watch: 168 Star: 2,753 Fork: 429
The JSON superset aspect nicely supports spitting out JSON from a script when people want to do it that way.
HOCON is nice when for example you just want to sub in a couple of env variables or avoid a little cut-and-paste.