Product 01 March 2022

Why k6 does not support multiple scripting languages?

Mihail Stoykov & Pawel Suwala

At k6, we regularly get requests to support other programming languages in addition to JavaScript. Go developers would like to write test scripts in Go, Java developers migrating from jMeter would like to write tests in Java. We have evaluated these requests and internally discussed in detail if this is a good direction for the k6 tool. Ultimately we have decided against supporting more programming languages for scripting.

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.

Non-technical reasons

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.

Collaboration

Today, multiple engineering teams in our organizations are driving the testing of our systems and applications. We often work on the same application, so testing is more of a team effort.

In this context, reusing tests and test code between teams is a strong benefit.

Teams writing tests in different languages will prevent collaboration in testing and limit the possibility of reusing our test code with other colleagues.

Documentation

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.

Developer 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.

Technical reasons

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.

Complexity

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

Each of which will be slightly different, likely due to differences in best practices for the applicable language. Arguably this isn't simply syntax. For example, what is used for asynchronous execution in JavaScript is completely different from Go, and Python has a variety of implementations as well.

Supporting language X doesn't mean that your code will work

The reality is that much of the JavaScript code depending on NodeJS or browser APIs simply won't work in k6. The same will happen for any other language that is implemented.

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

xk6, in practice, lets people write code in Go by building a k6 extension and calling the function within the JavaScript. All the underlying complexity will likely be exaggerated if Go was actually a scripting language within k6. Additionally, Go is known for its performance...interpreting Go code is very unlikely to be as performant as expected. Having a Go compiler will likely be even more complicated.

Dependency management

Another minor point is that any language having a particular way of loading dependencies will need to have some support in k6. Some of those are a lot more complicated than the default JavaScript one - just loading source from a file.

Final notes

WebAssembly

While the idea of WASM is agreeable, this path will also require having a k6 API specifically for WASM.

As of now, this will mean that using code written in language X transpiled to WASM will not "just work" - just like we have now with some JavaScript cases.

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.

< Back to all posts