One of the best ways to disappoint someone is to break a promise - and this applies both to the software we write and the applications we use as well.

When running tests, the Go compiler has a -json option allowing you to request output in JSON format. This is useful as it allows those test results to be easily processed by a separate application.

The implied promise is that using the -json option will give you output in JSON format. This is such an obvious thing that we do not really think about it. We assume that the flag does what it says it does.

Unfortunately, the Go compiler (at least as of version 1.18) breaks this promise - sometimes the output is not JSON at all.

Here’s an example we recently encountered with Azure Service Operator (ASO).

First, here’s one of the log lines that adheres to JSON format; I’ve formatted it for readability, but in the original output it’s all on one line:

{
    "Time": "2022-05-14T09:15:45.8395504+12:00",
    "Action": "output",
    "Package": "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel",
    "Output": "ok  \tgithub.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel\t4.986s\tcoverage: 13.1% of statements in ./...\n"
}

Most of the lines have the same schema.

But some do not.

FAIL        github.com/Azure/azure-service-operator/v2/tools/generator/internal/codegen/pipeline [build failed]

Pretty safe to say, that’s not JSON - and it broke the program that a colleague wrote to summarize our test results.

When you make a promise, your code should keep that promise. This applies whether we’re talking about a command-line option (as in this example), a REST API, or simply the design of your types and methods.

Comments

blog comments powered by Disqus