Skip to content

Instantly share code, notes, and snippets.

@jonathaningram
Last active January 22, 2019 17:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathaningram/2b62022844348f3407518dd3a180ef42 to your computer and use it in GitHub Desktop.
Save jonathaningram/2b62022844348f3407518dd3a180ef42 to your computer and use it in GitHub Desktop.
Go Experience Report regarding gofmt not being opinionated enough

Problem

Code reviews containing Go code have unnecessary and ongoing debates about style because gofmt is not opinionated enough.

gofmt does not do enough formatting and particularly it does not take the line length into account.

Comparing gofmt with prettier, in code reviews for a Javascript codebase, there are rarely debates about style-related issues because prettier is very opinionated.

Example: different ways to format method arguments

Given three versions of the same Go code, but formatted differently by different developers:

Version A:

package x

import (
	"bytes"
	"context"
)

type User struct {}
type Mailer struct {}

// Comment showing where an 80 column ruler would appear.
// ---------------------------------------------------------------------------->
func (m Mailer) sendEmailToUser(ctx context.Context, u User, subject, html, text *bytes.Buffer) error {
	return nil
}

Version B:

package x

import (
	"bytes"
	"context"
)

type User struct {}
type Mailer struct {}

// Comment showing where an 80 column ruler would appear.
// ---------------------------------------------------------------------------->
func (m Mailer) sendEmailToUser(
	ctx context.Context,
	u User,
	subject,
	html,
	text *bytes.Buffer,
) error {
	return nil
}

Version C:

package x

import (
	"bytes"
	"context"
)

type User struct {}
type Mailer struct {}

// Comment showing where an 80 column ruler would appear.
// ---------------------------------------------------------------------------->
func (m Mailer) sendEmailToUser(
	ctx context.Context,
	u User,
	subject, html, text *bytes.Buffer,
) error {
	return nil
}

Problem 1

A code review containing either of these versions unnecessarily creates the possibility of a debate between developers about how the method arguments should be formatted:

  1. Should they all be on one line?
  2. Should each parameter have its own line?
  3. Should some arguments be on the same line while others are on a new line?

We want to avoid the possibility of this debate entirely by having gofmt format as much as possible (best effort) in the same way.

Problem 2

The code is (arguably) not as readable because the line length has not been taken into account. In Version A, the comment shows that the method arguments extend beyond an 80 column ruler.

With regards to the choice of an 80 column ruler, extracts from prettier's print width reasoning are referred to in order to justify the choice:

In code style guides, maximum line length rules are often set to 100 or 120. However, when humans write code, they don't strive to reach the maximum number of columns on every line. Developers often use whitespace to break up long lines for readability. In practice, the average line length often ends up well below the maximum.

Prettier, on the other hand, strives to fit the most code into every line. With the print width set to 120, prettier may produce overly compact, or otherwise undesirable code.

Final note

The example in this experience report shows different ways to format method arguments. However, the problem of gofmt being not opinionated enough applies to other parts of Go code as well - the underlying problem is that given N ways of writing the same Go code, gofmt does not output one universal format.

Note: published in "Go Experience Reports"

@disintegrator
Copy link

nice 👍

@EIrwin
Copy link

EIrwin commented Sep 3, 2017

I do agree that gofmt is not opinionated enough and can be improved in many areas. It seems that the opinion of gofmt in this case is in the form of not enforcing line length which as you mentioned can be argued as more readable. This seems to be the opinion.

@chickenandpork
Copy link

blacken is the opinionated python formatter; I wish gofmt had a "black" mode, whereby it did adhere to a single format -- including line-length. I've worked at FB, and I assume the same code velocity at Google would cause them to govern line-lengths for internal toolsets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment