Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: refactor contributing guidelines - add go style guide #2709

Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions docs/dev/go-style-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

# Go style guide

In order to keep our code looking good with lots of programmers working on it, it helps to have a "style guide", so all the code generally looks quite similar. This doesn't mean there is only one "right way" to write code, or even that this standard is better than your style. But if we agree to a number of stylistic practices, it makes it much easier to read and modify new code. Please feel free to make suggestions if there's something you would like to add or modify.

We expect all contributors to be familiar with [Effective Go](https://golang.org/doc/effective_go.html) (and it's recommended reading for all Go programmers anyways). Additionally, we generally agree with the suggestions in [Uber's style guide](https://github.com/uber-go/guide/blob/master/style.md) and use that as a starting point.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never read the Uber style guide. What's particularly useful about it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had a scroll threw it once or twice before, but not read in-depth.

In summary, it more or less just had pretty good, reasonable and sane suggestions wrt code style and things that are considered more "idiomatic go".


## Code Structure

Perhaps more key for code readability than good commenting is having the right structure. As a rule of thumb, try to write in a logical order of importance, taking a little time to think how to order and divide the code such that someone could scroll down and understand the functionality of it just as well as you do. A loose example of such order would be:

- Constants, global and package-level variables
- Main Struct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this mean exactly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say a struct definition...

- Options (only if they are seen as critical to the struct else they should be placed in another file)
- Initialization / Start and stop of the service
- Msgs/Events
- Public Functions (In order of most important)
- Private/helper functions
- Auxiliary structs and function (can also be above private functions or in a separate file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this section is very reflective of our existing code. Msgs/Events are split into separate files so I don't understand how there is an ordering here?


## General

* Use `gofumpt` to format all code upon saving it (or run `make format`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need to change anything now, but I think we should establish some sort of pre-commit hook that will run all this stuff. Relying on people to run make format manually each time isn't ideal.

* Think about documentation, and try to leave godoc comments, when it will help new developers.
* Every package should have a high level doc.go file to describe the purpose of that package, its main functions, and any other relevant information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't follow this practice at the moment..

* Applications (e.g. clis/servers) *should* panic on unexpected unrecoverable errors and print a stack trace.

## Comments

* Use a space after the comment deliminter (ex. `// your comment`).
* Many comments are not sentences. These should begin with a lower case letter and end without a period.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we need to include things like this that can easily automated with a linter?

* Conversely, sentences in comments should be sentenced-cased and end with a period.

## Linting

* Run `make lint-fix` to fix any linting errors.

## Various

- Functions that return functions should have the suffix `Fn`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we apply this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do in some places, but I can open a separate PR to update all occurrences.

- Names should not [stutter](https://blog.golang.org/package-names). For example, a struct generally shouldn’t have a field named after itself; e.g., this shouldn't occur:

``` golang
type middleware struct {
middleware Middleware
}
```

* In comments, use "iff" to mean, "if and only if".
* Acronyms are all capitalized, like "RPC", "gRPC", "API". "MyID", rather than "MyId".
* Prefer errors.New() instead of fmt.Errorf() unless you're actually using the format feature with arguments.

## Importing libraries

* Use [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports).
* Separate imports into blocks - one for the standard lib, one for external libs and one for application libs.

## Dependencies

* Dependencies should be pinned by a release tag, or specific commit, to avoid breaking `go get` when external dependencies are updated.
* Refer to the [contributing](./development.md#dependencies) document for more details

## Testing

- Make use of table driven testing where possible and not-cumbersome. Read [this blog post](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) for more information.
- Make use of [assert](https://godoc.org/github.com/stretchr/testify/assert) and [require](https://godoc.org/github.com/stretchr/testify/require)
- When using mocks, it is recommended to use Testify [mock](https://pkg.go.dev/github.com/stretchr/testify/mock) along with [Mockery](https://github.com/vektra/mockery) for autogeneration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we apply this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can if we ever need to use mocks!


## Errors

- Ensure that errors are concise, clear and traceable.
- Use stdlib errors package.
- For wrapping errors, use `fmt.Errorf()` with `%w`.
- Panic is appropriate when an internal invariant of a system is broken, while all other cases (in particular, incorrect or invalid usage) should return errors.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this in general, but I feel like it is a special case with the SDK where returning errors can sometimes reset state changes and panics are caught and as a result will not result in the shutdown of the system.