This guide establishes shared stylistic conventions for the Tenderdash codebase. We expect all contributors to be familiar with Effective Go. We also use Uber's style guide as a starting point.
Try to write in a logical order of importance so that someone scrolling down can understand the functionality. A loose example:
- Constants, global and package-level variables
- Main Struct
- Options (only if critical to the struct; otherwise place in another file)
- Initialization / Start and stop of the service
- Msgs/Events
- Public functions (in order of importance)
- Private/helper functions
- Auxiliary structs and functions (can also be in a separate file)
- Don't Repeat Yourself. Search the codebase before writing new code.
- Less code is better. Review code after implementation to ensure it cannot be written in a shorter form.
- Use
gofmt(orgoimports) to format all code upon saving. - Use a linter (see below) and keep it happy where it makes sense.
- Leave godoc comments when they will help new developers.
TODOshould not be used. If important enough, file an issue.BUG/FIXMEshould be used sparingly.XXXmay appear in WIP branches but must be removed before merging.- Applications (e.g. CLIs/servers) should panic on unexpected unrecoverable errors and print a stack trace.
- Use a space after the comment delimiter (e.g.
// your comment). - Non-sentence comments should begin with a lower case letter and end without a period.
- Sentence comments should be sentence-cased and end with a period.
- Lint your changes to the code base, not the whole project.
- golangci-lint — see
.golangci.ymlfor configuration.
-
Reserve "Save" and "Load" for long-running persistence operations. For parsing bytes, use "Encode" or "Decode".
-
Functions that return functions should have the suffix
Fn. -
Names should not stutter. For example, avoid:
type middleware struct { middleware Middleware }
-
Product names are capitalized ("Tenderdash", "Protobuf") except in command lines:
tenderdash --help. -
Acronyms are all-caps: "RPC", "gRPC", "API", "MyID" (not "MyId").
-
Prefer
errors.New()overfmt.Errorf()unless you need format arguments.
- Use goimports.
- Separate imports into three blocks: standard library, external, and application.
- Never use dot imports (
.). - Use the
_import for side-effect-only imports.
- All code must have tests.
- Use table-driven tests where possible and not cumbersome.
- Use assert and require from testify.
- For mocks, use Testify mock with Mockery for autogeneration.
- Ensure errors are concise, clear, and traceable.
- Use the stdlib
errorspackage. - Wrap errors with
fmt.Errorf()and%w. - Panic only when an internal invariant is broken. All other cases should return errors.
All non-Go code (*.proto, Makefile, *.sh) should be formatted according
to the EditorConfig in the repo root (.editorconfig).