6 ms·
Interesting take, the article describes ENV variables and their inherent untyped danger when you depend on them, but doesn't really describe an alternative solu
by gitgud 4y ago
Interesting take, the article describes ENV variables and their inherent untyped danger when you depend on them, but doesn't really describe an alternative solution for them.
A good solution I've just seen is to validate the environment variables using a schema like [1] zod. Which will guarantee that the ENV variables are the exact type that you expect when the program starts, or it will throw an error.
[1] Example -> https://github.com/t3-oss/create-t3-app/blob/bc57d02789209f116662c7ebe365673027e1a1c1/cli/template/base/src/env/schema.mjs#L8-L10 https://github.com/t3-oss/create-t3-app/blob/bc57d02789209f1...
- josephg 4y agoThe normal alternatives to environment variables are: - Command line arguments - Or a configuration file. (Optionally at a path specified on a command-line argument)
- jakewins 4y agoI was pondering this while reading as well.. what makes FOO=bar myapp Different from myapp —-foo=bar Or myfunc(foo=“bar”) ? All of these are handled by various underlying mechanisms that then make the data available on the other side
- gpderetta 4y agoScoping.
- eithed 4y agoFrom my understanding, explicitness of passing and usage - if your application for example logs all env variables `FOO=bar myapp` would log `FOO=bar XYZ=asd`, but `myapp --foo=bar` would log only `foo=bar` If two applications are setting FOO, then it results in undesired behaviour: 1. myapp1 runs, FOO=bar 2. myapp2 runs, FOO=xyz 3. myapp1 tries to use FOO, gets xyz Instead 1. myapp1 --foo=bar runs 2. myapp2 --foo=xyz runs 3. myapp uses foo, gets bar
- jakewins 4y agoIn my example I set the env var on the same line as the command, so the env var is only set in the new process, per open group: > If the command name is not a special built-in utility or function, the variable assignments shall be exported for the execution environment of the command and shall not affect the current execution environment Eg FOO=bar myapp FOO=xyz myapp echo $FOO # prints empty string/newline
- bkfunk 4y agoThe issue is, can myapp know that it was set that way, vs being set somewhere else? The command line argument uses syntactical constraints to ensure that the value of the argument was set specifically with the intention of using it in myapp.
- gwd 4y agoI think probably the main thing is that environment variables are a distinct and well-defined; they don't have to interact with anything else syntactically. This makes them nice to use, say, to pass secret API keys to your program in a way which is less likely to leak (apart from the "log all env variables" problem discussed in the post). Consider say, aws-cli. If I have to pass the API key as an argument, I have to C&P it into every command I write, or write a shell wrapper, thus storing the key on a file, which could accidentally get checked in or leak in some other way. Same with a configuration file. But if I just once per shell session put the API key into an environment variable, then it's only stored in memory; virtually zero chance it will make it into a git tree, and not terribly inconvenient. Similar if you need to pass an API key to the app running in a docker container. You don't want to rely on your docker container image itself being secret; and it's often very convenient to keep your Dockerfile in a git tree, so you don't want to explicitly set the command in the dockerfile to include your key. And do you really want to keep your config file on the data volume? Or create a special separate volume just for the configuration file (when in fact, you want the vast majority of configuration to be stored in your docker image)? Much easier to just tell the system running your container, "When you start this container, set this environment variable to this secret value." Then the system knows to treat that environment variable with discretion. The alternate would be to tell the system running your container, "Add this secret rune to the command line before running", or "Add this secret config file". Environment variables are much easier to reason about.
- jakewins 4y agoI agree with this. My question was about the blog posts assertion that something using environment variables to pass information was using a "ghost", but something like a command line option isn't. I guess, maybe the difference is in when and where the env var is specified. If you do something like ``` FOO=bar <hundreds of lines of bash> myapp # uses FOO `` Then I think the blog post author has a point - there's "hidden" information in the environment/context that the callee expects and will use. If you copied just the `myapp` line and stuck it somewhere else, it would lose the implicit `FOO` it expects to have. Vs something like ``` FOO=bar <hundreds of lines of bash> myapp --foo="${FOO}" ``` or ``` FOO=bar <hundreds of lines of bash> FOO="${FOO}" myapp # at least this way it's explicit! ```
- eptcyka 4y agoTechnically, environment variables can be changed at runtime, and so can the config file, but I don't believe that's the case for arguments.
- kec 4y agoEnvironment variables can have a spooky action at a distance when inherited by subprocesses. For your example specifically though, there's no check against a variable you misspelled / neglected to specify which could be ever worse as the variable may already exist in the environment with some other value you don't expect.
- sunfish 4y agoTyping is nice, and when one is working within an existing system where environment variables are the main way for communicating data between parts of a system (which is many popular systems today), this kind of typing looks like it can add some nice benefits. The blog post linked here is thinking about how the systems themselves could be designed differently, whether that's OS's, frameworks, platforms, languages, clusters, networks, or other things.
- Animats 4y agoHm. So, like enums for the web? Or, key/value stores where all key values are known. Who maintains the master list?
- sunfish 4y agoIn systems designed for it, communication channels can transmit handles without using a shared namespace or master list. An example of this in the real world is Unix-domain sockets having the ability to send file descriptors across the socket without using a namespace or master list.