github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/STYLE_GUIDE.md (about) 1 # Go Coding Style Guide 2 3 In order to keep our code looking good with lots of programmers working on it, it helps to have a "style guide", so all 4 the code generally looks quite similar. This doesn't mean there is only one "right way" to write code, or even that this 5 standard is better than your style. But if we agree to a number of stylistic practices, it makes it much easier to read 6 and modify new code. Please feel free to make suggestions if there's something you would like to add or modify. 7 8 We expect all contributors to be familiar with [Effective Go](https://golang.org/doc/effective_go.html) 9 (and it's recommended reading for all Go programmers anyways). Additionally, we generally agree with the suggestions 10 in [Uber's style guide](https://github.com/uber-go/guide/blob/master/style.md) and use that as a starting point. 11 12 13 ## Code Structure 14 15 Perhaps more key for code readability than good commenting is having the right structure. As a rule of thumb, try to write 16 in a logical order of importance, taking a little time to think how to order and divide the code such that someone could 17 scroll down and understand the functionality of it just as well as you do. A loose example of such order would be: 18 * Constants, global and package-level variables 19 * Main Struct 20 * Options (only if they are seen as critical to the struct else they should be placed in another file) 21 * Initialization / Start and stop of the service 22 * Msgs/Events 23 * Public Functions (In order of most important) 24 * Private/helper functions 25 * Auxiliary structs and function (can also be above private functions or in a separate file) 26 27 ## General 28 29 * Use `gofmt` (or `goimport`) to format all code upon saving it. (If you use VIM, check out vim-go). 30 * Use a linter (see below) and generally try to keep the linter happy (where it makes sense). 31 * Think about documentation, and try to leave godoc comments, when it will help new developers. 32 * 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. 33 * `TODO` should not be used. If important enough should be recorded as an issue. 34 * `BUG` / `FIXME` should be used sparingly to guide future developers on some of the vulnerabilities of the code. 35 * `XXX` can be used in work-in-progress (prefixed with "WIP:" on github) branches but they must be removed before approving a PR. 36 * Applications (e.g. clis/servers) *should* panic on unexpected unrecoverable errors and print a stack trace. 37 38 ## Comments 39 40 * Use a space after comment deliminter (ex. `// your comment`). 41 * Many comments are not sentences. These should begin with a lower case letter and end without a period. 42 * Conversely, sentences in comments should be sentenced-cased and end with a period. 43 44 ## Linters 45 46 These must be applied to all (Go) repos. 47 48 * [shellcheck](https://github.com/koalaman/shellcheck) 49 * [golangci-lint](https://github.com/golangci/golangci-lint) (covers all important linters) 50 - See the `.golangci.yml` file in each repo for linter configuration. 51 52 ## Various 53 54 * Reserve "Save" and "Load" for long-running persistence operations. When parsing bytes, use "Encode" or "Decode". 55 * Maintain consistency across the codebase. 56 * Functions that return functions should have the suffix `Fn` 57 * Names should not [stutter](https://blog.golang.org/package-names). For example, a struct generally shouldn’t have 58 a field named after itself; e.g., this shouldn't occur: 59 ``` golang 60 type middleware struct { 61 middleware Middleware 62 } 63 ``` 64 * In comments, use "iff" to mean, "if and only if". 65 * Product names are capitalized, like "Tendermint", "Basecoin", "Protobuf", etc except in command lines: `tendermint --help` 66 * Acronyms are all capitalized, like "RPC", "gRPC", "API". "MyID", rather than "MyId". 67 * Prefer errors.New() instead of fmt.Errorf() unless you're actually using the format feature with arguments. 68 69 ## Importing Libraries 70 71 Sometimes it's necessary to rename libraries to avoid naming collisions or ambiguity. 72 73 * Use [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) 74 * Separate imports into blocks - one for the standard lib, one for external libs and one for application libs. 75 * Here are some common library labels for consistency: 76 - dbm "github.com/tendermint/tm-db" 77 - tmcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" 78 - tmcfg "github.com/tendermint/tendermint/config/tendermint" 79 - tmtypes "github.com/tendermint/tendermint/types" 80 * Never use anonymous imports (the `.`), for example, `tmlibs/common` or anything else. 81 * When importing a pkg from the `tendermint/libs` directory, prefix the pkg alias with tm. 82 - tmbits "github.com/tendermint/tendermint/libs/bits" 83 * tip: Use the `_` library import to import a library for initialization effects (side effects) 84 85 ## Dependencies 86 87 * Dependencies should be pinned by a release tag, or specific commit, to avoid breaking `go get` when external dependencies are updated. 88 * Refer to the [contributing](CONTRIBUTING.md) document for more details 89 90 ## Testing 91 92 * The first rule of testing is: we add tests to our code 93 * The second rule of testing is: we add tests to our code 94 * For Golang testing: 95 * Make use of table driven testing where possible and not-cumbersome 96 - [Inspiration](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) 97 * Make use of [assert](https://godoc.org/github.com/stretchr/testify/assert) and [require](https://godoc.org/github.com/stretchr/testify/require) 98 * When using mocks, it is recommended to use Testify [mock] (https://pkg.go.dev/github.com/stretchr/testify/mock 99 ) along with [Mockery](https://github.com/vektra/mockery) for autogeneration 100 101 ## Errors 102 103 * Ensure that errors are concise, clear and traceable. 104 * Use stdlib errors package. 105 * For wrapping errors, use `fmt.Errorf()` with `%w`. 106 * Panic is appropriate when an internal invariant of a system is broken, while all other cases (in particular, 107 incorrect or invalid usage) should return errors. 108 109 ## Config 110 111 * Currently the TOML filetype is being used for config files 112 * A good practice is to store per-user config files under `~/.[yourAppName]/config.toml` 113 114 ## CLI 115 116 * When implementing a CLI use [Cobra](https://github.com/spf13/cobra) and [Viper](https://github.com/spf13/viper). 117 * Helper messages for commands and flags must be all lowercase. 118 * Instead of using pointer flags (eg. `FlagSet().StringVar`) use Viper to retrieve flag values (eg. `viper.GetString`) 119 - The flag key used when setting and getting the flag should always be stored in a 120 variable taking the form `FlagXxx` or `flagXxx`. 121 - Flag short variable descriptions should always start with a lower case character as to remain consistent with 122 the description provided in the default `--help` flag. 123 124 ## Version 125 126 * Every repo should have a version/version.go file that mimics the Tendermint Core repo 127 * We read the value of the constant version in our build scripts and hence it has to be a string 128 129 ## Non-Go Code 130 131 * All non-Go code (`*.proto`, `Makefile`, `*.sh`), where there is no common 132 agreement on style, should be formatted according to 133 [EditorConfig](http://editorconfig.org/) config: 134 135 ``` 136 # top-most EditorConfig file 137 root = true 138 139 # Unix-style newlines with a newline ending every file 140 [*] 141 charset = utf-8 142 end_of_line = lf 143 insert_final_newline = true 144 trim_trailing_whitespace = true 145 146 [Makefile] 147 indent_style = tab 148 149 [*.sh] 150 indent_style = tab 151 152 [*.proto] 153 indent_style = space 154 indent_size = 2 155 ``` 156 157 Make sure the file above (`.editorconfig`) are in the root directory of your 158 repo and you have a [plugin for your 159 editor](http://editorconfig.org/#download) installed.