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