I have been following the Twelve-Factor App methodology for a considerable amount of years. I mean, just like the Pirate Code, I see them more as guidelines than rules. There is a factor I’d like to challenge. Can tell you how and why in this blog post I have written just for you ;)
Factor III: Config
I’m going to keep it short and sweet, it’s been a long week! Factor #3 relates to enabling the injection of runtime configuration in an application through environment variables. Unlike the Pirate Code, it’s a rule I have been strictly following since my early days of Django development:
# Read database connection host from environment variable, with a default value
DATABASES['default']['HOST'] = os.environ.get('DJANGO_DATABASE_HOST', 'localhost')
The advantages of this factor are best described on the reference documentation so, not playing that song again.
So What’s The Problem
Well, “no problemo” per se. A couple of weeks ago, I came across a tweet by from a random Internet stranger that commented on the subject. Unfortunately I did not bookmark it, so cannot give credit but, thank you Internet dude, you seem like a very smart guy!
What he mentioned was that he preferred command-line argument based configuration over environment variables. The reason he stated was that CLI arguments have the advantage of discoverability of the available configuration options.
For checking which application configuration points are supported (environment variables and their potential values and format), documentation has to be written and/or source code has to be read. Whereas, with CLI arguments, the human can execute <cli program> --help
and get list of available options, their short plus long documentation and example values:
~ $ ./api-server-cli --help
Start the API
Usage:
api-server-cli [flags]
Flags:
--CouchDBDatabase string CouchDB Database Name (default "users")
--CouchDBURL string CouchDB URL (default "http://localhost:5984")
--ListenHost string http listen host (default "0.0.0.0")
--ListenPort int http listen port (default 8080)
-h, --help help for api-server-cli
Some libraries, for example viper, support multiple levels of configuration types (environment variables, files, command line flags, etc). It’s also straightforward to in-line environment variable values in command line flags if needed:
~ $ ./api-server-cli --database-host="$(DATABASE_HOST)"
An important question in my mind is actually … What are the the security risks associated with either method ? Something to look into over a latte one of these days. If you already know feel free to get in touch and let me know … ༼ つ ◕_◕ ༽つ (answer)