Live data from Hacker News

Practical Go: Real-world advice for writing maintainable Go programs

dave.cheney.net

181–190 of 237 posts

Re: Practical Go: Real-world advice for writing maintainable Go programs

#181
post #35

> Naming the Config parameter config is redundant. We know its a Config, it says so right there. > In this case consider conf or maybe c will do if the lifetime of the variable is short enough. This seems petty. Is it really that problematic to type out a few extra characters?

They don't use any IDEs or modern editors, but vim as a bare bones text entry, without syntax highlighting or word completion.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#182
post #62

Earlier quoted context omitted.

Yeah, I used to go by this advice, and I found the maintainability of my code dramatically increased when I typed out full names. I don't even use "i" for loop variables anymore. If the length is a problem, invest in an editor with autocomplete. Well-known abbreviations are fine, like "iter" and "prev", but single-letter variable names notoriously impede readability for me.

I feel like I have the opposite problem. If the name is more than a few characters long, it starts to become non-instantaneous to recognize it. Things get much easier to follow with visually-instantly-recognizable symbols. So in conditions where a variable is used over a short area in the code (or where it's used _constantly_ over a wide area), I prefer short variables.

I think you're identifying the core issue here, that is, frequently vs infrequently read code. I'd argue that if you've spent enough time in go, variables like `i`, `conf` and `ctx` will become very recognisable and easy to skim over, if they're always used in the same context.

If it's less "boilerplate" code, I'd go for more descriptive names. I think.

I like the sorta described "rule" in this document; the longer the variable is used, the more descriptive it should be.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#183
post #148

Earlier quoted context omitted.

Totally agree. If you have to scroll up to be reminded what some variable means, a longer name is good. But if its usage is a few lines away from its declaration then there's no reason to add visual noise to your code.

Its easier said than done though. We started following this few years back but then while it was "few lines away" originally, code evolved and now there are parts where its 20+ lines away. This means that short var names need to be continuously "enlarged". Well, then why not start with a "medium" name and avoid all that headache? ctx is a good enough compromise between c and context. (c can be client, config, context…

Well as the article states, one-lettered variable names should only really be used in tight loops; `ctx` is a better name for e.g. a function argument.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#184

Earlier quoted context omitted.

Yeah, I used to go by this advice, and I found the maintainability of my code dramatically increased when I typed out full names. I don't even use "i" for loop variables anymore. If the length is a problem, invest in an editor with autocomplete. Well-known abbreviations are fine, like "iter" and "prev", but single-letter variable names notoriously impede readability for me.

Regarding single-letter variables, mathematical functions might be an exception. I think writing func gcd(a, b int) int {...} is better than other alternatives. There is simply no need to assign any more meaning to the arguments other than their type.

Maybe if you - and more importantly, everyone that will read the code in the future - are comfortable with domain-specific expressions like that. It depends on the audience really.

As an extreme example, scalaz is similarly a very specialized DSL. Or in my personal experience, functional constructions like map, flatMap, foldLeft and reduce (which I never learned in school).

Re: Practical Go: Real-world advice for writing maintainable Go programs

#185

Came from Java world, I find the Go comment and godoc are really limited. We can't link between functions, types. We don't have a standard way to declare input, output, don't have any distinction between a normal word and a Go identifier Refactoring using tool (e.g: Goland) usually lead to unexpected text replacements. Take following functions, for example: // Auth check if user credential is existed in bla, bla... /…

The problem with the Java way, as I see it, is that it puts more of a burden on the programmer to the point where a majority simply won't do it. Getting programmers to document their code is an uphill battle to begin with. But the bureaucracy that Java(doc) imposes makes it even harder to win in all but the most elite institutions. What I see a lot, is IDE-generated documentation which can be automatically inferred from the code, and is therefore redundant. While it superficially looks like documentation, it really is just line noise. I would agree that Java documentation at its best can be better than Go documentation. But I suspect that the average Go codebase is better documented than the average Java codebase.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#186

Earlier quoted context omitted.

What would be the signature of your gcd function ?

Numerator, denominator?

For GCD? I would find those names very misleading since semantically the order of the arguments to GCD is irrelevant (even if in the implementation you typically mod by b there's no reason you couldn't mod by a).

Re: Practical Go: Real-world advice for writing maintainable Go programs

#187
post #35

> Naming the Config parameter config is redundant. We know its a Config, it says so right there. > In this case consider conf or maybe c will do if the lifetime of the variable is short enough. This seems petty. Is it really that problematic to type out a few extra characters?

It is problematic for readability reasons as long as you are making complex expressions:

    configuration := NewConfiguration()
    configuration[word] = parameters[values[line][column]] - parameters[values[column][line]]
vs

    conf := NewConfig()
    conf[w] = params[vals[i][j]] - params[vals[j][i]]
It takes your brain more time to parse the first line. Now, there is an obvious limit, this is probably too much

    c[w] = p[v[i][j]] - p[v[j][i]]
unless maybe the scope of the vars is very limited.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#188
Good collection of best practices overall. I would not say they are Go-only, as I read about them 5 years ago in Clean Code by R. Martin and another part can be found in Code Complete by Steve McConnell.

Once again, good collection if you have no time to read the book. Anyway, it does not cover other parts like contracts/interfaces, the absence of comments (which can be a good sign) etc. Would recommend checking both CC books if you want to write better and maintainable code.

PS. Anyway, Dave, thank you for the popularization of best practices.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#189

Earlier quoted context omitted.

> For a local variable, the name i conveys as much information as index or idx and is quicker to read This is only true because i is a specific, common abbreviation for index. When writing arbitrary glue code, a single letter variable would be a meaningless abbreviation without shared context. If you encounter "i" and it doesn't mean "index of a for loop", you're going to be taking additional time parsing meaning.

An example where I disagree, and use 1-letter names daily: arrow functions in both Java and JS. `usersList.stream().forEach(u -> someSet.add(u))` It's immediately obvious that u is a user in usersList. I realize that it's debatable if u is really more readable than spelling out user, but I prefer it, and I don't think anyone is going to be confused by it. If the chain does get really long, also, I will spell it out e…

Shouldn't you be able to write that as `usersList.stream().forEach(someSet.add)`

For Javascript at least that would work.

Post reply on HN