The life of a developer is not always easy. In addition to the fact that a developer has to deliver results, he also has the obligation of leaving behind an understandable, maintainable codebase.
Possibilities of context switching ↔️
Before you can switch from one context to another, two contexts must be able to exist in parallel and independently of each other. This assumes that contexts can be isolated. Exactly this context isolation is a driver of many thrusts in the IT world. There’s a need to isolate certain aspects of a given system in such a way that something can be easily replicated again in order to then achieve a desired end state without being influenced by external factors.
First, entire operating systems were isolated and called hardware virtualization. Of course, I am saying this in a very simplified way and leaving out many sub-concepts so as not to have to go into too much detail. The next step was virtualization, when isolation of the environment became possible at the operating system level. This is colloquially called containerization. Nonetheless, within a virtualized environment, the prevailing conditions, i.e. which software packages are installed, are paramount. A mechanism is needed to manage these packages. Package managers can perform this function, provided that no manual installation steps are used to manage them.
However, with environmental isolation via hardware or OS-level virtualization, there is still a lot of operational overhead involved. It is precisely in such situations that alternative methods provide a remedy. What I’m getting at here is that with the help of a so-called version manager like asdf you’ve got exactly one software tool with which you can bypass this operational overhead.
A version manager solves one of the most tedious problems of every developer’s daily business, namely the harmonization of the developer environment. There are other alternatives like the Nix Package Manager, but today we’re going to look at asdf as a small but mighty tool that’s especially useful for version management of local development environments.
asdf - The (easy) version manager 😇
asdf may be an unassuming or even uninspired name, but it’s a perfect nod to how transparent and accessible it can be as a developer’s tool. asdf is primarily a version manager that handles automatic versioning. asdf recognizes where you are in a directory or project and decides which version of a given toolset is appropriate for that.
If you have configured asdf correctly and know which levers you have to pull in order to be able to use it, you no longer need to worry about development versions and software environments. The really great thing about asdf is simply how easy version management is and how easy it is to expand its setup according to your needs and requirements.
asdf coming soon
The principle behind how asdf works is quite simple. There is a hidden .asdf
directory in the user’s home directory. It contains the asdf entry point as a ~/.asdf/asdf.sh
shell script. Once the path of this shell script has been added to the shell, one can invoke asdf. In addition to the entry point, there are other folders, such as the ~/.asdf/plugins
directory, which contains all available runtimes.
asdf knows the global and local versions for different runtimes. Local versions are declared whenever a .tool-versions
text file exists for a given directory and its subdirectories. It simply contains the runtime designation, a unique designation that corresponds to the corresponding asdf plugin, and its version.
|
|
Global versions are versions declared for all other directories via the asdf CLI.
How To and Best Practices 🧐
asdf is not only “straightforward” in its use, it is also very easy to install. Here I’ll do a standard install from asdf and install an Elixir runtime using the plugin. Then I declare a global version for the Elixir runtime of 1.13.2-otp-24
and a local version of 1.12-otp-23
.
Installation
Installation on MacOS.
|
|
For GNU/Linux or Unix-like, simply via the GitHub repo.
|
|
Just like brew, the above command puts the repo in a dot directory in the home directory, say ~/.asdf
.
That then has to be in the .bashrc or in the .zshrc.
|
|
Here we make sure that the asdf.bash file is also under completions/
.
|
|
Get started
Once asdf is installed, we can actually start using it.
Plugin Installation
We’ll Elixir as an example, since we have to set up a Phoenix project anyway.
|
|
Version Installation
So now asdf understands Elixir. Now we can provision any versions, that is, language runtimes for it.
|
|
For this example, let’s install an older version of Elixir. To make the whole thing a little more realistic, we use an older OTP version, namely the 23 version.
|
|
Define contexts
Now we put a global and several local versions.
|
|
If I’m in a random directory now, I can check the Elixir version as follows.
|
|
There is a 3rd party project using the 23 OTP version of Elixir that I found in a GitHub repo and will now use as an example.
|
|
This command places a .tool-versions
file in the target directory.
|
|
Now the Elixir OTP version in this directory should also be adjusted.
|
|
✅ Hint for Elixir
With Elixir, it is important to note that an Erlang toolchain is always installed alongside Elixir. Since the Erlang toolchain also provides the OTP runtime, the Elixir version must always be compiled for the same target runtime, i.e. the same OTP platform. In this case we would have to downgrade the Erlang version to a 23 version in the local .tool-versions
.
Now comes the crux. Experience has shown that all versions of Erlang are compiled. Now let’s install Erlang version 23.3
. The corresponding repository is drawn from it and then compiled. This could take a while.
|
|
Once it’s successfully built (on my Macbook Pro with the new M1Max processor, this took about five minutes), you can include Erlang as an entry in .tool-versions
as follows:
|
|
Now the first line of elixir --version
should say “Erlang/OTP 23”. So you can use an OTP-23 capable Elixir runtime.
|
|
The version is also displayed in the prompt:
Best Practices 👌
In the standard version of asdf, certain files are created in the .asdf
directory. What is not created by default though, is a runtime configuration. However, this is not in the .asdf
directory but in the home directory. Certain settings can be adjusted there. It’s certainly best practice to know these settings and how to customize asdf’s behavior to suit your needs.
It is best to create the runtime configuration as a ~/.asdfrc
file in the home directory. Here that’s described in the official documentation.
In this .asdfrc
file you can adjust the following four parameters:
|
|
If you want to leave open the possibility of a fallback for a legacy version, you would have to set the first property to “true” like this: legacy_version_file = true
.
Extensibility
There is also a relatively well-documented asdf-Plugin-Template that you can use to write your own plugin. This can also be in a private Git repository, since you can specify the Git repository as the last parameter when using a plugin. The scheme would be as follows:
|
|
asdf at b-nova
Since the community can also write its own asdf plugins, there now are a large number of asdf plugins. The list is maintained in the official GitHub-Repo in asdf-vm/asdf-plugins
.
We use asdf for the following runtimes:
- asdf-graalvm
- asdf-hashicorp (terraform)
- asdf-java
Conclusion 🙌
asdf is a nice open source project, which simplifies a central part of the developer’s everyday life to a quasi “no-brainer”. Especially in today’s DevOps landscape, in which it is not always necessary to containerize all projects for local development, asdf is an ingenious filler and serves its purpose extremely well.
Pros and cons
- 👍 Easy installation and setup
- 👍 Lots and lots of plugins for pretty much every runtime, software package and programming language
- 👍 Many versions
- 👎 Some older or very specific versions need to be compiled, which can be time-consuming
Related links and resources 🤓
asdf-vm/asdf | GitHub Repository
The future-proof solution to manage your Flutter versions: global, FVM, or asdf-vm? | iainsmith.me
asdf and Docker for Managing Local Development Dependencies | pawelurbanek.com