-
-
Notifications
You must be signed in to change notification settings - Fork 41
Add style guide for Go #373
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
Conversation
|
Deploy preview for keen-clarke-470db9 ready! Built with commit 26b897c |
|
This is awesome! Thanks for adding it - already learned from it. |
yorinasub17
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM! I had a few nits about the organization of the guides but other than that looks great!
_includes/search.html
Outdated
| <div class="filter" id="gcp"><span class="helper"></span><img src="/assets/img/logos-technologies/gcp-logo.png" alt="aws logo"></div> | ||
| <div class="filter"id="azure"><span class="helper"></span><img src="/assets/img/logos-technologies/azure-logo.png" alt="aws logo"></div> | ||
| <div class="filter" id="azure"><span class="helper"></span><img src="/assets/img/logos-technologies/azure-logo.png" alt="aws logo"></div> | ||
| <div class="filter" id="styleguides"><span class="helper"></span><img src="/assets/img/logos-technologies/style-guides-logo.png" alt="style guides logo"></div> |
There was a problem hiding this comment.
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 fits in this filter, given that it has nothing to do with the cloud. I think what we actually want is the guide to be marked as all clouds, similar to https://github.com/gruntwork-io/gruntwork-io.github.io/blob/master/_posts/2019-08-26-how-to-use-gruntwork-infrastructure-as-code-library.adoc
| image: /assets/img/guides/go-logo-blue.png | ||
| excerpt: The style guide for the Go programming language that is used by all Gruntwork-owned code repositories that contain Go code. | ||
| tags: ["go", "golang", "code", "style"] | ||
| cloud: ["styleguides"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, I think we should actually mark this as all clouds to avoid overloading the cloud filter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
| === Testing | ||
| All files containing business logic must have a corresponding unit test file, and we aim to have 100% test coverage. | ||
|
|
||
| Unless there's a reason not to, tests should run in parallel. This is done by including a call to `t.Parallel` in the test function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zackproser
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
_includes/search.html
Outdated
| <div class="filter" id="gcp"><span class="helper"></span><img src="/assets/img/logos-technologies/gcp-logo.png" alt="aws logo"></div> | ||
| <div class="filter"id="azure"><span class="helper"></span><img src="/assets/img/logos-technologies/azure-logo.png" alt="aws logo"></div> | ||
| <div class="filter" id="azure"><span class="helper"></span><img src="/assets/img/logos-technologies/azure-logo.png" alt="aws logo"></div> | ||
| <div class="filter" id="styleguides"><span class="helper"></span><img src="/assets/img/logos-technologies/style-guides-logo.png" alt="style guides logo"></div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: My one piece of feedback here is that even though I was looking for your guide I had a hard time finding it - the </> logo just didn't jump out at me for some reason - and it was harder to parse than its sibling icons which all include text.
Perhaps we should consider creating an icon that says "style guides" or is somehow otherwise more clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally agree wrt icon, however this issue is moot as I'll move the style guide under all clouds, as described here.
|
|
||
| === Repo-specific conventions | ||
| ==== terratest | ||
| Note the existence of methods in terratest which are suffixed with the letter `E`, e.g. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yorinasub17 is there anywhere else we're currently using this pattern that we could include here? I feel like I've seen it elsewhere, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, but we should add as we find them.
| === Testing | ||
| All files containing business logic must have a corresponding unit test file, and we aim to have 100% test coverage. | ||
|
|
||
| Unless there's a reason not to, tests should run in parallel. This is done by including a call to `t.Parallel` in the test function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Unless there's a reason not to, tests should run in parallel. This is done by including a call to `t.Parallel` in the test function. | |
| Unless there's a reason not to, tests should run in parallel. This is done by including a call to `t.Parallel()` in the test function. |
Should we add parenthesis to reinforce its a function call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine, since we're talking about a function and referring to it by its name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting this together Ana!
A few more items to add:
- Default to functional programming practices. That is:
- Immutability. Prefer returning a new value rather than mutating an existing one.
- Pure functions. Prefer functions that take all their inputs as function parameters, instead of reading those inputs via side effects (e.g., reading from disk or the network or global vars), and who's entire behavior is to return values (note: errors are values too!), rather than performing side effects (e.g., by writing to disk or the network or global vars). Of course, you can't avoid side effects forever if you want your code to do something useful, but try to do as much of your logic with pure functions as you can, try to pass everything around as explicit parameters and return everything as explicit values, and centralize the side effecting code to a few isolated places.
- Composition. Build your code out of small, named functions, that you compose together.
- Examples. Might be worth adding a few examples of the above.
- Error handling.
- Don't panic (hat tip, Douglas Adams). Any method that can have an error should return that error as its final value. This should be passed up through each layer, which can decide what to do with it, all the way up to the very entrypoint of the app (or
main) if necessary. You should almost NEVER usepanic. - Use custom error types. Create your own types that implement the
errorinterface so that error messages are clear and have well-defined types you can check against. - Include stack traces. In most of our code, we have to wrap errors with
errors.WithStackTrace(e)to add the stack trace. Go annoyingly doesn't do this by default, but without it, sorting out an error can be very tricky.
- Don't panic (hat tip, Douglas Adams). Any method that can have an error should return that error as its final value. This should be passed up through each layer, which can decide what to do with it, all the way up to the very entrypoint of the app (or
- Comments. We may want to standardize on a comment style. E.g., Every public function
foohas a//comment of the stylefoo <explanation>, whereexplanationsays whatfoodoes, and more importantly, why it does, what assumptions it makes, and other aspects not obvious from the function name.
| image: /assets/img/guides/go-logo-blue.png | ||
| excerpt: The style guide for the Go programming language that is used by all Gruntwork-owned code repositories that contain Go code. | ||
| tags: ["go", "golang", "code", "style"] | ||
| cloud: ["styleguides"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
| endif::[] | ||
|
|
||
| == Intro | ||
| This is the style guide for the Go programming language. It aims to help us ensure that the code we write is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| This is the style guide for the Go programming language. It aims to help us ensure that the code we write is | |
| This is Gruntwork's style guide for the Go programming language. It aims to help us ensure that the code we write is |
| We use the excellent https://golang.org/doc/effective_go.html[Effective Go] guide as the starting point for our style | ||
| guide. Unless explicitly mentioned otherwise, we default to following the conventions outlined in it. | ||
|
|
||
| Another helpful resource is the https://github.com/golang/go/wiki/CodeReviewComments[CodeReviewComments] section of the | ||
| Go GitHub wiki page. | ||
|
|
||
| Below you will find the list of conventions that differ from the above mentioned documents, either because they are | ||
| specific to Gruntwork, or because we consciously chose to go against what Effective Go and CodeReviewComments recommend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, these paragraphs are rendering without the proper vertical whitespace between them: https://deploy-preview-373--keen-clarke-470db9.netlify.app/guides/styleguides/golang-style-guide/#starting-point. @eak12913 @oredavids Could you take a look?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed this when doing the upgrade guide too. I didn't have time to figure out why this was happening, but I did manage to see that the CSS styles were only applying if you use the headings expected in the guides, Intro, Core concepts, Deployment walkthrough, etc. Just wanted to share this in case the info helps shorten the debug cycle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eak12913 I noticed this issue still remains:
Note the lack of vertical whitespace between paragraphs. Not urgent, but when you get a chance, could you take a look?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eak12913 -- test mention as requested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
PR to address the issue here: #379
|
|
||
| == Starting point | ||
| We use the excellent https://golang.org/doc/effective_go.html[Effective Go] guide as the starting point for our style | ||
| guide. Unless explicitly mentioned otherwise, we default to following the conventions outlined in it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| guide. Unless explicitly mentioned otherwise, we default to following the conventions outlined in it. | |
| guide. **Unless explicitly mentioned otherwise, we default to following the conventions outlined in Effective Go.** |
|
|
||
| == Additional conventions | ||
| === General | ||
| Before committing any Go code, run `go fmt` and `goimports`. We run these as part of the CI build, so this will prevent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, goimports is a superset of go fmt—it formats the code and imports—so I think running just one is enough. We currently only run go fmt in CI, but in the future, may "upgrade" to goimports.
| Prefer using the `errors` standard library package for handling single errors and `hashicorp/go-multierror` for | ||
| handling multiple errors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: an example would help here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: We want to avoid linking in hashicorp libraries as they use a flavor of copyleft license (albeit weak form) which we currently don't allow use of as a policy. Can't do anything about the usage we already have, but should probably avoid new usage until we resolve that issue.
Given that, we probably shouldn't include recommendations in the style guide that require linking in a hashicorp library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that's a good point that totally slipped my mind. Will amend.
| handling multiple errors. | ||
|
|
||
| === Pointer usage | ||
| Prefer using value type over pointers, unless necessary. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs a bit more context. That is, when are pointers necessary (e.g., when you need to be able to mutate a reference or to return nil as a default).
| Prefer using value type over pointers, unless necessary. | ||
|
|
||
| === Testing | ||
| All files containing business logic must have a corresponding unit test file, and we aim to have 100% test coverage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is true. Our goal isn't 100% test coverage; our goal is to have enough testing to give us confidence that our code works and allow us to update it quickly. That means balancing:
- The likelihood of bugs: some code is harder to get right than others, and merits correspondingly more tests.
- The cost of bugs: some bugs are much more costly than others—e.g., bugs in payment systems or security functionality—so it makes sense to invest more in testing there.
- The cost of tests: some types of tests are cheap & easy to write and maintain, whereas others are very costly and brittle.
In practice, with infra code, which has an exceptional number of side effects, 100% test coverage is rarely a practical goal to aim for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I'll reword.
| Unless there's a reason not to, tests should run in parallel. This is done by including a call to `t.Parallel` in the test function. | ||
|
|
||
| === Naming things | ||
| Prefer descriptive names over short ones. In particular, avoid one-letter variable names. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: mention that one-letter variable names are OK in a tiny handful of cases where that has become the idiom (e.g., i as the index in for-loops), but everywhere else, a more descriptive name helps with code understanding and maintenance, at very little cost, given auto-complete in most IDEs/editors.
| https://github.com/gruntwork-io/terratest/blob/master/modules/aws/account.go#L23[GetAccountIdE]. The suffix `E` | ||
| signifies that the method returns an error as the last return value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| https://github.com/gruntwork-io/terratest/blob/master/modules/aws/account.go#L23[GetAccountIdE]. The suffix `E` | |
| signifies that the method returns an error as the last return value. | |
| https://github.com/gruntwork-io/terratest/blob/master/modules/aws/account.go#L23[GetAccountIdE]. Methods that have the suffix `E` return an error as the last return value; methods without `E` mark the test as failed (e.g., via calling `t.Fail()`) instead of returning an error. |
8ddd58f
yorinasub17
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates LGTM! The one thing that I think we should tweak is the section on errors, where we reference a hashicorp library.
brikis98
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! @eak12913 and @oredavids we'd still appreciate your help on the paragraph spacing issue.
|
Thanks folks for the reviews! I'll hold off on merging until we get some input on the paragraph spacing and the category naming issues. |
|
This is fantastic! Nice work. The only feedback I have is to consider mentioning the gruntwork-cli repo which contains a bunch of packages for Go CLI programs, including errors, logging, shell helpers, etc. |
|
Ugh - I hate hate github notifications. I apologize to all for seeing this so late. Could I ask for a personal favor, if folks need my attention - could you mention me in our Slack channel. This PR has many messages and the specific call out to me got lost in my inbox :-( |
@brikis98 @infraredgirl --- 2 hours later I found the issue. The problem is with the code in TLDR; one part of the code is comparing a kebab cased identifier vs a non kebab cased identifier. Those are identical when there are no spaces, but when spaces are introduced - the comparison fails because you end up with I'm going to bed now but I'll push the fix tomorrow! |
|
Thanks Eugene, and no worries! GitHub notifications are far from perfect (and this was by no means urgent anyway)! |
…ories` which expects an array of strings. If you pass `Style Guides` as a value, then it will treat it like: `["Style", "Guides"]` In the UI we take just the first value out of this array and it will end up just displaying "Style". You either have to provide the value like I did or to do: `categories: ["Style Guides"]`
… that had spaces in it.
|
@brikis98 @infraredgirl I pushed my changes to fix the issue. Do you folks want to take a look and approve/merge away as necessary? |
|
Hey @eak12913 that looks much better, thanks for your help! The only problem I still see the link in the breadcrumbs is not rendering nor working properly: Any chance you could help with that also? 😄 |
…multi word categories.
I believe I've fixed this. Please take a look! |
|
The only bit of slight annoyance is that we're only capitalizing the first word...so it's: "Style guides" in the breadcrumb and not "Style Guides". I'm not sure if this is a problem. It's a little more annoying to fix this with Jekyll - but doable so if it's important I can go back in there and figure it out. Additionally it should also be possible to do this with CSS - but then that may change the capitalization of a title where we intentionally have "The first thing capitalized but nothing else" into --> "The First Thing Capitalized But Nothing Else" |
|
Looks perfect, many thanks @eak12913! (I can definitely live with "Style guides" vs "Style Guides".) @gruntwork-io/team-iac can one of you give the final seal of approval, please? |
brikis98
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
|
BTW, we'll probably want to cross-link to this from our internal Notion pages! And eventually, migrate our Terraform style guide here... |
Definitely - I'll take care of it. We should also link to this guide from our open source repos that are heavy on Go (terragrunt, terratest, cloud-nuke, any others?) - I'll do that too. |
Thanks! It's not urgent, so feel free to tackle it incrementally, when time permits.
Yup, good idea! |



This change adds a new category for Style guides and a style guide for Go under it.
Notes to reviewers: