That's just "don't create a non-static method if you don't use 'this'" in other languages with classes. Which is not a bad idea, but hardly matters. If someone realizes that it's difficult to add a unit test for the function, they'll fix it themselves. Maybe the real question is: did the code author create a unit test for the function?
(P.S. I never understood why Go uses words like "receiver" and "marshaling" that are rarely used elsewhere)
> Empty string check
Sure, but that's just ordinary code smell, likely due to someone not thinking carefully over the code, which could be easily identified in a code review. If it's never found, it barely matters anyway. Is it really worth bringing this up?
Everything else seems unnecessarily boring, like the number of spaces between sentences. Most people I know write comments like how they write regular English sentences, like in emails. Other than a professor who is near retirement age, I don't know anyone who uses double spaces. It's so rare I don't see any point in mentioning it. And if someone did do this in the code, whether it's their style or by accident, I wouldn't even flag it in the code review. For what? Does anyone benefit from it? It's important to have consistency over fundamental things like tab vs space, but that quickly becomes meaningless bikeshedding.
My advice would be: write code using your common sense. Don't be obsessed with trivial things that don't matter. Use your time elsewhere -- push a new feature, fix a bug, add a unit test, or just relax.
tczMUFlmoNk 50 days ago [-]
> > Avoid unused method receiver names
> That's just "don't create a non-static method if you don't use 'this'" in other languages with classes.
I don't think that's what's meant. It means to write `func (Receiver) Method()` rather than `func (r Receiver) Method()` when you don't use `r`. Sometimes you need this to implement an interface like `error` or `Stringer` and you just don't need instance data.
(I'm no Go apologist but I think "receiver" is a great term. It's clear, it's applies to other languages and paradigms, and it doesn't really have an alternative that I'm aware of.)
That makes sense. I just about figured it would. :-)
adastra22 50 days ago [-]
> P.S. I never understood why Go uses words like "receiver" and "marshaling" that are rarely used elsewhere
What else are you familiar with? Those are extremely common terms in the object oriented community.
MooseBurger 50 days ago [-]
Method? Serialize?
atombender 50 days ago [-]
A receiver isn't a method. It's the "self" instance the method is invoked on. It's standard OOP terminology.
I'm with you regarding marshaling, but not because it's not an industry-standard term, it's just that Go misapplies it. Marshaling historically has referred to describing a remote procedure call and its return value; for example, you call "CreateFoo()" with a "CreateRequest", the latter must be marshaled into a payload that the remote call can read. For a network call this requires serializing the data to bytes using some kind of format, but for a local call it could just be a pointer to a data structure. However, historically people have often mixed the two terms. Python's standard library also misuses "marshal" to refer to serialization.
adastra22 50 days ago [-]
The history on marshaling goes back further than that. Smalltalk used the word more or less how it’s used in Go. There is definitely an RPC connotation these days though, probably because small talk was based on message passing.
mkl95 50 days ago [-]
> (P.S. I never understood why Go uses words like "receiver" and "marshaling" that are rarely used elsewhere)
Not sure about receiver, but marshaling has been part of Python's lingo for ages.
cratermoon 50 days ago [-]
The term 'receiver' has a long and distinguished history.
Alan Kay used it, Smalltalk used the word almost exclusively.
If Zoomers don't know their computer science history that's on them.
zaphirplane 49 days ago [-]
> Alan Kay used it, Smalltalk used
So Alan and the language he helped create. That’s double counting the sample of 1
layer8 50 days ago [-]
“Marshaling” became pretty ubiquitous as a term in the 1990s with CORBA and Microsoft OLE/COM.
38 50 days ago [-]
> That's just "don't create a non-static method if you don't use 'this'" in other languages with classes
Go doesn't have static methods. Regardless if you name the receiver, you have to provide an instance of the type to all methods. Maybe you should check your own knowledge before criticizing others
dbattaglia 50 days ago [-]
They said “in other languages with classes”. They are comparing to a common code review but/gripe in other languages besides Go.
hnlmorg 50 days ago [-]
I’ve worked with people who raised comments like these in PRs and they were a nightmare: always arguing, never listening to anyone but themselves, and generally full of ego. Good developers but often slow to deliver too.
If you’re focused on what character of “GitHub” or “oauth” should capitalised in a variable name, then you really are focusing on the wrong problems of software development.
B-Con 50 days ago [-]
There is value in having local consistency, which is usually achieved through having rules.
The more uniform a code base, the easier it is to breeze around and get stuff done. Naming things is already hard, so having rules around the annoying bits is nice.
theshrike79 50 days ago [-]
Rules are best handled by automated tools with as few configuration options as possible - like gofmt or black.
This way people won't start bikeshedding about the placement of curly braces, they either accept the style or move on.
It also prevents things from getting political or personified. It's the tool that's making the decisions, not a specific person.
__s 49 days ago [-]
This is why I push for gofumpt over gofmt
hnlmorg 50 days ago [-]
These rules aren’t really about naming things, which I agree is hard. It’s pedantry around terms that really don’t matter which way you choose and thus are categorically not “best practices” let alone “idioms” one must abide by.
If the author really cares this much then they should be linter rules instead of a blog post.
donatj 50 days ago [-]
I don't know, code that isn't at least internally consistent with itself in capitalization is a pet peeve. There should be one way to do a thing.
hnlmorg 50 days ago [-]
When is agree when talking about all caps terms like HTTP or even just camel case verses snake case. But it’s really scraping the barrel of usefulness when you’re debating whether the H in Github or A in OAuth is capitalised.
Just write a linter rule and be done already.
mikedelago 50 days ago [-]
Github has a neat extension to its' markdown syntax where if you comment with a block for a specific line or lines, it will render to have a "commit suggestion" button.
```suggestion
my_change
```
if there's someone on your team prone to style nitpicks like this, this can often sate them, and it's convenient for you to merge into your branch
theshrike79 50 days ago [-]
A project should have an .editorconfig setup that automatically hints or enforces the correct code style in the IDE.
mjburgess 50 days ago [-]
> When reviewing Go code
This article reads as a parody of the worst sort of code review. This seems to be a person who sees themselves as little more than a regex engine.
Were I writing a go codebase in the UK, all spellings would be UK -- because of how absurd it would be to retrain the staff to split their brain on a trivial issue of this kind.
Likewise plurals do not matter, -- double spacing in comment sentences? I cannot imagine comment whitespacing being on the radar of any person one would wish to have as a team mate.
jrockway 50 days ago [-]
Being consistent is the key. When you open up a codebase worked on by 50 people, it's nice when you can't tell who wrote it because of the spelling or whatever. Everyone on the team can see it, think "this looks like I wrote it", and work on it accordingly. That's a good thing.
Joker_vD 50 days ago [-]
> Were I writing a go codebase in the UK, all spellings would be UK.
What about if you were in Australia? Germany? Poland? Bulgaria? China?
> how absurd it would be to retrain the staff to split their brain on a trivial issue of this kind.
I've seen this argument used to argue that all the spellings in source code should be US English, always and everywhere. In my opinion, this (being able to use the same argument to argue both for and against the same issue) invalidates the argument entirely.
mjburgess 49 days ago [-]
So, just to be clear, you think the right level of abstraction that codebase rules should operate at is, "the codebase should be accessible to programmers in every country across the world without modification" even when no such programmers operate on the codebase or are likely to ?
Do you apply this rule uniformly, or just to spellings?
The level of time-wasting here is off the charts. Write code to solve problems. If you have an international team, have international standards, if you do not -- it does not matter.
If any of this changes, literally, apply a regex. OP is a blog article about rules for a code review -- as if the relevant part of the review is spelling ? Are we mad?
Code review isnt to enforce these superficial standards -- these are regexes/flags in a build process. Code review is to ensure the code solves the problem under functional/non-functional constraints, in a manner which is easy to understand, communicates intention, etc.
Anyone talking about whether something is pluralised in a code review is a person who should be no where near any such process. They are clearly pathologically incapable of prioritisation or completely uninterested in review.
Mogzol 50 days ago [-]
The link in the "Error variable naming" section seems to directly contradict what the section says.
Error values should be of the form ErrFoo:
var ErrFormat = errors.New("image: unknown format")
But the page says:
// But if you want to give it a longer name, use "somethingError".
var specificError error
result, specificError = doSpecificThing()
And also says:
Don't do this:
[...]
var errSpecific error
result, errSpecific = doSpecificThing()
So should error variables written like `errSpecific` or `specificError`? The go wiki says they should be written starting with `err`: https://go.dev/wiki/Errors#naming
DHowett 50 days ago [-]
The advice in the 2014 talk applies to exporting specific types of errors as part of a package’s public API surface.
The article, on the other hand, advocates for local variables storing errors not to have distinct names.
Mogzol 50 days ago [-]
So a public variable error should follow different naming conventions then a local variable? That doesn't seem right, the go wiki says you should use the 'err' prefix for both (capitalized for public variables though, obviously)
And I'm only asking about when you are giving an error a distinct name, not just naming it 'err'.
danw1979 50 days ago [-]
Pedantic Go more like…
“oAuth is not pretty” but “oauth” is ?
We’ve all had PRs reviewed by people like this and we know where it leads.
50 days ago [-]
dlahoda 50 days ago [-]
where it leads?
stevebmark 50 days ago [-]
Idiomatic Go is using shortened variable names, not what's in this article. I thought that was common knowledge and part of the Go ethos? I also wouldn't consider grammar in comments part of the language idioms? This is an unusual and very light take on Golang language idioms.
prisenco 50 days ago [-]
My understanding is that shortened variable names are recommended for small, tight contexts (loops, short functions) but not generally.
cube2222 50 days ago [-]
That and conventionally standard names, like r for request/reader, w for writer, etc.
Agreed. Functions shouldn’t be full of short non-descriptly named variables.
The longer the lifetime/scope of a variable, and the more variables there are, the more descriptive the names should be.
GauntletWizard 50 days ago [-]
These are dang short compared to Java's FooBarBazBeanFactoryFuncClassImpl. The point you may be responding to is that "Short variable names" are themselves contextual. If you're doing a simple loop:
for i := range personlist {
person := personlist[i]
...
}
Is more readable than
for personNum := range personlist {
person := personlist[personNum]
...
}
because it makes clear that the i is basically irrelevant. The latter isn't bad style if you're three loops deep, because i, j, k is a bit harder to keep track of which is which.
callc 50 days ago [-]
I used Golang in a medium and large project. To anyone learning or thinking about learning Go, try it and ignore the online opinions.
I say this as someone who is simultaneously impressed by some parts of it, and gobsmacked at other parts.
Just ignore the dogmatic Gopher priests.
dlahoda 50 days ago [-]
why ignorance is good?
euroderf 50 days ago [-]
Go is straightforward enough that fairly quickly you'll figure out how your own working style and coding style meld with it.
crackrook 50 days ago [-]
I'm not angry about it but the fact that Go uses capitalization for access control is just so silly to me. Like something a child might design when figuring out how to hide secrets in a note.
euroderf 50 days ago [-]
Strong disagree. Using capitalization for access control is ridiculously obvious and simple and clear. Sure, things like "Printf" look odd for a little while.
crackrook 49 days ago [-]
What is it that you strongly disagree with? That it's silly? I never said it was wrong or harmful, once you know what the rule is I agree that it makes access control obvious - it's just a bit atypical for the capitalization of symbol names to be syntactically significant, no?
I'm not aware of any other language that does this. It's common for other languages to use underscores to indicate that something should be private, but I can't think of another example that uses either capitalization for access control or that embeds syntactic meaning in variable names. To me that makes Go unusual, and for a language that cares greatly about being accessible, unusual choices like this seem silly - not bad or foolish, necessarily - just silly.
I think most people have to be told about the capitalization rule (by the compiler, docs, etc.) because the rule itself isn't that obvious to someone coming from another language, that was my experience at least, and in that sense it feels a bit like a secret handshake to me.
euroderf 49 days ago [-]
> To me that makes Go unusual, and for a language that cares greatly about being accessible, unusual choices like this seem silly
I might agree with you if the UC/LC innovation were burdensome to "implement" (i.e. to remember). But, well, it's about as burdensome as understanding that on Unix, a filename that starts with a dot is normally hidden. In other words: instantly grokable and memorable.
crackrook 48 days ago [-]
I don't mean to nitpick but I'm not arguing that it's burdensome or difficult to remember. I meant it when I said:
> once you know what the rule is I agree that it makes access control obvious
The rule is memorable and grokable, I agree with you! I don't use "silly" to characterize it as the wrong choice, I strictly mean it's a quizzical choice.
Using your hidden file analogy in Unix: if I were to invent a new file system and I decided to use lower case letters to represent hidden files instead of borrowing the "." convention, wouldn't that strike you as a silly choice given the ubiquity of Unix-like filesystems?
euroderf 48 days ago [-]
Unix has a hegemony that Go doesn't. Go can be a playground for the New Jersey Way.
But sure, I'll sign on to "quizzical". Mainly I'm glad that in Go there's only two levels of visibility, not 3+. Much easier to reason about. Altho I'll admit to being confused when you mix the two levels in the names of a struct and its fields.
PhasmaFelis 50 days ago [-]
I am obsessively pedantic about grammar and spelling, in code and in English. I have a firm personal preference about how to spell "cancelled"--I like two Ls.
The only reason I'd ever consider telling someone that "canceled" is wrong is if the other spelling was firmly established in the actual codebase. Not in comments. And absolutely not with the ridiculous claim that the language you're coding in has opinions about how to spell your comments.
TechDebtDevin 50 days ago [-]
In case no one has mentioned it, Learning Go, an Idiomatic approach to real world programming, by Jon Bodner is my favorite Go related book and one of my favorite programming books in general.
I love go and everything but this reads more like pedantic go, not idiomatic go.
mjr00 50 days ago [-]
Yeah. And if you do care about this stuff, you shouldn't be reviewing it anyway; you should be setting up linter rules to enforce it automatically.
rs186 50 days ago [-]
Exactly. Unless these are rules that are enforced during build, they are just "someone's opinions", regardless of how "correct" they are.
gnabgib 50 days ago [-]
(2016) Based on the comment/voting entries, first submitted here in 2018.. I wonder if the author feels the same 9 years later.
liampulles 50 days ago [-]
Here's the idiomatic Go style guide: accept whatever go format outputs. The fact that go formats code by default is one of the best things about the language. The whole point is that spending time either correcting whitespace (or even worse, arguing about how much whitespace to put) is an absolute waste of time and a comradery killer.
50 days ago [-]
koakuma-chan 50 days ago [-]
It's the same language that "marshals" and "unmarshals" JSON and "dials" sockets.
tptacek 50 days ago [-]
Dial is a Plan9-ism and it's hard to argue that it isn't a lot better than the BSD sockets interface.
nickvec 50 days ago [-]
> Use singular form for collection repo/folder name
I’m confused by the examples in this section. Are they not identical?
pansa2 50 days ago [-]
`player` vs `players` etc.
_jab 50 days ago [-]
[flagged]
tptacek 50 days ago [-]
This article isn't about whether you like or don't like Go, which has been around for 15 years and whose merits have been debated, like those of literally every programming language, forever. We need to be careful about threads like these, because language war arguments spread like kudzu. Let's just try to talk about what this article is actually talking about.
If you want to see an article about the shortcomings of some language discussed, write one.
LudwigNagasena 50 days ago [-]
But those are far better topics for a discussion about idiomatic Go. I would rather see how to deal with lack of custom default values or error handling rather than how many spaces one should place after a punctuation mark.
tptacek 50 days ago [-]
We can't be talking about code that is or isn't idiomatic Go if we're arguing about features people are unhappy Go doesn't have.
LudwigNagasena 50 days ago [-]
That seems to be the exact context where we should be talking about idiomatic Go. You expect feature X and you are unhappy that Go doesn't have it because it's now harder to do Y. So here is an idiomatic Go way to do Y. Or that's why you should do Z in Go instead.
silisili 50 days ago [-]
> I hate that forgetting to initialize all fields of a struct does not lead to an error, but will just fill in "zero-values" for those fields. This has bitten me many times, and zero-values are almost never the behavior I want.
There's a linter for this you can easily integrate into your build or CI. Personally, having worked at a place with that as a CI rule, I'm the opposite. I felt annoyed having to explicitly set things I purposely didn't set. So I think it living as an optional linter is probably the right place.
> I've found Golang's generics to be confusing and unexpressive.
Same. Also with iterators.
B-Con 50 days ago [-]
> I hate that forgetting to initialize all fields of a struct does not lead to an error, but will just fill in "zero-values" for those fields. This has bitten me many times, and zero-values are almost never the behavior I want.
If empty values are biting you, you need constructors.
There's definitely multiple ways to go about struct initialization, and Go had firmly chosen one approach. Best practice is to make the zero value of a field "useful", and to write a constructor function if you need it populated with any sort of conditional values.
catlifeonmars 50 days ago [-]
Contrary to (probably) popular opinion, I find the concurrency model to be relatively poor. You get some cute primitives, but they come with a bunch of footguns. It’s really easy to spawn a green thread with `go <expr>`, which means it is easy to introduce deadlocks or race conditions.
On the other hand, I find the syntax to be relatively simple and non-concurrent code to be straightforward and unsurprising.
levkk 50 days ago [-]
For a programming language that makes unused variables a compiler error, I'm surprised there is no clippy/rubocop/black/cargo fmt/clang fmt built-in.
Mawr 50 days ago [-]
As far as I can tell every single one of those tools was inspired by Go's `gofmt` & `go vet` in the first place.
> Avoid unused method receiver names
That's just "don't create a non-static method if you don't use 'this'" in other languages with classes. Which is not a bad idea, but hardly matters. If someone realizes that it's difficult to add a unit test for the function, they'll fix it themselves. Maybe the real question is: did the code author create a unit test for the function?
(P.S. I never understood why Go uses words like "receiver" and "marshaling" that are rarely used elsewhere)
> Empty string check
Sure, but that's just ordinary code smell, likely due to someone not thinking carefully over the code, which could be easily identified in a code review. If it's never found, it barely matters anyway. Is it really worth bringing this up?
Everything else seems unnecessarily boring, like the number of spaces between sentences. Most people I know write comments like how they write regular English sentences, like in emails. Other than a professor who is near retirement age, I don't know anyone who uses double spaces. It's so rare I don't see any point in mentioning it. And if someone did do this in the code, whether it's their style or by accident, I wouldn't even flag it in the code review. For what? Does anyone benefit from it? It's important to have consistency over fundamental things like tab vs space, but that quickly becomes meaningless bikeshedding.
My advice would be: write code using your common sense. Don't be obsessed with trivial things that don't matter. Use your time elsewhere -- push a new feature, fix a bug, add a unit test, or just relax.
> That's just "don't create a non-static method if you don't use 'this'" in other languages with classes.
I don't think that's what's meant. It means to write `func (Receiver) Method()` rather than `func (r Receiver) Method()` when you don't use `r`. Sometimes you need this to implement an interface like `error` or `Stringer` and you just don't need instance data.
(I'm no Go apologist but I think "receiver" is a great term. It's clear, it's applies to other languages and paradigms, and it doesn't really have an alternative that I'm aware of.)
What else are you familiar with? Those are extremely common terms in the object oriented community.
I'm with you regarding marshaling, but not because it's not an industry-standard term, it's just that Go misapplies it. Marshaling historically has referred to describing a remote procedure call and its return value; for example, you call "CreateFoo()" with a "CreateRequest", the latter must be marshaled into a payload that the remote call can read. For a network call this requires serializing the data to bytes using some kind of format, but for a local call it could just be a pointer to a data structure. However, historically people have often mixed the two terms. Python's standard library also misuses "marshal" to refer to serialization.
Not sure about receiver, but marshaling has been part of Python's lingo for ages.
So Alan and the language he helped create. That’s double counting the sample of 1
Go doesn't have static methods. Regardless if you name the receiver, you have to provide an instance of the type to all methods. Maybe you should check your own knowledge before criticizing others
If you’re focused on what character of “GitHub” or “oauth” should capitalised in a variable name, then you really are focusing on the wrong problems of software development.
The more uniform a code base, the easier it is to breeze around and get stuff done. Naming things is already hard, so having rules around the annoying bits is nice.
This way people won't start bikeshedding about the placement of curly braces, they either accept the style or move on.
It also prevents things from getting political or personified. It's the tool that's making the decisions, not a specific person.
If the author really cares this much then they should be linter rules instead of a blog post.
Just write a linter rule and be done already.
```suggestion
my_change
```
if there's someone on your team prone to style nitpicks like this, this can often sate them, and it's convenient for you to merge into your branch
This article reads as a parody of the worst sort of code review. This seems to be a person who sees themselves as little more than a regex engine.
Were I writing a go codebase in the UK, all spellings would be UK -- because of how absurd it would be to retrain the staff to split their brain on a trivial issue of this kind.
Likewise plurals do not matter, -- double spacing in comment sentences? I cannot imagine comment whitespacing being on the radar of any person one would wish to have as a team mate.
What about if you were in Australia? Germany? Poland? Bulgaria? China?
> how absurd it would be to retrain the staff to split their brain on a trivial issue of this kind.
I've seen this argument used to argue that all the spellings in source code should be US English, always and everywhere. In my opinion, this (being able to use the same argument to argue both for and against the same issue) invalidates the argument entirely.
Do you apply this rule uniformly, or just to spellings?
The level of time-wasting here is off the charts. Write code to solve problems. If you have an international team, have international standards, if you do not -- it does not matter.
If any of this changes, literally, apply a regex. OP is a blog article about rules for a code review -- as if the relevant part of the review is spelling ? Are we mad?
Code review isnt to enforce these superficial standards -- these are regexes/flags in a build process. Code review is to ensure the code solves the problem under functional/non-functional constraints, in a manner which is easy to understand, communicates intention, etc.
Anyone talking about whether something is pluralised in a code review is a person who should be no where near any such process. They are clearly pathologically incapable of prioritisation or completely uninterested in review.
The link (https://go.dev/talks/2014/names.slide#14) says:
But the page says: And also says: So should error variables written like `errSpecific` or `specificError`? The go wiki says they should be written starting with `err`: https://go.dev/wiki/Errors#namingThe article, on the other hand, advocates for local variables storing errors not to have distinct names.
And I'm only asking about when you are giving an error a distinct name, not just naming it 'err'.
“oAuth is not pretty” but “oauth” is ?
We’ve all had PRs reviewed by people like this and we know where it leads.
Agreed. Functions shouldn’t be full of short non-descriptly named variables.
The longer the lifetime/scope of a variable, and the more variables there are, the more descriptive the names should be.
I say this as someone who is simultaneously impressed by some parts of it, and gobsmacked at other parts.
Just ignore the dogmatic Gopher priests.
I'm not aware of any other language that does this. It's common for other languages to use underscores to indicate that something should be private, but I can't think of another example that uses either capitalization for access control or that embeds syntactic meaning in variable names. To me that makes Go unusual, and for a language that cares greatly about being accessible, unusual choices like this seem silly - not bad or foolish, necessarily - just silly.
I think most people have to be told about the capitalization rule (by the compiler, docs, etc.) because the rule itself isn't that obvious to someone coming from another language, that was my experience at least, and in that sense it feels a bit like a secret handshake to me.
I might agree with you if the UC/LC innovation were burdensome to "implement" (i.e. to remember). But, well, it's about as burdensome as understanding that on Unix, a filename that starts with a dot is normally hidden. In other words: instantly grokable and memorable.
> once you know what the rule is I agree that it makes access control obvious
The rule is memorable and grokable, I agree with you! I don't use "silly" to characterize it as the wrong choice, I strictly mean it's a quizzical choice.
Using your hidden file analogy in Unix: if I were to invent a new file system and I decided to use lower case letters to represent hidden files instead of borrowing the "." convention, wouldn't that strike you as a silly choice given the ubiquity of Unix-like filesystems?
But sure, I'll sign on to "quizzical". Mainly I'm glad that in Go there's only two levels of visibility, not 3+. Much easier to reason about. Altho I'll admit to being confused when you mix the two levels in the names of a struct and its fields.
The only reason I'd ever consider telling someone that "canceled" is wrong is if the other spelling was firmly established in the actual codebase. Not in comments. And absolutely not with the ridiculous claim that the language you're coding in has opinions about how to spell your comments.
https://books.google.com/books/about/Learning_Go.html?id=vjA...
I’m confused by the examples in this section. Are they not identical?
If you want to see an article about the shortcomings of some language discussed, write one.
There's a linter for this you can easily integrate into your build or CI. Personally, having worked at a place with that as a CI rule, I'm the opposite. I felt annoyed having to explicitly set things I purposely didn't set. So I think it living as an optional linter is probably the right place.
> I've found Golang's generics to be confusing and unexpressive.
Same. Also with iterators.
If empty values are biting you, you need constructors.
There's definitely multiple ways to go about struct initialization, and Go had firmly chosen one approach. Best practice is to make the zero value of a field "useful", and to write a constructor function if you need it populated with any sort of conditional values.
On the other hand, I find the syntax to be relatively simple and non-concurrent code to be straightforward and unsurprising.
https://go.dev/blog/gofmt