Below is our reasoning for this decision. We are documenting it in hopes that those who are dissatisfied with this decision at least understand our position :-)
Some reasons are technical, but many are non-technical. Let’s start with non-technical.
Ability to innovate
Suppose we allow more than one scripting language. In that case, any language will likely lack capabilities compared to its counterpart, or our ability to innovate will be limited to the common set of features available in both languages.
In terms of effort, providing new capabilities will require considerable work as every new feature should be supported for each language. Let’s not forget that building is not the most significant part of the work; the maintenance and support overhead will pile up dramatically.
We deeply care about pursuing great documentation as most of the k6 community is new to both performance testing and k6.
Documenting scripts in multiple languages will create an additional burden and decrease our documentation quality, negatively impacting the learning and getting-started experience.
At k6, we care about developer experience more than anything. Our software must be easy to use, allowing for quick adoption. It must be reliable and live up to high quality standards.
Multiple scripting languages adds many complexities hindering our ability to maintain the quality of our products.
The below technical reasons examine the Go language as a potential second scripting language. We evaluated Go since k6 itself is written in Go, and its adoption has grown among platform engineers.
For every language that will be added we need to:
- have an interpreter for it (or compiler)
- implement the k6 API provided to the user
Supporting language X doesn't mean that your code will work
Many APIs can never be implemented or will be restricted for security reasons:
- forking and launching a new process
- sending signals to a different process
- opening files to write
For this reason, even if we get a Go interpreter in k6, many examples will not work. This likely includes a lot (I will expect all) dependencies that users hope to use.
Even if k6 supports importing a library that makes requests (e.g. go-socket.io), you will likely want k6 to collect performance metrics; you would need to implement this on your own. The same situation will more or less be true for any language or library that makes requests in some specific way.
Best practices in other languages
For example, Go can handle thousands--or millions--of goroutines. It is common to start new goroutines for everything, but creating a bunch of new goroutines in multiple VUs will likely not be very efficient.
Currently, k6 expects anything started by a script within an iteration to be cleaned up by the script itself. This will likely be unenforceable with a Go interpreter. This means we will make the k6 script harder to write in Go.
Also, it is likely that none of the tooling in the Go ecosystem will work with k6, so all the ways a Go developer is used to working...will just not work.
Extensions to the rescue
While the idea of WASM is agreeable, this path will also require having a k6 API specifically for WASM.
Extensions for different languages
We potentially could have extensions to support different languages. This idea will, if nothing else, have a positive effect on the actual codebase. Here is the Go example.
Supporting a different language than Go will take some time, requiring example implementations, documentation, and stabilizing the APIs for each. This will likely be a very big task.