_______               __                   _______
       |   |   |.---.-..----.|  |--..-----..----. |    |  |.-----..--.--.--..-----.
       |       ||  _  ||  __||    < |  -__||   _| |       ||  -__||  |  |  ||__ --|
       |___|___||___._||____||__|__||_____||__|   |__|____||_____||________||_____|
                                                             on Gopher (inofficial)
   URI Visit Hacker News on the Web
       
       
       COMMENT PAGE FOR:
   URI   Go Naming Conventions: A Practical Guide
       
       
        wpollock wrote 3 hours 21 min ago:
        Allowing Unicode characters, then stating best practice is to stick
        with ASCII, is weird.  (Go is not alone in this practice.)  Unicode
        identifiers have a host of issues, such as some characters have no case
        distinction, some have title-case but not uppercase, some "capitalize"
        the last letter in a word and not the first (Hebrew has five "final
        form" letters), etc.  Does Go specify the meaning (exported or not) if
        a letter has no case, or if an identifier starts with a zero-width
        joiner character?  Without a huge list of detailled rules, too much is
        left to the implementation to decide.  I prefer to stick with ASCII for
        names.
        
        Fun fact:  When printing with movable type began, printers would travel
        with large "type cases" containing the small wood or metal blocks with
        glyphs on them.  The ones the used frequently were kept in the lower
        half of the case, in easy reach. That's where the terms "lowercase" and
        "uppercase" come from.
       
          arcxi wrote 1 hour 12 min ago:
          it is weird, especially for Go with its semantic naming and famously
          opinionated compiler. it will gladly build code with a variable named
          𖤐界ᥱᥲΣ੭, but God forbid it's unused.
       
        syngrog66 wrote 4 hours 18 min ago:
        one rando set of opinions. stopped reading fast
       
        Mawr wrote 6 hours 5 min ago:
        > 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`.
       
        menno-dot-ai wrote 6 hours 49 min ago:
        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 :)
       
          graynk wrote 5 hours 8 min ago:
          Why do you need AI agents for this?
          
          You either catch and enforce it with a linter (e.g. [1] ) (in which
          case you don't need AI to tell you the current state, you just add
          the same config to all projects) or you don't enforce it (because
          everyone will forget unless it's automated)
          
   URI    [1]: https://golangci-lint.run/docs/linters/configuration/#revive
       
            voidfunc wrote 4 hours 52 min ago:
            Using a linter doesn't get you noticed by leadership and net you a
            promo.
       
              graynk wrote 4 hours 1 min ago:
              Sure it does, just say you "established org-wide coding standards
              and drove adoption of automated linting tooling, reducing review
              friction and enforcing style consistency at scale" in your
              assessment.
       
                ManuelKiessling wrote 2 hours 53 min ago:
                Better yet, post about it on LinkedIn and explain what it
                taught you about marriage proposals!
       
        HumblyTossed wrote 7 hours 32 min ago:
        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.
       
        laserlight wrote 11 hours 19 min ago:
        > 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`.
       
          giancarlostoro wrote 5 hours 14 min ago:
          This comes from some dated idea for stuff like C where "its okay to
          use shorthands for variables" but is it really? The only place I
          allow it is simple iterators, but now we have enhanced loops where
          even this is unnecessary. We don't need to save on pixel screen space
          like if its still the 90s. Even with a simple 1080p monitor you can
          fit plenty of words and code.
          
          Give your variables, functions, classes meaningful descriptive names
          that make sense to humans.
       
          hackthemack wrote 5 hours 40 min ago:
          But what if your codebase has to interact with leads, customers, and
          another 3rd party system called Metrica with leads, customers?
          
          When you write a loop, do you now name the variable
          
          OurPerson.Age
          MetricaPerson.Age
          
          ?
          
          What if, 3 years from now, you include another 3rd party vendor into
          the system and have to write code against that data and in the data
          they name their stuff OurPerson.Age?
          
          Not saying you are wrong at all. Just naming things is hard and
          context dependent. I think that is why it is endlessly argued.
       
          zahlman wrote 7 hours 30 min ago:
          >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)`.
       
            laserlight wrote 6 hours 17 min ago:
            > 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.
       
              gopher_space wrote 4 hours 50 min ago:
              > Debugger puts me into a context where I have to figure out what
              `p` stands for.
              
              `p` stands for "the process in question".
              
              I like to think of single-character vars as idea or topic headers
              that track the single thing I'm currently up to.  I'm rarely
              working with more than one at a time, frequently it's the only
              variable, and there are contexts where I wouldn't use them at
              all.
              
              IMHO if you're in a situation where `p` isn't obvious to you,
              "something has gone wrong".
       
          esrauch wrote 9 hours 21 min ago:
          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.
       
            gadflyinyoureye wrote 5 hours 43 min ago:
            I think the community is split on such things. I ended up telling
            the  side that gets persnickety about short names and only using if
            statements in tests to pound sand. I use things that make my life
            easier. I now care less about some rude rando on r/golang than I
            did five years ago.
       
          bborud wrote 9 hours 24 min ago:
          If your loops are so long you can't fit them on one screenfull you
          have much more fundamental issues.
       
            laserlight wrote 8 hours 36 min ago:
            person.Age is easier to understand than p.Age regardless of the
            loop size.
       
              mysterymath wrote 24 min ago:
              Another point of view: ideally it would just be "Age". But in
              languages that don't have the ability to "open" scopes, one might
              be satisfied p.Age, being "the age". I've also seen $.age and
              it.age, in languages with constructs that automatically break out
              "it" anaphora.
       
            zer00eyz wrote 8 hours 41 min ago:
            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.
       
              bborud wrote 8 hours 8 min ago:
              I didn't say it was an absolute.  But once a scope grows to the
              point where you have to navigate to absorb a function or a loop,
              both readability and complexity tends to worsen. As does your
              mental processing time.  Especially for people who "scan" code
              rapidly rather than reading it.
              
              The slower "readers" will probably not mind as much.
              
              This is why things like function size is usually part of coding
              standards at a company or on a project.  (Look at Google, Linux
              etc)
       
          jplona wrote 9 hours 28 min ago:
          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.
       
          cookiengineer wrote 10 hours 39 min ago:
          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.
       
          saghm wrote 10 hours 48 min ago:
          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.
       
            ickyforce wrote 10 hours 7 min ago:
            > 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.
       
              saghm wrote 2 hours 7 min ago:
              I'd argue there's a stark difference between abbreviating words
              and adding extra ones. `p` as a shorthand for `person` is silly
              to me, but that doesn't mean that `personObject` would also be
              silly to me. I fundamentally don't agree with the premise that
              it's possible to be too verbose means that terseness is its own
              goal; the goal should be clarity, and I don't think that lossy
              abbreviations actually help with that except when someone already
              knows what the code is doing, in which case they don't need to
              read it in the first place.
       
          piekvorst wrote 10 hours 49 min ago:
          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.
       
            jayd16 wrote 8 hours 33 min ago:
            >  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.
       
              Groxx wrote 8 hours 21 min ago:
              and god help you if those loops are pairing People and Products.
              
              though now that I write that out... it would be really nice if
              you could optionally type iteration vars so they couldn't be used
              on other collections / as plain integers.  I haven't seen any
              languages that do that though, aside from it being difficult to
              do by accident in proof-oriented languages.
       
                jayd16 wrote 7 hours 29 min ago:
                You usually don't need an index that can't be used elsewhere. 
                If you don't then you can abstract it away entirely and use an
                iterator or foreach features.
       
                  Groxx wrote 6 hours 46 min ago:
                  Depends on the language. Doing that is a huge pain in Go
                  (until fairly recently, and it's still quite abnormal or
                  closure-heavy), so the vast majority of code there does
                  manual index-pairing instead of e.g. a zip iterator when
                  going through two paired arrays.
       
            bborud wrote 8 hours 54 min ago:
            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).
       
              zer00eyz wrote 8 hours 12 min ago:
              > 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 think this is an astute observation.
              
              I think there is another category of "reading" that happens, is
              what you're reading for "interaction" or "isolation".
              
              Sure c.method is a scalable shape but if your system deals with
              Cats, Camels, Cars, and Crabs that same c.method when dealing
              with an abstract api call divorced from the underlying
              representation might not be as helpful.
              
              I would think that we would have more and better research on
              this, but the only paper I could find was this: [1] its a meta
              analysis of 57 other papers, a decent primer but nothing ground
              breaking here.
              
              > I scan shapes. ... verbal description.
              
              I would be curious if you frequently use a debugger? Because I
              tend to find the latter style much more useful (descriptive) in
              that context.
              
   URI        [1]: https://arxiv.org/pdf/2110.00785
       
                functional_dev wrote 7 hours 29 min ago:
                The shape argument works well in small packages but it starts
                to fail once you have multiple domain models starting with the
                same letter
       
                  bborud wrote 3 hours 38 min ago:
                  I wasn’t talking about just symbols but entire paragraphs
                  of code as well.
       
                bborud wrote 7 hours 40 min ago:
                dealing with an abstract api call divorced from the underlying
                representation
                
                I don't understand what you mean.  Could you give me an
                example?
                
                I would be curious if you frequently use a debugger?
                
                I practically never use a debugger.
       
              ConcurrentCrab wrote 8 hours 30 min ago:
              I think this is pretty insightful, and I might add this as
              another reason LLM code looks so revolting. It's basically
              writing prose in a different language, which make sense - it's a
              _language_ model, it has no structural comprehension to speak of.
              
              Whereas I write code (and expect good code to be written) such
              that most information is represented structurally: in types,
              truth tables, shape of interfaces and control flow, etc.
       
            diath wrote 9 hours 26 min ago:
            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.
       
              bborud wrote 8 hours 27 min ago:
              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.
              
              ijk for indices in loops are actually clearer than random names
              in nested loops precisely because it is a *very common
              convention* and because they occur in a defined order.    So you
              always know that "j" is the second nesting level, for instance. 
              Which relates to the visual layout of the code.
              
              You may not have known of this convention or you are unable to
              apply "the principle of least astonishment".  A set of random
              names for indices is less useful because it communicates less and
              takes longer to comprehend.
              
              Just like most humans do not read text one letter at a time, many
              programmers also do not read code as prose.  They scan it rapidly
              looking at shapes and familiar structures.  "ProductIndex",
              "BatchIndex" and "SeriesIndex" do not lend themselves to
              scanning, so you force people who need to understand the code to
              slow down to the speed of someone who reads code like they'd read
              prose.    That is a bit amateurish.
       
                zahlman wrote 7 hours 27 min ago:
                > ijk for indices in loops are actually clearer than random
                names in nested loops precisely because it is a very common
                convention and because they occur in a defined order. So you
                always know that "j" is the second nesting level, for instance.
                Which relates to the visual layout of the code.
                
                In problem domains that emphasize multidimensional arrays, yes.
                
                More often nowadays I would see `i` and think "an element of
                some sequence whose name starts with i". (I tend to use `k` and
                `v` to iterate keys and values of dictionaries, but spell
                `item` in full. I couldn't tell you why.)
       
                Groxx wrote 8 hours 17 min ago:
                I partly agree, and partly don't.  When ijk really is
                unambiguous and the order is common (say you're implementing a
                well-known algorithm) I totally agree, the convention aids
                understanding.
                
                But nesting order often doesn't control critical semantics.
                Personally, it has much more often implied a heuristic about
                the lengths or types (map, array, linked list) of the
                collections (i.e. mild tuning for performance but not
                critical), and it could be done in any order with different
                surrounding code.  There the letters are meaningless, or
                possibly worse because you can't expect that similar code
                elsewhere does things in the same nesting order.
                
                This likely depends heavily on your field though.
       
                  bborud wrote 7 hours 51 min ago:
                  I think I know what you mean.  Let's assume a nesting
                  structure like this:
                  
                  Company -> Employee -> Device
                  
                  That is, a company has a number of employees that have a
                  number of devices, and you may want to traverse all cars.  If
                  you are not interested in where in the list/array/slice a
                  given employee is, or a given device is, the index is
                  essentually a throwaway variable. You just need it to address
                  an entity. You're really interested in the Person structure
                  -- not its position in a slice.  So you'd assign it to a
                  locally scoped variable (pointer or otherwise).
                  
                  In Go you'd probably say something like:
                  
                  for _, company := range companies {
                    for _, employee := range company.Employees {
                      for _, device := range employee.Devices
                        // ..do stuff
                    }
                  }
                  
                  ignoring the indices completely and going for the thing you
                  want (the entity, not its index).
                  
                  Of course, there are places where you do care about the
                  indices (since you might want to do arithmetic on them).  For
                  instance if you are doing image processing or work on dense
                  tensors.  Then using the convention borrowed from math tends
                  to be not only convenient, but perhaps even expected.
       
            Joker_vD wrote 9 hours 34 min ago:
            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".
       
            monooso wrote 9 hours 52 min ago:
            I would argue that ambiguity and uncertainty slow down reading, and
            more importantly comprehension, far more than a few additional
            characters.
       
              lokar wrote 8 hours 2 min ago:
              It depends on whom you are optimizing for.  Someone who knows the
              language, but not this system/codebase, or someone who works in
              this area often?
       
        qezz wrote 12 hours 39 min ago:
        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?
       
          alex_edwards wrote 8 hours 6 min ago:
          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.
       
          pphysch wrote 8 hours 44 min ago:
          "Chat, generate me a table of bad Golang making practices"
       
          alexfoo wrote 8 hours 53 min ago:
          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 'Ù¡'
          
          (I tried a few of them but not all.)
       
          0x696C6961 wrote 12 hours 18 min ago:
          The example with the dash in it confused me as well.
       
        nasretdinov wrote 12 hours 51 min ago:
        I like this article — short, accurate (which is somehow not a given
        these days...) and useful, just like Go language itself.
       
        red_admiral wrote 13 hours 56 min ago:
        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).
       
          DauntingPear7 wrote 12 hours 52 min ago:
          The booms receive regular updates. I got an email about an update to
          Let’s Go Further on 3/12 for Go 1.26
       
       
   DIR <- back to front page