It is a profoundly erroneous truism, repeated by all copy-books and by eminent people when they are making speeches, that we should cultivate the habit of thinking of what we are doing. The precise opposite is the case. Civilization advances by extending the number of important operations which we can perform without thinking about them. Operations of thought are like cavalry charges in a battle — they are strictly limited in number, they require fresh horses, and must only be made at decisive moments.
There's a lot to be said about the failure of the computer revolution to be revolutionary and the failure of personal computers to be personal, and I won't get into it here.
But at the very least, I believe that professional programmers should be able to program their working environment to save themselves effort.
Specifically, professional programmers of Ruby should not have to write
bundle exec before every goddamn thing.
If you don't write Ruby, then let me explain
- Ruby has a ubiquitous package manager named Bundler.
- Bundler has a subcommand
execwhich runs commands in an environment where .
- It's very
- You will probably not get much use from this article. You don't ever find yourself typing
bundle exec, so a method to save yourself that effort isn't any help to you.
For those who are
$ nix-env --install direnv # ... $ direnv version 2.20.0
Complete your direnv installation by adding its hooks for your shell.
$ echo 'eval "$(direnv hook bash)"' >> ~/.bash_profile $ source ~/.bash_profile
If you use zsh or fish, obviously you'd change the argument to
direnv hook and add the line to a different file.
.envrc file to the root of your project with the line
layout ruby in it, and enable it by running
direnv allow while in that directory.
This will set two environment variables that control Bundlers behavior and add two directories to your
PATH environment variable.
$ echo 'layout ruby' >> .envrc direnv: error .envrc is blocked. Run `direnv allow` to approve its content. $ direnv allow direnv: loading .envrc direnv: export +BUNDLE_BIN +GEM_HOME ~PATH nick-mbp% echo $BUNDLE_BIN /Users/nick/Source/ruby_project/.direnv/bin $ echo $GEM_HOME /Users/nick/Source/ruby_project/.direnv/ruby nick-mbp% echo $PATH /Users/nick/Source/ruby_project/.direnv/bin:/Users/nick/Source/ruby_project/.direnv/ruby/bin # ...
GEM_HOME determines where bundler and other tools place gems.
BUNDLE_BIN determines where bundler puts binstubs.
PATH of course determines where your shell will look for commands you invoke.
Bundler will be filling that
.direnv directory, so let's leave it out of source control.
$ echo '/.direnv/' >> .gitignore
You know this one.
$ bundle install # ... Bundle complete! 25 Gemfile dependencies, 131 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed.
Step 5: there is no step 5
Step 4 has put the binstubs of all your project's dependencies in
.direnv/bin, and step 2 has put that folder at the front of your
PATH. That means that when you run
foo, it will always be the version of
foo specified in the
% which rake /Users/nick/Source/ruby_project/.direnv/bin/rake $ rake --version rake, version 11.3.0 $ cd .. direnv: unloading $ which rake /usr/bin/rake $ rake --version rake, version 12.3.2
Step 6: Reflection
I wrote all this so you could enjoy a reliable experience in at least one corner of your professional life.
I also hope that you start demanding it in all corners of your professional life.
The highest degree of reliability is not consistency, but invisibility. We often call something that "always" "works" reliable, without asking how much time we spend making it work, how much time we spent learning to make it work, and what probabilities are really hiding behind the blithe word "always."
You deserve better than that. Your life is worth more than the tedious things you've been trained to spend it doing and thinking about. You deserve things so reliable that you can use them without thinking about them.
It's not really possible to "save time." Time is always "spent," and can't be hoarded for later. But the reason we should fight to save each other time is so that we can spend it better. As in the story of the magic washing machine, you don't buy a washing machine to wash clothes, but to do things instead of washing clothes.
It's possible to get enjoyment from washing clothes or typing "bundle exec," but hopefully you can think of things you'd prefer to get enjoyment from.