{"id":13476887,"url":"https://github.com/bahlo/go-styleguide","last_synced_at":"2025-05-15T15:05:22.932Z","repository":{"id":42019451,"uuid":"98724416","full_name":"bahlo/go-styleguide","owner":"bahlo","description":"🏆 Opinionated Styleguide for the Go language","archived":false,"fork":false,"pushed_at":"2024-08-02T17:05:35.000Z","size":85,"stargazers_count":1510,"open_issues_count":0,"forks_count":126,"subscribers_count":31,"default_branch":"main","last_synced_at":"2025-04-07T18:11:11.095Z","etag":null,"topics":["effective","go","golang","styleguide"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bahlo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"bahlo"}},"created_at":"2017-07-29T10:03:30.000Z","updated_at":"2025-04-06T22:15:16.000Z","dependencies_parsed_at":"2024-08-02T19:45:24.618Z","dependency_job_id":"cdaba7e0-31c8-4343-8b94-300eb4cda032","html_url":"https://github.com/bahlo/go-styleguide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahlo%2Fgo-styleguide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahlo%2Fgo-styleguide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahlo%2Fgo-styleguide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahlo%2Fgo-styleguide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bahlo","download_url":"https://codeload.github.com/bahlo/go-styleguide/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254364270,"owners_count":22058878,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["effective","go","golang","styleguide"],"created_at":"2024-07-31T16:01:35.758Z","updated_at":"2025-05-15T15:05:22.877Z","avatar_url":"https://github.com/bahlo.png","language":null,"funding_links":["https://github.com/sponsors/bahlo"],"categories":["Others","Style Guides","Languages","Twitter","风格指南","Repositories"],"sub_categories":["Free e-books","Other Software","免费电子书"],"readme":"# Go Styleguide\n\nThis serves as a supplement to\n[Effective Go](https://golang.org/doc/effective_go.html), based on years of\nexperience and inspiration/ideas from conference talks.\n\n## Table of contents\n- [Add context to errors](#add-context-to-errors)\n- [Consistent error and log messages](#consistent-error-and-log-messages)\n- [Dependency management](#dependency-management)\n  - [Use modules](#use-modules)\n  - [Use Semantic Versioning](#use-semantic-versioning)\n- [Structured logging](#structured-logging)\n- [Avoid global variables](#avoid-global-variables)\n- [Keep the happy path left](#keep-the-happy-path-left)\n- [Testing](#testing)\n  - [Use an assert library](#use-an-assert-library)\n  - [Use sub-tests to structure functional tests](#use-sub-tests-to-structure-functional-tests)\n  - [Use table-driven tests](#use-table-driven-tests)\n  - [Avoid mocks](#avoid-mocks)\n  - [Avoid DeepEqual](#avoid-deepequal)\n  - [Avoid testing unexported funcs](#avoid-testing-unexported-funcs)\n  - [Add examples to your test files to demonstrate usage](#add-examples-to-your-test-files-to-demonstrate-usage)\n- [Use linters](#use-linters)\n- [Use goimports](#use-goimports)\n- [Use meaningful variable names](#use-meaningful-variable-names)\n- [Avoid side effects](#avoid-side-effects)\n- [Favour pure functions](#favour-pure-functions)\n- [Don't over-interface](#dont-over-interface)\n- [Don't under-package](#dont-under-package)\n- [Handle signals](#handle-signals)\n- [Divide imports](#divide-imports)\n- [Avoid unadorned return](#avoid-unadorned-return)\n- [Use canonical import path](#use-canonical-import-path)\n- [Avoid empty interface](#avoid-empty-interface)\n- [Main first](#main-first)\n- [Use internal packages](#use-internal-packages)\n- [Avoid helper/util](#avoid-helperutil)\n- [Embed binary data](#embed-binary-data)\n- [Use `io.WriteString`](#use-iowritestring)\n- [Use functional options](#use-functional-options)\n- [Structs](#structs)\n  - [Use named structs](#use-named-structs)\n  - [Avoid new keyword](#avoid-new-keyword)\n- [Consistent header naming](#consistent-header-naming)\n- [Avoid magic numbers](#avoid-magic-numbers)\n- [Use context for cancellation](#use-context-for-cancellation)\n- [Avoid panic in production](#avoid-panic-in-production)\n- [Error handling and error types](#error-handling-and-error-types)\n- [Code formatting](#code-formatting)\n- [Concurrency patterns](#concurrency-patterns)\n- [Package documentation](#package-documentation)\n- [Avoid unnecessary abstraction](#avoid-unnecessary-abstraction)\n\n## Add context to errors\n\n**Don't:**\n```go\nfile, err := os.Open(\"foo.txt\")\nif err != nil {\n\treturn err\n}\n```\n\nUsing the approach above can lead to unclear error messages because of missing\ncontext.\n\n**Do:**\n```go\nfile, err := os.Open(\"foo.txt\")\nif err != nil {\n\treturn fmt.Errorf(\"open foo.txt failed: %w\", err)\n}\n```\n\nWrapping errors with a custom message provides context as it gets propagated up\nthe stack.\nThis does not always make sense.\nIf you're unsure if the context of a returned error is at all times sufficient,\nwrap it.\n\n## Dependency management\n\n### Use modules\nUse [modules](https://github.com/golang/go/wiki/Modules), since it is the built-in go dependency \nmanagement tooling and will be widely supported (available with Go 1.11+).\n\n### Use Semantic Versioning\nTag your packages using [Semantic Versioning](http://semver.org), check the [modules wiki](https://github.com/golang/go/wiki/Modules#how-to-prepare-for-a-release) for more information about\nbest practices regarding releases.\nThe git tag for your go package should have the format `v\u003cmajor\u003e.\u003cminor\u003e.\u003cpatch\u003e`, e.g., `v1.0.1`.\n\n## Structured logging\n\n**Don't:**\n```go\nlog.Printf(\"Listening on :%d\", port)\nhttp.ListenAndServe(fmt.Sprintf(\":%d\", port), nil)\n// 2017/07/29 13:05:50 Listening on :80\n```\n\n**Do:**\n```go\nimport \"github.com/sirupsen/logrus\"\n// ...\n\nlogger.WithField(\"port\", port).Info(\"Server is listening\")\nhttp.ListenAndServe(fmt.Sprintf(\":%d\", port), nil)\n// {\"level\":\"info\",\"msg\":\"Server is listening\",\"port\":\"7000\",\"time\":\"2017-12-24T13:25:31+01:00\"}\n```\n\nThis is a harmless example, but using structured logging makes debugging and log\nparsing easier.\n\n## Avoid global variables\n\n**Don't:**\n```go\nvar db *sql.DB\n\nfunc main() {\n\tdb = // ...\n\thttp.HandleFunc(\"/drop\", DropHandler)\n\t// ...\n}\n\nfunc DropHandler(w http.ResponseWriter, r *http.Request) {\n\tdb.Exec(\"DROP DATABASE prod\")\n}\n```\n\nGlobal variables make testing and readability hard and every method has access\nto them (even those, that don't need it).\n\n**Do:**\n```go\nfunc main() {\n\tdb := // ...\n\thandlers := Handlers{DB: db}\n\thttp.HandleFunc(\"/drop\", handlers.DropHandler)\n\t// ...\n}\n\ntype Handlers struct {\n\tDB *sql.DB\n}\n\nfunc (h *Handlers) DropHandler(w http.ResponseWriter, r *http.Request) {\n\th.DB.Exec(\"DROP DATABASE prod\")\n}\n```\nUse structs to encapsulate the variables and make them available only to those functions that actually need them by making them methods implemented for that struct.\n\nAlternatively, higher-order functions can be used to inject dependencies via closures.\n```go\nfunc main() {\n\tdb := // ...\n\thttp.HandleFunc(\"/drop\", DropHandler(db))\n\t// ...\n}\n\nfunc DropHandler(db *sql.DB) http.HandleFunc {\n\treturn func (w http.ResponseWriter, r *http.Request) {\n\t\tdb.Exec(\"DROP DATABASE prod\")\n\t}\n}\n```\n\nIf you really need global variables or constants, e.g., for defining errors or string constants, put them at the top of your file.\n\n**Don't:**\n```go\nimport \"xyz\"\n\nfunc someFunc() {\n\t//...\n}\n\nconst route = \"/some-route\"\n\nfunc someOtherFunc() {\n\t// usage of route\n}\n\nvar NotFoundErr = errors.New(\"not found\")\n\nfunc yetAnotherFunc() {\n\t// usage of NotFoundErr\n}\n```\n\n**Do:**\n```go\nimport \"xyz\"\n\nconst route = \"/some-route\"\n\nvar NotFoundErr = errors.New(\"not found\")\n\nfunc someFunc() {\n\t//...\n}\n\nfunc someOtherFunc() {\n\t// usage of route\n}\n\nfunc yetAnotherFunc() {\n\t// usage of NotFoundErr\n}\n```\n\n## Keep the happy path left\n\n**Don't:**\n```go\nif item, ok := someMap[someKey]; ok {\n\treturn item\n}\nreturn ErrKeyNotFound\n```\n\n**Do:**\n```go\nitem, ok := someMap[someKey]\nif !ok {\n\treturn ErrKeyNotFound\n}\nreturn item\n```\n\nThis helps to keep your code clear and readable. Not doing it accumulates in \nlarger functions and leads to the happy path being buried in a lot of if/for/... \nstatements.\n\n## Testing\n\n### Use an assert library\n\n**Don't:**\n```go\nfunc TestAdd(t *testing.T) {\n\tactual := 2 + 2\n\texpected := 4\n\tif (actual != expected) {\n\t\tt.Errorf(\"Expected %d, but got %d\", expected, actual)\n\t}\n}\n```\n\n**Do:**\n```go\nimport \"github.com/stretchr/testify/assert\"\n\nfunc TestAdd(t *testing.T) {\n\tactual := 2 + 2\n\texpected := 4\n\tassert.Equal(t, expected, actual)\n}\n```\n\nUsing assert libraries makes your tests more readable, requires less code and\nprovides consistent error output.\n\n### Use sub-tests to structure functional tests\n**Don't:**\n```go\nfunc TestSomeFunctionSuccess(t *testing.T) {\n\t// ...\n}\n\nfunc TestSomeFunctionWrongInput(t *testing.T) {\n\t// ...\n}\n```\n\n**Do:**\n```go\nfunc TestSomeFunction(t *testing.T) {\n\tt.Run(\"success\", func(t *testing.T){\n\t\t//...\n\t})\n\n\tt.Run(\"wrong input\", func(t *testing.T){\n\t\t//...\n\t})\n}\n```\n\n### Use table driven tests\n\n**Don't:**\n```go\nfunc TestAdd(t *testing.T) {\n\tassert.Equal(t, 1+1, 2)\n\tassert.Equal(t, 1+-1, 0)\n\tassert.Equal(t, 1, 0, 1)\n\tassert.Equal(t, 0, 0, 0)\n}\n```\n\nThe above approach looks simpler, but it's much harder to find a failing case,\nespecially when having hundreds of cases.\n\n**Do:**\n```go\nfunc TestAdd(t *testing.T) {\n\tcases := []struct {\n\t\tA, B, Expected int\n\t}{\n\t\t{1, 1, 2},\n\t\t{1, -1, 0},\n\t\t{1, 0, 1},\n\t\t{0, 0, 0},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttc := tc\n\t\tt.Run(fmt.Sprintf(\"%d + %d\", tc.A, tc.B), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tassert.Equal(t, tc.Expected, tc.A+tc.B)\n\t\t})\n\t}\n}\n```\n\nUsing table-driven tests in combination with subtests gives you direct insight\nabout which case is failing and which cases are tested.\n– [Mitchell Hashimoto at GopherCon 2017](https://youtu.be/8hQG7QlcLBk?t=7m34s)\n\nRunning subtests in parallel allow you to have a lot more test cases and still get those awesomely fast go build times.\n– [The Go Blog](https://blog.golang.org/subtests)\n\nA `tc := tc` is needed. Because without it, only one of the cases would be checked.\n– [Be Careful with Table Driven Tests and t.Parallel()](https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721)\n\n### Avoid mocks\n\n**Don't:**\n```go\nfunc TestRun(t *testing.T) {\n\tmockConn := new(MockConn)\n\trun(mockConn)\n}\n```\n\n**Do:**\n```go\nimport \"github.com/stretchr/testify/assert\"\n\nfunc TestRun(t *testing.T) {\n\tln, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tassert.Nil(t, err)\n\n\tgo func() {\n\t\tdefer ln.Close()\n\t\t_, err := ln.Accept()\n\t\tassert.Nil(t, err)\n\t}()\n\n\tclient, err := net.Dial(\"tcp\", ln.Addr().String())\n\tassert.Nil(t, err)\n\n\trun(client)\n}\n```\n\nOnly use mocks if not otherwise possible, favor real implementations.\n– [Mitchell Hashimoto at GopherCon 2017](https://youtu.be/8hQG7QlcLBk?t=26m51s)\n\n### Avoid DeepEqual\n\n**Don't:**\n```go\ntype myType struct {\n\tid         int\n\tname       string\n\tirrelevant []byte\n}\n\nfunc TestSomething(t *testing.T) {\n\tactual := \u0026myType{/* ... */}\n\texpected := \u0026myType{/* ... */}\n\tassert.True(t, reflect.DeepEqual(expected, actual))\n}\n```\n\n**Do:**\n```go\ntype myType struct {\n\tid         int\n\tname       string\n\tirrelevant []byte\n}\n\nfunc (m *myType) testString() string {\n\treturn fmt.Sprintf(\"%d.%s\", m.id, m.name)\n}\n\nfunc TestSomething(t *testing.T) {\n\tactual := \u0026myType{/* ... */}\n\texpected := \u0026myType{/* ... */}\n\tif actual.testString() != expected.testString() {\n\t\tt.Errorf(\"Expected '%s', got '%s'\", expected.testString(), actual.testString())\n\t}\n\t// or assert.Equal(t, actual.testString(), expected.testString())\n}\n```\n\nUsing `testString()` for comparing structs helps on complex structs with many\nfields that are not relevant for the equality check.\nThis approach only makes sense for very big or tree-like structs.\n– [Mitchell Hashimoto at GopherCon 2017](https://youtu.be/8hQG7QlcLBk?t=30m45s)\n\nGoogle open sourced their [go-cmp](http://github.com/google/go-cmp) package as a more powerful and safer alternative to `reflect.DeepEqual`.\n– [Joe Tsai](https://twitter.com/francesc/status/885630175668346880).\n\n### Avoid testing unexported funcs\n\nOnly test unexported funcs if you can't access a path via exported funcs.\nSince they are unexported, they are prone to change.\n\n### Add examples to your test files to demonstrate usage\n```go\nfunc ExampleSomeInterface_SomeMethod(){\n\tinstance := New()\n\tresult, err := instance.SomeMethod()\n\tfmt.Println(result, err)\n\t// Output: someResult, \u003cnil\u003e\n}\n```\n\n## Use linters\n\nUse all the linters included in [golangci-lint](https://github.com/golangci/golangci-lint) to lint your projects before committing.\n```bash\n# Installation - replace vX.X.X with the version you want to use\nGO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@vX.X.X\n# traditional way without go module\ngo get -u github.com/golangci/golangci-lint/cmd/golangci-lint\n\n\n# Usage in the project workspace\ngolangci-lint run\n```\nFor detailed usage and the ci-pipeline installation guide visit [golangci-lint](https://github.com/golangci/golangci-lint).\n\n## Use goimports\n\nOnly commit gofmt'd files. Use `goimports` for this to format/update the import statements as well.\n\n## Use meaningful variable names\nAvoid single-letter variable names. They may seem more readable to you at the moment of writing but they make the code hard to understand for your colleagues and your future self.\n\n**Don't:**\n```go\nfunc findMax(l []int) int {\n\tm := l[0]\n\tfor _, n := range l {\n\t\tif n \u003e m {\n\t\t\tm = n\n\t\t}\n\t}\n\treturn m\n}\n```\n\n**Do:**\n```go\nfunc findMax(inputs []int) int {\n\tmax := inputs[0]\n\tfor _, value := range inputs {\n\t\tif value \u003e max {\n\t\t\tmax = value\n\t\t}\n\t}\n\treturn max\n}\n```\nSingle-letter variable names are fine in the following cases.\n* They are absolute standard like ...\n\t* `t` in tests\n\t* `r` and `w` in http request handlers\n\t* `i` for the index in a loop\n* They name the receiver of a method, e.g., `func (s *someStruct) myFunction(){}`\n\nOf course also too long variables names like `createInstanceOfMyStructFromString` should be avoided.\n\n## Avoid side-effects\n\n**Don't:**\n```go\nfunc init() {\n\tsomeStruct.Load()\n}\n```\n\nSide effects are only okay in special cases (e.g. parsing flags in a cmd).\nIf you find no other way, rethink and refactor.\n\n## Favour pure functions\n\n\u003e In computer programming, a function may be considered a pure function if both of the following statements about the function hold:\n\u003e 1. The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices.\n\u003e 2. Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.\n\n– [Wikipedia](https://en.wikipedia.org/wiki/Pure_function)\n\n**Don't:**\n```go\nfunc MarshalAndWrite(some *Thing) error {\n\tb, err := json.Marshal(some)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn ioutil.WriteFile(\"some.thing\", b, 0644)\n}\n```\n\n**Do:**\n```go\n// Marshal is a pure func (even though useless)\nfunc Marshal(some *Thing) ([]bytes, error) {\n\treturn json.Marshal(some)\n}\n\n// ...\n```\n\nThis is obviously not possible at all times, but trying to make every possible\nfunc pure makes code more understandable and improves debugging.\n\n## Don't over-interface\n\n**Don't:**\n```go\ntype Server interface {\n\tServe() error\n\tSome() int\n\tFields() float64\n\tThat() string\n\tAre([]byte) error\n\tNot() []string\n\tNecessary() error\n}\n\nfunc debug(srv Server) {\n\tfmt.Println(srv.String())\n}\n\nfunc run(srv Server) {\n\tsrv.Serve()\n}\n```\n\n**Do:**\n```go\ntype Server interface {\n\tServe() error\n}\n\nfunc debug(v fmt.Stringer) {\n\tfmt.Println(v.String())\n}\n\nfunc run(srv Server) {\n\tsrv.Serve()\n}\n```\n\nFavour small interfaces and only expect the interfaces you need in your funcs.\n\n## Don't under-package\n\nDeleting or merging packages is far easier than splitting big ones up.\nWhen unsure if a package can be split, do it.\n\n## Handle signals\n\n**Don't:**\n```go\nfunc main() {\n\tfor {\n\t\ttime.Sleep(1 * time.Second)\n\t\tioutil.WriteFile(\"foo\", []byte(\"bar\"), 0644)\n\t}\n}\n```\n\n**Do:**\n```go\nfunc main() {\n\tlogger := // ...\n\tsc := make(chan os.Signal, 1)\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase s := \u003c-sc:\n\t\t\t\tlogger.Info(\"Received signal, stopping application\",\n\t\t\t\t\tzap.String(\"signal\", s.String()))\n\t\t\t\tdone \u003c- true\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t\ttime.Sleep(1 * time.Second)\n\t\t\t\tioutil.WriteFile(\"foo\", []byte(\"bar\"), 0644)\n\t\t\t}\n\t\t}\n\t}()\n\n\tsignal.Notify(sc, os.Interrupt, os.Kill)\n\t\u003c-done // Wait for go-routine\n}\n```\n\nHandling signals allows us to gracefully stop our server, close open files and\nconnections and therefore prevent file corruption among other things.\n\n## Divide imports\n\n**Don't:**\n```go\nimport (\n\t\"encoding/json\"\n\t\"github.com/some/external/pkg\"\n\t\"fmt\"\n\t\"github.com/this-project/pkg/some-lib\"\n\t\"os\"\n)\n```\n\n**Do:**\n```go\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/bahlo/this-project/pkg/some-lib\"\n\n\t\"github.com/bahlo/another-project/pkg/some-lib\"\n\t\"github.com/bahlo/yet-another-project/pkg/some-lib\"\n\n\t\"github.com/some/external/pkg\"\n\t\"github.com/some-other/external/pkg\"\n)\n```\n\nDivide imports into four groups sorted from internal to external for readability:\n1. Standard library\n2. Project internal packages\n3. Company internal packages\n4. External packages\n\n## Avoid unadorned return\n\n**Don't:**\n```go\nfunc run() (n int, err error) {\n\t// ...\n\treturn\n}\n```\n\n**Do:**\n```go\nfunc run() (n int, err error) {\n\t// ...\n\treturn n, err\n}\n```\n\nNamed returns are good for documentation, unadorned returns are bad for\nreadability and error-prone.\n\n## Use canonical import path\n\n**Don't:**\n```go\npackage sub\n```\n\n**Do:**\n```go\npackage sub // import \"github.com/my-package/pkg/sth/else/sub\"\n```\n\nAdding the canonical import path adds context to the package and makes\nimporting easy.\n\n## Avoid empty interface\n\n**Don't:**\n```go\nfunc run(foo interface{}) {\n\t// ...\n}\n```\n\nEmpty interfaces make code more complex and unclear, avoid them where you can.\n\n## Main first\n\n**Don't:**\n```go\npackage main // import \"github.com/me/my-project\"\n\nfunc someHelper() int {\n\t// ...\n}\n\nfunc someOtherHelper() string {\n\t// ...\n}\n\nfunc Handler(w http.ResponseWriter, r *http.Reqeust) {\n\t// ...\n}\n\nfunc main() {\n\t// ...\n}\n```\n\n**Do:**\n```go\npackage main // import \"github.com/me/my-project\"\n\nfunc main() {\n\t// ...\n}\n\nfunc Handler(w http.ResponseWriter, r *http.Reqeust) {\n\t// ...\n}\n\nfunc someHelper() int {\n\t// ...\n}\n\nfunc someOtherHelper() string {\n\t// ...\n}\n```\n\nPutting `main()` first makes reading the file a lot easier. Only the\n`init()` function should be above it.\n\n## Use internal packages\n\nIf you're creating a cmd, consider moving libraries to `internal/` to prevent\nimport of unstable, changing packages.\n\n## Avoid helper/util\n\nUse clear names and try to avoid creating a `helper.go`, `utils.go` or even\npackage.\n\n## Embed binary data\n\nTo enable single-binary deployments, use the `//go:embed` directive and the [embed](https://pkg.go.dev/embed) package to add templates and other static\nassets to your binary.  \nFor Go versions prior [v1.16](https://go.dev/doc/go1.16#library-embed), use external tools \n(e.g. [github.com/gobuffalo/packr](https://github.com/gobuffalo/packr)).\n\n## Use `io.WriteString`\nA number of important types that satisfy `io.Writer` also have a `WriteString`\nmethod, including `*bytes.Buffer`, `*os.File` and `*bufio.Writer`. `WriteString`\nis behavioral contract with implicit assent that passed string will be written\nin efficient way, without a temporary allocation. Therefore using\n`io.WriteString` may improve performance at most, and at least string will be\nwritten in any way.\n\n**Don't:**\n```go\nvar w io.Writer = new(bytes.Buffer)\nstr := \"some string\"\nw.Write([]byte(str))\n```\n\n**Do:**\n```go\nvar w io.Writer = new(bytes.Buffer)\nstr := \"some string\"\nio.WriteString(w, str)\n```\n\n## Use functional options\n\n```go\n\nfunc main() {\n\t// ...\n\tstartServer(\n\t\tWithPort(8080),\n\t\tWithTimeout(1 * time.Second),\n\t)\n}\n\ntype Config struct {\n\tport    int\n\ttimeout time.Duration\n}\n\ntype ServerOpt func(*Config)\n\nfunc WithPort(port int) ServerOpt {\n\treturn func(cfg *Config) {\n\t\tcfg.port = port\n\t}\n}\n\nfunc WithTimeout(timeout time.Duration) ServerOpt {\n\treturn func(cfg *Config) {\n\t\tcfg.timeout = timeout\n\t}\n}\n\nfunc startServer(opts ...ServerOpt) {\n\tcfg := new(Config)\n\tfor _, fn := range opts {\n\t\tfn(cfg)\n\t}\n\n\t// ...\n}\n\n\n```\n\n## Structs\n### Use named structs\nIf a struct has more than one field, include field names when instantiating it.\n\n**Don't:**\n```go\nparams := myStruct{\n\t1, \n\ttrue,\n}\n```\n\n**Do:**\n```go\nparams := myStruct{\n\tFoo: 1,\n\tBar: true,\n}\n```\n\n### Avoid new keyword\nUsing the normal syntax instead of the `new` keyword makes it more clear what is happening: a new instance of the struct is created `MyStruct{}` and we get the pointer for it with `\u0026`.\n\n**Don't:**\n```go\ns := new(MyStruct)\n```\n\n**Do:**\n```go\ns := \u0026MyStruct{}\n```\n\n## Consistent header naming\n**Don't:**\n```go\nr.Header.Get(\"authorization\")\nw.Header.Set(\"Content-type\")\nw.Header.Set(\"content-type\")\nw.Header.Set(\"content-Type\")\n```\n\n**Do:**\n```go\nr.Header.Get(\"Authorization\")\nw.Header.Set(\"Content-Type\")\n```\n\n## Avoid magic numbers\nA number without a name and any context is just a random value. It tells us nothing, so avoid them in your code (the exception might be the number 0, for example when creating loops). \n\n**Don't:**\n```go\nfunc IsStrongPassword(password string) bool {\n\treturn len(password) \u003e= 8\n}\n```\n\n**Do:**\n```go\nconst minPasswordLength = 8\n\nfunc IsStrongPassword(password string) bool {\n\treturn len(password) \u003e= minPasswordLength\n}\n```\n\n## Error handling and error types\n**Don't:**\n```go\nfunc readFile(filename string) ([]byte, error) {\n\tdata, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn data, nil\n}\n```\n\n**Do:**\n```go\nfunc readFile(filename string) ([]byte, error) {\n\tdata, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading file %s: %v\", filename, err)\n\t}\n\treturn data, nil\n}\n```\nUsing `fmt.Errorf` provides a simple and readable way to add context to errors.\n\n## Package documentation \n**Don't:**\n```go\npackage main\n\nfunc main() {\n\t// No package or function documentation\n}\n```\n\n**Do:**\n```go\n// Package main provides the entry point for the application.\npackage main\n\n// main is the entry point for the application.\nfunc main() {\n\t// Start the application\n}\n```\nDocumenting packages and functions enhances code understanding and usability.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbahlo%2Fgo-styleguide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbahlo%2Fgo-styleguide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbahlo%2Fgo-styleguide/lists"}