feat(golang-rewrite): Rewrite application in Go by Stratus3D · Pull Request #1805 · asdf-vm/asdf

4 min read Original article ↗

Description

This is a full rewrite of asdf in Golang. 🚀 🎉

I've taken the existing BATS tests and used them as a guide in building a completely new version of asdf that is 100% Go and doesn't rely on any of the existing code. The Go implementation contained in this PR is feature complete, and unless specified, as all the features of the Bash version. I've been working on this for several months and have been using it myself every day for several weeks. I've found it to be very fast and stable for my uses.

Special thanks those that helped me with this rewrite:

@chrisjpalmer
@mikelorant
@DeedleFake

And @danhper for https://github.com/danhper/asdf-exec, which I referenced extensively when implementing the version resolution functionality.

Breaking Changes

While my aim was to copy the behavior of the existing Bash implementation exactly, I came across several features that were no longer needed, two that couldn't be easily done in Go (asdf update self-update, asdf shell env var setting), and a bunch of things that were overly complicated with no real benefit.

All breaking changes are documented here: here: https://github.com/asdf-vm/asdf/blob/97d48aa179c666f94cf821091db312678c926aee/docs/guide/upgrading-from-v0-14-to-v0-15.md#breaking-changes

If you notice unexpected behavior when testing this code, and it's not on that list, it is a bug. Please report it.

@asdf-vm/core @HashNuke @vic @danhper @jthegedus I would appreciate your input on this on this PR.

PR highlights

FAQ

Why a rewrite?

This project is widely used, and many people (myself included) rely on it every day to work on dozens of different projects each with their own distinct dependencies. I need to continue to use asdf, and many others do as well.

This project has grown challenging to maintain due to what I deem three distinct things:

  • Number of users and the number of bugs and feature requests they submit
  • It is all written in Bash, and as a result the codebase is harder change than most codebases of similar size
  • Performance is a problem

A rewrite can solve two of these problems.

Why Go?

I actually tried out Rust for a time, and eventually settled on Go. Go is a simple language with a fast compiler. It's easy to learn, and has a large ecosystem. It feels very well suited to CLI apps. Many people including existing maintainers @jthegedus and @danhper already know Go. I found it quick to pick up and am now very productive with it myself.

How can I test out these changes?

The changes for this rewrite were managed in the https://github.com/asdf-vm/asdf-core-go repository prior to opening this PR. You can download prebuilt binaries here - https://github.com/asdf-vm/asdf-core-go/releases or install via Go with go install github.com/asdf-vm/asdf-core-go@latest

What is left to do?

Not much. I'm aware of a few things:

  • 🏷️ Tag the last non-Go version of asdf so we've got a stable Bash version for those that choose not to upgrade yet.
  • 👨‍💻 Figure out how to handle shell completions. Currently completions are separate files, but I think it may make sense to bake them into the Go binary for easier distribution. Thoughts?
  • 📖 Update documentation
  • 🏗️ Update release process so it builds Go binaries
  • 🚀 Release new tag

How does this improve runtime performance?

From manual testing this new implementation is anywhere between 2x - 15x faster than the existing Bash implementation. This is not surprising given the general inefficiency of most of the Bash code.

I'm not going to do any thorough benchmarks right now. But I do plan on doing them in the future and writing another blog post similar to http://stratus3d.com/blog/2022/08/11/asdf-performance/ with the updated numbers.

How stable is this code?

I've written tests for everything that I could easily write tests for, and I've been using this code exclusively since November 22nd.

How is this going to be released?

There are a couple ways:

  • Package manager (apt-get, Brew, etc...)
  • Pre-built binary (we can publish binaries for common OS-architecture combos here on GitHub)
  • go install ...
  • Build from source