> we use the identifier p to represent a value in the people slice — the range block is so small and tight that using a single letter name is clear enough.
No, it's not. When you see `p.Age`, you have to go back and find the body of the loop, see what it operates on and decipher what p stands for. When you see `person.Age`, you understand it. I've never understood what is gained by using `p` instead of spelling it out as `person`.
>you have to go back and find the body of the loop
If the loop is long enough that you don't naturally remember how it was introduced, that's the problem. In the given example, the use of `p.Age` is literally on the next line of code after ` for _, p := range people`.
> I've never understood what is gained by using `p` instead of spelling it out as `person`.
Wisdom I received from, IIRC, the Perl documentation decades ago: tightly-scoped names should be shorter and less attention-grabbing than more broadly-scoped ones, because you should really notice when you're using a global, and you don't want to suffer attention fatigue. (I'm sure the exact wording was quite different.)
Also because it's better for information density. As I recall, Larry Wall also had the idea that more commonly used language keywords should be shorter than rare ones. Good code uses the locals much more often than globals, so you shouldn't need to expend the same amount of effort on them. (The limiting case of this is functional programming idioms where you can eliminate the variable name completely, in cases like (Python examples) `lambda x: int(x)` -> `int`, or `(foo(x) for x in xs)` -> `map(foo, xs)`.
The problem is that many times I have not read the definition to remember. Debugger puts me into a context where I have to figure out what `p` stands for. I go up the call stack and now there's `s` to be deciphered. Worse is the reuse of `p` for person, product, part, etc. in different contexts.
Debugging is not the only problem. Code is read rarely linearly. Many times I browse different uses of a function, or see how a data structure is modified in different contexts. Looking up single letter variables is just a waste of time.
I've felt strongly for a while now that abbreviations should be "lossless" in order to be useful; it should be unambiguous now get back to the unabbreviated form. For whatever reason, people seem to love trying to optimize for character count with abbreviations that actually make things more confusing (like `res` in a context where it might mean either "response" or "result).
I just don't get the obsession with terseness when we have modern tooling. I don't type particularly fast, but autocomplete makes it pretty quick for me to type out even longer names, and any decent formatter will split up long lines automatically in a way that's usually sane (and in my experience, the times when it's annoying are usually due to something like a function with way too many arguments or people not wanting to put a subexpression in a separate variable because I guess they don't know that the compiler will just inline it) rather than the names being a few characters too many.
Meanwhile, pretty much everywhere I've worked has had at least some concerns about code reviews either already being or potentially becoming a burden on the team due to the amount of time and effort it takes to read through someone else's code. I feel like more emphasis on making code readable rather than just functional and quick to write would be a sensible thing to consider, but somehow it never seems to be part of the discussion.
> and any decent formatter will split up long lines
Any decent editor can wrap long lines on demand. But it's even better not to have to do either of those if not necessary.
> I've felt strongly for a while now that abbreviations should be "lossless" in order to be useful
This is how we got lpszClassName. The world moved away from hungarian notation and even away from defining types for variables in some contexts (auto in cpp, := in Go, var in Java). Often it just adds noise and makes it harder to understand the code at a glance, not easier.
This is something that it seems some Go people just don't "believe" in my experience, that for some people that letter in that context is not mentally populated immediately.
It's honestly a shame because it seems like Go is a good language but with such extremely opinionated style that is so unpleasant (not just single letters but other things stuff about tests aren't supposed to ever have helpers or test frameworks) feels aggressively bad enough to basically ruin the language for me.
Long lines make reading rhythm uncomfortable (long jumps, prolonged eye movements) and long words make the text too dense and slow down the reading. It’s bad typography.
I have heard an idea that a good variable should be understood by just reading its name, out of context. That would make “ProductIndex” superior to “i”, which doesn't add any clarity.
A good variable name is the one that is understood by reading it in context, which is why you don't have names like "current_person" or "CurrentIndexOfProductBeingUpdated".
Something like "AnIteratorObjectWithPersonPointer" would be a long word, "person" is absolutely not. If a 6 letter identifier causes you that much trouble with code being too verbose, then it's likely a screen resolution/density/font issue, not a naming issue.
> That would make “ProductIndex” superior to “i”, which doesn't add any clarity.
And then you introduce extra two levels of nested loops and suddenly "i", "j", and "k" don't make any sense on their own, but "ProductIndex", "BatchIndex" and "SeriesIndex" do.
I think this may be related to how people read code. You have people who scan shapes, and then you have people who read code almost like prose.
I scan shapes. For me, working with people who read code is painful because their code tends to to have less clear "shapes" (more noise) and reads like more like a verbal description.
For instance, one thing I've noticed is the preference for "else if" rather than switch structures. Because they reason in terms of words. And convoluted logic that almost makes sense when you read it out loud, but not when you glance at it.
This is also where I tend to see unnecessarily verbose code like
func isZero(a int) bool {
if a == 0 {
return true
} else {
retur false
}
}
strictly speaking not wrong, but many times slower to absorb. (I think most developers screech to a halt and their brain goes "is there something funny going on in the logic here that would necessitate this?")
I deliberately chose to learn "scanning shapes" as the main way to orient myself because my first mentor showed me how you could navigate code much faster that way. (I'd see him rapidly skip around in source files and got curious how he would read that fast. Turns out he didn't. He just knew what shape the code he was looking for would be).
I think this is clearly a matter of preference. Shorter variable (or rather, appropriately short variables for the context) for me are easier to recognize and disambiguate. They take up fewer tokens, so to speak. When I see `p.Age` I don't have to go back and look at the beginning of the loop because I just read that line and I remember it.
Furniture maker, house framer, finish carpenter are all under the category of woodworking, but these jobs are not the same. Years of honed skill in tool use makes working in the other categories possible, but quality and productivity will suffer.
Does working in JS, on the front end teach you how to code, it sure does. So does working in an embedded system. But these jobs might be further apart than any of the ones I highlighted in the previous category.
There are plenty of combinations of systems and languages where your rule about a screen just isn't going to apply. There are plenty of problems that make scenarios where "ugly loops" are a reality.
Tried to use the new slices package or comparables? It's a nightmare to debug, for no reason whatsoever. If they would've used interface names like Slice or Comparable or Stringable or something, it would have been so much easier.
The naming conventions are something that really fucks up my coding workflow, and it can be avoided 100% of the time if they would stop with those stupid variable names. I am not a machine, and there is no reason to make code intentionally unreadable.
I was surprised to see literally invalid names in the "bad" section, e.g. "Cannot start with a digit". Why even presenting this if it's rejected by the compiler?
I wondered if you could sneak in some unicode digit but it seems to reject those too:
$ go run z.go
# command-line-arguments
./z.go:6:2: identifier cannot begin with digit U+0661 '١'
./z.go:7:27: identifier cannot begin with digit U+0661 '١'
This is great!
My team started using Go last year so I fed this article to set off a fleet of agents on our Go codebase and generate a report out w/ code samples based on it. Ended up with a pretty good little document to present on Monday :)
People have been arguing this stuff since the dawn of (computer) time. I don't get it. I've been at it so long now, IDGAF what or how you name something. Short names in loops? Long? I don't care. I really don't. Just be consistent in what you decide and I can read it.
All this arguing... FFS, go DO something with your time!
EDIT: Oh, yeah, as for the article itself, it's a good article. But again, just be consistent in what you choose.
Another of mine: don't name a struct after an interface method that it's supposed to implement. If you have a package linearalgebra, then making a custom error type linearalgebra.LinearAlgebraError is too "chatty" but linearalgebra.Error will cause you pain if it implements "Error string()", as it probably should, and you decide to make a linearalgebra.MatrixSingularError that wraps a linearalgebra.Error to "inherit" its methods.
In the end, it ended up called linearalgebra.Err .
P.S Alex Edwards' "let's go" and "let's go further" are great books to get someone up to date with golang, just keep an eye on features that are newer than the book(s).
> Words that are acronyms or initialisms (like API, URL or HTTP) should use a consistent case within the identifier. So, for example, apiKey or APIKey are conventional, but ApiKey is not. This rule also applies to ID when it is used as shorthand for the words "identity" or "identifier" — so that means write userID rather than userId.
Outdated.
Over time, it's become clear that breaking the camelCase convention in this manner is inappropriate:
- The inconsistency with the convention is jarring, consider `APIURL` - is that a variable (ApiUrl) or a constant (APIURL)?
- The inconsistency introduces doubt on how to write any given identifier - which is why the above advice even needs to exist
- The whole point of the convention is to make separate parts of the name visually separate, consider `someAPIURLHTMLJSONExtension` vs `someApiUrlHtmlJsonExtension`
- It's hard to keep this consistent - we may reasonably disagree whether `ID` should be capitalized or not, meaning you may just as well find both `ID` and `id` across codebases. This erases the benefits of capitalization altogether.
The benefits of keeping these acronyms capitalized are dubious and don't outweigh the downsides.
And of course, the real solution is to use the one correct naming convention - `snake_case`. Then you can capitalize all you want without trouble - `some_API_URL_HTML_JSON_extension`.
> we use the identifier p to represent a value in the people slice — the range block is so small and tight that using a single letter name is clear enough.
No, it's not. When you see `p.Age`, you have to go back and find the body of the loop, see what it operates on and decipher what p stands for. When you see `person.Age`, you understand it. I've never understood what is gained by using `p` instead of spelling it out as `person`.
>you have to go back and find the body of the loop
If the loop is long enough that you don't naturally remember how it was introduced, that's the problem. In the given example, the use of `p.Age` is literally on the next line of code after ` for _, p := range people`.
> I've never understood what is gained by using `p` instead of spelling it out as `person`.
Wisdom I received from, IIRC, the Perl documentation decades ago: tightly-scoped names should be shorter and less attention-grabbing than more broadly-scoped ones, because you should really notice when you're using a global, and you don't want to suffer attention fatigue. (I'm sure the exact wording was quite different.)
Also because it's better for information density. As I recall, Larry Wall also had the idea that more commonly used language keywords should be shorter than rare ones. Good code uses the locals much more often than globals, so you shouldn't need to expend the same amount of effort on them. (The limiting case of this is functional programming idioms where you can eliminate the variable name completely, in cases like (Python examples) `lambda x: int(x)` -> `int`, or `(foo(x) for x in xs)` -> `map(foo, xs)`.
> remember how it was introduced
The problem is that many times I have not read the definition to remember. Debugger puts me into a context where I have to figure out what `p` stands for. I go up the call stack and now there's `s` to be deciphered. Worse is the reuse of `p` for person, product, part, etc. in different contexts.
Debugging is not the only problem. Code is read rarely linearly. Many times I browse different uses of a function, or see how a data structure is modified in different contexts. Looking up single letter variables is just a waste of time.
I've felt strongly for a while now that abbreviations should be "lossless" in order to be useful; it should be unambiguous now get back to the unabbreviated form. For whatever reason, people seem to love trying to optimize for character count with abbreviations that actually make things more confusing (like `res` in a context where it might mean either "response" or "result).
I just don't get the obsession with terseness when we have modern tooling. I don't type particularly fast, but autocomplete makes it pretty quick for me to type out even longer names, and any decent formatter will split up long lines automatically in a way that's usually sane (and in my experience, the times when it's annoying are usually due to something like a function with way too many arguments or people not wanting to put a subexpression in a separate variable because I guess they don't know that the compiler will just inline it) rather than the names being a few characters too many.
Meanwhile, pretty much everywhere I've worked has had at least some concerns about code reviews either already being or potentially becoming a burden on the team due to the amount of time and effort it takes to read through someone else's code. I feel like more emphasis on making code readable rather than just functional and quick to write would be a sensible thing to consider, but somehow it never seems to be part of the discussion.
> and any decent formatter will split up long lines
Any decent editor can wrap long lines on demand. But it's even better not to have to do either of those if not necessary.
> I've felt strongly for a while now that abbreviations should be "lossless" in order to be useful
This is how we got lpszClassName. The world moved away from hungarian notation and even away from defining types for variables in some contexts (auto in cpp, := in Go, var in Java). Often it just adds noise and makes it harder to understand the code at a glance, not easier.
This is something that it seems some Go people just don't "believe" in my experience, that for some people that letter in that context is not mentally populated immediately.
It's honestly a shame because it seems like Go is a good language but with such extremely opinionated style that is so unpleasant (not just single letters but other things stuff about tests aren't supposed to ever have helpers or test frameworks) feels aggressively bad enough to basically ruin the language for me.
Long lines make reading rhythm uncomfortable (long jumps, prolonged eye movements) and long words make the text too dense and slow down the reading. It’s bad typography.
I have heard an idea that a good variable should be understood by just reading its name, out of context. That would make “ProductIndex” superior to “i”, which doesn't add any clarity.
I would argue that ambiguity and uncertainty slow down reading, and more importantly comprehension, far more than a few additional characters.
1 reply →
A good variable name is the one that is understood by reading it in context, which is why you don't have names like "current_person" or "CurrentIndexOfProductBeingUpdated".
Something like "AnIteratorObjectWithPersonPointer" would be a long word, "person" is absolutely not. If a 6 letter identifier causes you that much trouble with code being too verbose, then it's likely a screen resolution/density/font issue, not a naming issue.
> That would make “ProductIndex” superior to “i”, which doesn't add any clarity.
And then you introduce extra two levels of nested loops and suddenly "i", "j", and "k" don't make any sense on their own, but "ProductIndex", "BatchIndex" and "SeriesIndex" do.
4 replies →
I think this may be related to how people read code. You have people who scan shapes, and then you have people who read code almost like prose.
I scan shapes. For me, working with people who read code is painful because their code tends to to have less clear "shapes" (more noise) and reads like more like a verbal description.
For instance, one thing I've noticed is the preference for "else if" rather than switch structures. Because they reason in terms of words. And convoluted logic that almost makes sense when you read it out loud, but not when you glance at it.
This is also where I tend to see unnecessarily verbose code like
func isZero(a int) bool { if a == 0 { return true } else { retur false } }
strictly speaking not wrong, but many times slower to absorb. (I think most developers screech to a halt and their brain goes "is there something funny going on in the logic here that would necessitate this?")
I deliberately chose to learn "scanning shapes" as the main way to orient myself because my first mentor showed me how you could navigate code much faster that way. (I'd see him rapidly skip around in source files and got curious how he would read that fast. Turns out he didn't. He just knew what shape the code he was looking for would be).
4 replies →
> That would make “ProductIndex” superior to “i”, which doesn't add any clarity.
Adds a ton of clarity, especially if you have a nested loop.
3 replies →
I think this is clearly a matter of preference. Shorter variable (or rather, appropriately short variables for the context) for me are easier to recognize and disambiguate. They take up fewer tokens, so to speak. When I see `p.Age` I don't have to go back and look at the beginning of the loop because I just read that line and I remember it.
If your loops are so long you can't fit them on one screenfull you have much more fundamental issues.
person.Age is easier to understand than p.Age regardless of the loop size.
You arent wrong, but it is not an absolute.
Furniture maker, house framer, finish carpenter are all under the category of woodworking, but these jobs are not the same. Years of honed skill in tool use makes working in the other categories possible, but quality and productivity will suffer.
Does working in JS, on the front end teach you how to code, it sure does. So does working in an embedded system. But these jobs might be further apart than any of the ones I highlighted in the previous category.
There are plenty of combinations of systems and languages where your rule about a screen just isn't going to apply. There are plenty of problems that make scenarios where "ugly loops" are a reality.
1 reply →
I agree with this comment so much.
Tried to use the new slices package or comparables? It's a nightmare to debug, for no reason whatsoever. If they would've used interface names like Slice or Comparable or Stringable or something, it would have been so much easier.
The naming conventions are something that really fucks up my coding workflow, and it can be avoided 100% of the time if they would stop with those stupid variable names. I am not a machine, and there is no reason to make code intentionally unreadable.
I was surprised to see literally invalid names in the "bad" section, e.g. "Cannot start with a digit". Why even presenting this if it's rejected by the compiler?
Author here. The answer is because I mentioned it as one of the bullet pointed hard-rules, and I wanted to include an example to illustrate it.
I wondered if you could sneak in some unicode digit but it seems to reject those too:
(I tried a few of them but not all.)
The example with the dash in it confused me as well.
"Chat, generate me a table of bad Golang making practices"
This is great! My team started using Go last year so I fed this article to set off a fleet of agents on our Go codebase and generate a report out w/ code samples based on it. Ended up with a pretty good little document to present on Monday :)
People have been arguing this stuff since the dawn of (computer) time. I don't get it. I've been at it so long now, IDGAF what or how you name something. Short names in loops? Long? I don't care. I really don't. Just be consistent in what you decide and I can read it.
All this arguing... FFS, go DO something with your time!
EDIT: Oh, yeah, as for the article itself, it's a good article. But again, just be consistent in what you choose.
Another of mine: don't name a struct after an interface method that it's supposed to implement. If you have a package linearalgebra, then making a custom error type linearalgebra.LinearAlgebraError is too "chatty" but linearalgebra.Error will cause you pain if it implements "Error string()", as it probably should, and you decide to make a linearalgebra.MatrixSingularError that wraps a linearalgebra.Error to "inherit" its methods.
In the end, it ended up called linearalgebra.Err .
P.S Alex Edwards' "let's go" and "let's go further" are great books to get someone up to date with golang, just keep an eye on features that are newer than the book(s).
The booms receive regular updates. I got an email about an update to Let’s Go Further on 3/12 for Go 1.26
I like this article — short, accurate (which is somehow not a given these days...) and useful, just like Go language itself.
> Words that are acronyms or initialisms (like API, URL or HTTP) should use a consistent case within the identifier. So, for example, apiKey or APIKey are conventional, but ApiKey is not. This rule also applies to ID when it is used as shorthand for the words "identity" or "identifier" — so that means write userID rather than userId.
Outdated.
Over time, it's become clear that breaking the camelCase convention in this manner is inappropriate:
- The inconsistency with the convention is jarring, consider `APIURL` - is that a variable (ApiUrl) or a constant (APIURL)?
- The inconsistency introduces doubt on how to write any given identifier - which is why the above advice even needs to exist
- The whole point of the convention is to make separate parts of the name visually separate, consider `someAPIURLHTMLJSONExtension` vs `someApiUrlHtmlJsonExtension`
- It's hard to keep this consistent - we may reasonably disagree whether `ID` should be capitalized or not, meaning you may just as well find both `ID` and `id` across codebases. This erases the benefits of capitalization altogether.
The benefits of keeping these acronyms capitalized are dubious and don't outweigh the downsides.
And of course, the real solution is to use the one correct naming convention - `snake_case`. Then you can capitalize all you want without trouble - `some_API_URL_HTML_JSON_extension`.
[dead]
[dead]
[flagged]
> this seems anachronistic, written for a human artisan laboring over each naming choice directly
Some of us want to write well thought-through code, rather than letting an AI just spew poorly thought-through unmaintainable shit.
You can use this article to guide your choice of rulesets. And you still have to exert some artisan labor to develop any taste.
Parochialism here is saying “just use AI” in disguise.
> passed to the ai model for the code it generates
AI can't generate code. It only copies it (badly) from somewhere else.
You're making yourself redundant if you don't keep your actual programming skills sharp.
[flagged]