Argument passing strategy - environment variables vs. command line

一世执手 提交于 2019-11-27 11:05:20

1) I would recommend avoiding environmental variables as much as possible.

Pros of environmental variables

  • easy to use because they're visible from anywhere. If lots of independent programs need a piece of information, this approach is a whole lot more convenient.

Cons of environmental variables

  • hard to use correctly because they're visible (delete-able, set-able) from anywhere. If I install a new program that relies on environmental variables, are they going to stomp on my existing ones? Did I inadvertently screw up my environmental variables when I was monkeying around yesterday?

My opinion

  • use command-line arguments for those arguments which are most likely to be different for each individual invocation of the program (i.e. n for a program which calculates n!)
  • use config files for arguments which a user might reasonably want to change, but not very often (i.e. display size when the window pops up)
  • use environmental variables sparingly -- preferably only for arguments which are expected not to change (i.e. the location of the Python interpreter)
  • your point They are global and accessible from anywhere, which is less elegant from architectural point of view, but limits the amount of code reminds me of justifications for the use of global variables ;)

My scars from experiencing first-hand the horrors of environmental variable overuse

  • two programs we need at work, which can't run on the same computer at the same time due to environmental clashes
  • multiple versions of programs with the same name but different bugs -- brought an entire workshop to its knees for hours because the location of the program was pulled from the environment, and was (silently, subtly) wrong.

2) Limits

If I were pushing the limits of either what the command line can hold, or what the environment can handle, I would refactor immediately.

I've used JSON in the past for a command-line application which needed a lot of parameters. It was very convenient to be able to use dictionaries and lists, along with strings and numbers. The application only took a couple of command line args, one of which was the location of the JSON file.

Advantages of this approach

  • didn't have to write a lot of (painful) code to interact with a CLI library -- it can be a pain to get many of the common libraries to enforce complicated constraints (by 'complicated' I mean more complex than checking for a specific key or alternation between a set of keys)
  • don't have to worry about the CLI libraries requirements for order of arguments -- just use a JSON object!
  • easy to represent complicated data (answering What won't fit into command line parameters?) such as lists
  • easy to use the data from other applications -- both to create and to parse programmatically
  • easy to accommodate future extensions

Note: I want to distinguish this from the .config-file approach -- this is not for storing user configuration. Maybe I should call this the 'command-line parameter-file' approach, because I use it for a program that needs lots of values that don't fit well on the command line.


3) Solution portability: I don't know a whole lot about the differences between Mac, PC, and Linux with regard to environmental variables and command line arguments, but I can tell you:

  • all three have support for environmental variables
  • they all support command line arguments

Yes, I know -- it wasn't very helpful. I'm sorry. But the key point is that you can expect a reasonable solution to be portable, although you would definitely want to verify this for your programs (for example, are command line args case sensitive on any platforms? on all platforms? I don't know).


One last point:

As Tomasz mentioned, it shouldn't matter to most of the application where the parameters came from.

You should abstract reading parameters using Strategy pattern. Create an abstraction named ConfigurationSource having readConfig(key) -> value method (or returning some Configuration object/structure) with following implementations:

  • CommandLineConfigurationSource
  • EnvironmentVariableConfigurationSource
  • WindowsFileConfigurationSource - loading from a configuration file from C:/Document and settings...
  • WindowsRegistryConfigurationSource
  • NetworkConfigrationSource
  • UnixFileConfigurationSource - - loading from a configuration file from /home/user/...
  • DefaultConfigurationSource - defaults
  • ...

You can also use Chain of responsibility pattern to chain sources in various configurations like: if command line argument is not supplied, try environment variable and if everything else fails, return defauls.

Ad 1. This approach not only allows you to abstract reading configuration, but you can easily change the underlying mechanism without any affect on client code. Also you can use several sources at once, falling back or gathering configuration from different sources.

Ad 2. Just choose whichever implementation is suitable. Of course some configuration entries won't fit for instance into command line arguments.

Ad 3. If some implementations aren't portable, have two, one silently ignored/skipped when not suitable for a given system.

I think this question has been answered rather well already, but I feel like it deserves a 2018 update. I feel like an unmentioned benefit of environmental variables is that they generally require less boiler plate code to work with. This makes for cleaner more readable code. However a major disadvatnage is that they remove a layers of isolation from different applications running on the same machine. I think this is where Docker really shines. My favorite design pattern is to exclusively use environment variables and run the application inside of a Docker container. This removes the isolation issue.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!