by Leon Rosenshein


Hard coded config is bad. Making code flexible is good. We can debate that at another time, but let's go with that for now. One of the ways to make your code more generic is to move the instance specific data to an external config file that gets read and used at runtime. That way the same code can run in multiple environments and you don't have to worry about which version is deployed where. And one of the common ways to define that config file is yet another markup language, YAML.

The first thing to keep in mind is that YAML is a superset of JSON, which means that every JSON file is valid YAML, but the converse is definitely not true. The other thing to keep in mind is that while it's possible to have multiple YAML documents in one YAML file, a YAML document can not span files. Which means that while a common YAML file can be used by code in multiple languages, every implementation of merging YAML files is custom and probably not portable across languages.

That said, there are a bunch of things you can do inside a YAML file that are supported cross-platform, and can make your life a lot easier.

Most important, to me, is the ability to define "variables" and then use them multiple times in the file. This lets you put together a set of information and use it in multiple places without having to worry about typos. It can be a single value, or it could be a complex sequence of values, maps, and sub-items. Whatever it is, it is exactly the same everywhere it is used. You can even use the "variable" as a base and extend it differently in different places.

Another good one is the ability to handle multi-line strings or long strings without having to scroll 6 screens to the right or slam things against the left. Combined these features let you keep your YAML file readable while maintaining the look/format you want for the end user.

The last one that gets used a lot, especially when working with Kubernetes and kubectl is multiple documents in one file. Instead of having multiple files that you need to keep in sync you can add a separator and then just keep them all in one file. I don't recommend putting ALL your YAML in a single file, but if you need to define multiple related Kubernetes resources like a role, role-binding, and namespace, putting them all in one file can help you keep things in sync.

Which brings me back to merging multiple files. In this case I don't mean concatenating, or extending, but merging as in overriding a base for an instance specific result. Like having a base YAML file, then overriding the dB endpoint differently for dev, staging, and prod, but having the resulting document have the same structure. While there's no globally portable way (that I know of), there is Uber's config/configfx for Go. The base config library lets you specify how the different environment specific files are merged into the base, and configfx offers a pre-defined structure that uses the always-available ENV variables to automatically choose the correct files to merge together for you. If you're writing Go code, check it out.