Das Leben eines Entwicklers ist nicht immer einfach. Nebst dem, dass ein Entwickler Resultate liefern muss, hat er auch noch die Aufgabe, dabei eine verständliche, wartbare Codebase zu hinterlassen. Zu der grossen Anzahl von Tools, über die man als Entwickler den Überblick behalten muss, kommen auch noch verschiedene Versionen eben dieser Tools, zwischen denen man je nach Anwendung hin und her “switchen” muss. Diese Form von Kontext-Switching lässt sich mit einem Version-Manager wie asdf stark vereinfachen. Da Kontext-Switching in der IT an unterschiedlichen Punkten verwendung findet, möchte ich dir zunächst einen Überblick über die Grundlagen und die Entwicklung des Kontext-Switching geben. Viel Spass! 😄
Möglichkeiten des Kontext-Switching ↔️
Bevor man von einem Kontext in einen anderen Kontext wechseln kann, müssen zwei Kontexte parallel zueinander und unabhängig voneinander existieren können. Das setzt voraus, dass Kontexte isoliert werden können. Genau diese Kontextisolation ist ein Treiber vieler Stossrichtungen in der IT-Welt. Es ist ja gerade der Wunsch danach, gewisse Aspekte eines gegebenen Systems so zu isolieren, dass man etwas ganz einfach wieder replizieren kann, um dann ein gewünschten Endzustand zu erzielen, ohne dass dieser von äusseren Einflüssen beeinflusst wird.
Zuerst hat man ganze Betriebssysteme isoliert und nannte das Hardware-Virtualisierung. Natürlich sage ich das hier sehr vereinfachend und lasse viele Teilkonzepte aussen vor, um nicht zu weit ausholen zu müssen. Als nächster Schritt kam die Virtualisierung, als auf Betriebssystem-Ebene eine Isolation der Umgebung möglich wurde. Dies nennt man umgangssprachlich auch Containerisierung. Innerhalb einer virtualisierten Umgebung steht nichtsdestotrotz im Vordergrund, welche Bedingungen darin herrschen, sprich, welche Softwarepakete verbaut sind. Für die Verwaltung dieser Pakete braucht es einen Mechanismus. Package-Manager können diese Funktion übernehmen, sofern die Verwaltung nicht über manuelle Installationsschritte übernommen wird.
Mit einer Umgebungsisolierung über eine Hardware- oder OS-Level-Virtualisierung ist aber dennoch viel betrieblicher Overhead notwendig. Gerade in solchen Situationen verschaffen alternative Methoden Abhilfe. Worauf ich hier hinaus will ist, dass man mithilfe von einem sogenannten Version-Manager wie asdf genau ein solches Software-Tool hat, mit dem man diesen betrieblichen Overhead umgehen kann.
Mit einem Version-Manager löst man eines der mühsamsten Probleme des täglichen Geschäfts eines jeden Entwicklers, nämlich die Harmonisierung der Entwicklerumgebung. Es gibt auch noch andere Alternativen wie der Nix Package Manager, aber heute werden wir uns asdf als kleines aber feines Tool, das sich besonders für das Versionsmanagement von lokalen Entwicklungsumgebungen eignet, anschauen.
asdf – Der (einfache) Versionsmanager 😇
asdf ist vielleicht ein etwas unscheinbarer oder gar uninspirierter Name, doch steckt dahinter eine optimale Anspielung darauf, wie transparent und zugänglich es als Hilfsmittel im Entwickleralltag sein kann. asdf ist in erster Linie ein Versionsmanager und übernimmt die automatische Versionsverwaltung. Dabei erkennt asdf, wo man sich in einem Verzeichnis oder Projekt befindet und entscheidet, welche Version von einem gegeben Toolset hierfür angebracht ist.
Sofern man asdf richtig konfiguriert hat und weiss, welche Hebel man betätigen muss, um asdf einsetzen zu können, braucht man sich nicht mehr um Versionen von Entwicklungs- und Softwareumgebungen zu kümmern. Das wirkliche grandiose an asdf ist einfach der Umstand, wie einfach die Versionsverwaltung gehandhabt wird und wie leicht man deren Setup nach seinen Bedürfnissen und Ansprüchen erweitern kann.
asdf in Kürze
Das Prinzip hinter der Funktionsweise von asdf ist ganz einfach. Es gibt im Home-Verzeichnis des Users ein verstecktes .asdf
-Verzeichnis. Darin ist der Einstiegspunkt von asdf als ~/.asdf/asdf.sh
-Shell-Skript enthalten. Sobald der Pfad dieses Shell-Skripts der Shell hinzugefügt wurde, kann man asdf aufrufen. Neben dem Einstiegspunkt gibt es noch weitere Ordner, wie zum Beispiel das ~/.asdf/plugins
-Verzeichnis, in dem alle verfügbaren Runtimes enthalten sind.
asdf kennt globale und lokale Versionen für Runtimes. Lokale Versionen sind deklariert, sobald für ein gegebenes Verzeichnis, sowie dessen Subverzeichnisse, eine .tool-versions
-Textdatei vorhanden ist. Darin wird einfach die Runtime-Bezeichnung, eine eindeutige Bezeichnung, welche dem entsprechenden asdf-Plugin gleichkommt, sowie dessen Version angegeben.
|
|
Globale Versionen sind Versionen, die man für alle anderen Verzeichnisse über die asdf-CLI deklariert hat.
How-To und Best-Practices 🧐
asdf ist nicht nur “straightforward” in seiner Benutzung, sondern lässt sich auch sehr einfach installieren. Hier werde ich eine Standard-Installation von asdf vornehmen, sowie eine Elixir-Runtime mithilfe des Plugins installieren. Danach deklariere ich eine globale Version für die Elixir-Runtime von 1.13.2-otp-24
und eine lokale Version von 1.12-otp-23
.
Installation
Installation auf MacOS.
|
|
Sonst GNU/Linux oder Unixartige, einfach über die GitHub-Repo.
|
|
Genau wie Brew setzt das obere Kommando die Repo in ein Dot-Verzeichnis im Home-Verzeichnis, sprich ~/.asdf
.
Das muss dann noch in die .bashrc oder in die .zshrc.
|
|
Hier vergewissern wir uns dass auch das asdf.bash-File unter completions/ liegt.
|
|
Erste Schritte
Sobald asdf installiert ist, können wir es eigentlich schon nutzen.
Plugin installieren
Beispiel an Elixir, da wir sowieso ein Phoenix-Projekt aufsetzen müssen.
|
|
Version installieren
So, jetzt versteht asdf Elixir. Jetzt können wir beliebige Versionen, sprich, Language-Runtimes dafür provisionieren.
|
|
Lass uns für dieses Beispiel noch eine ältere Elixir-Version installieren. Um das ganze ein wenig realistischer zu machen, nehmen wir eine ältere OTP-Version, nämlich die 23er-Version.
|
|
Kontexte definieren
Jetzt setzen wir eine globale und mehrere lokale Versionen.
|
|
Falls ich jetzt in einem zufälligen Verzeichnis bin, kann ich die Elixir-Version prüfen.
|
|
Es gibt ein 3rd-Party-Projekt, welches die 23-OTP-Version von Elixir nutzt, das ich in einem GitHub-Repo gefunden habe und jetzt beispielhaft nutzen werde.
|
|
Dieser Befehl platziert ein .tool-versions
-Datei in das Zielverzeichnis.
|
|
Jetzt sollte die Elixir-OTP-Version in diesem Verzeichnis auch angepasst sein.
|
|
✅ Hinweis für Elixir
Bei Elixir ist wichtig anzumerken, dass neben Elixir stets eine Erlang-Toolchain installiert ist. Da die Erlang-Toolchain auch die OTP-Runtime zur Verfügung stellt, müsste die Elixir-Version immer für die gleiche Ziel-Runtime, sprich, die gleiche OTP-Plattform kompiliert sein. In diesem Fall müssten wir in der lokalen .tool-versions
noch die Erlang-Version auf eine 23er-Version downgraden.
Jetzt kommt die Crux: Erfahrungsgemäss werden alle Versionen von Erlang kompiliert. Jetzt installieren wir die Erlang-Version 23.3
. Davon wird das entsprechende Repository gezogen und danach kompiliert. Das kann eine Weile dauern.
|
|
Sobald man diese erfolgreich gebaut hat (auf meinem MacBook Pro mit dem neuen M1-Prozessor hat das gut 5 Minuten gedauert), kann man Erlang als Eintrag in die .tool-versions
wie folgt aufnehmen:
|
|
Jetzt sollte in der ersten Zeile von elixir --version
“Erlang/OTP 23” stehen. Somit kann man eine OTP-23-fähige Elixir-Runtime nutzen.
|
|
In der Prompt wird die Version auch angezeigt:
Best-Practices 👌
In der Standardausführung von asdf werden gewisse Dateien im .asdf
-Verzeichnis angelegt. Was aber nicht standardmässig erstellt wird, ist eine Runtime-Configuration. Diese kommt aber nicht ins .asdf
-Verzeichnis sondern ins Home-Verzeichnis. Darin können gewisse Einstellungen angepasst werden. Es ist sicherlich ein Best-Practice, diese Einstellungen zu kennen und zu wissen, wie man das Verhalten von asdf für die eigenen Bedürfnisse anpassen kann.
Erstelle am besten gleich die Runtime-Konfiguration als ~/.asdfrc
-Datei im Home-Verzeichnis. In der offiziellen Dokumentation ist das hier beschrieben.
In dieser .asdfrc
-Datei kann man folgende vier Parameter anpassen:
|
|
Falls man die Möglichkeit offen lassen möchte, ob ein Fallback für eine Legacy-Version bestehen soll, so ist müsste man die erste Property auf “wahr” wie folgt setzen: legacy_version_file = true
.
Erweiterbarkeit
Es gibt auch ein relativ gut dokumentiertes asdf-Plugin-Template, mit dem man ein eigenes Plugin schreiben kann. Das darf auch in einem privaten Git-Repository liegen, da man beim anziehen eines Plugins als letzten Parameter das Git-Repository angeben kann. Das Schema wäre wie folgt:
|
|
asdf bei b-nova
Da die Community auch eigene asdf-Plugins schreiben kann, gibt es mittlerweile eine Vielzahl von asdf-Plugins. Die Liste wird im offiziellen GitHub-Repo unter asdf-vm/asdf-plugins
gepflegt.
Wir nutzen asdf für folgende Runtimes:
- asdf-graalvm
- asdf-hashicorp (terraform)
- asdf-java
Fazit 🙌
asdf ist ein nettes Open-Source-Projekt, welches einen zentralen Teilbreich des Entwickleralltags zu einem quasi “No-Brainer” vereinfacht. Gerade in der heutigen DevOps-Landschaft, in der man nicht immer zwingend alle Projekte für die lokale Entwicklung containerisiert hat, ist asdf ein genialer Lückenfüller und erfüllt seinen Zweck ungemein gut.
Vor- und Nachteile
- 👍 Einfache Installation und Setup
- 👍 Viele, viele Plugins für so ziemlich alle Runtimes, Software-Pakete und Programmiersprachen
- 👍 Viele Versionen
- 👎 Manche ältere oder sehr spezifische Versionen müssen kompiliert werden, was zeitaufwändig sein kann
Weiterführende Links und Ressourcen 🤓
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