This advice should be universal in coding. When I first started programming, I had a manager that hated 1-2 character variables. But they make sense for loop iterators.
Designing an API that "stutters" is a very common mistake that many programmers make. reader.Read() is pretty jarring.
There is also nothing wrong with naming variables after what they're for instead of what they are. Consider io.Copy(dst, src). That's nicer than io.Copy(reader1, reader2).
Sure, so call your reader `file` or `network` or `stream`. Don't call it `r`. Nobody is charging you by the character.
It isn't a huge deal when the code is simple, e.g. you create a reader named `r` and in the next line you use it. That's easy to understand. The problem is that the pattern propagates. A few more lines of code are added, the reader is still named `r`. It's name `r` here, so we start putting it in a struct as `r`. Soon enough the codebase is littered with instances of `r`. Not great.
This is much nicer for other people coming into this. It's the same problem with spoken language and slang, slang is better if you know it, worse if you don't.
Sorry to be pedantic (well, not really it's M.O. for a hacker news commentor after all, isn't it?) , but as someone who knows a few languages, slang is not an issue with spoken languages at all. You learn a language by full immersion with other speakers, who impart that knowledge unto you. Unless all you are doing is conversing with grammaticians and newscasters, you will pick up on regional and local differences, euphemisms, and slang.
This makes me wonder: what if there was a language where variable names are determined according to the type, with the option of overriding with a custom name. So a variable of type http.Request would automatically be named “req”, the next one in scope would be “req2”, etc.
If you think about it, when you solve a physics problem, for instance, you call every mass “m1”, “m2”, etc. Maybe this would be another step in Go’s direction of conforming style to make code more standard and readable.
I agree that most types come with a natural variable name.
However, in many cases a more descriptive name is way appropriate. On top of my mind:
- Multiple variables of the same type. How are you supposed to distinguish between req and req2? Compare it to something like "apiReq" and "cdnReq"
- Primitive types, that does not inherently carry a domain value. An integer called "seconds" or "max_offset" has a lot more meaning that one named "num"
Forcing such a notation into the language would make impossibile to represent all these cases
You’re right. Going back to my physics example, all the variables in a physics problem are actually of the same type, float. So you’d need more specific types, but that would be infeasible-the whole point of types in a general purpose language is that they’re general enough for any use case.
Werrrrlllllll... It all depends on what yo umean by "type". In physics problems, I find taht quantities may be measured in "floats", but have the types "mass", "amperage", "distance per second per second" and the like.
In Go, I would probably model this as:
type mass float64
type speed float64
type acceleration float64
That way, they'd all have float64 as the "storage type", but it would be harder to accidentally pass an acceleration when I wanted a mass.
> Going back to my physics example, all the variables in a physics problem are actually of the same type, float
This is why some people recommend a practice I've forgotten the name of, where they defined a new type that maps to language type. So type Mass could just be a float, but you know better how to treat it.
The real question from this example is: why are you creating two http requests in the same scope before using them?
I've been writing Go cloud stuff for the better part of a decade and "req" for a request has never been ambiguous because I go ahead and send the request and process the response before sending another one, at which point I can just reassign the variable and let the first one fall out of scope.
Terraform has an extreme approach to that, every time you reference a variable you have to spell out the complete TYPE.NAME.ATTRIBUTE, eg resource.aws_s3_bucket.my_bucket.website_endpoint. There is no way to access my_bucket without the whole prefix, even after assigning it to local variable you must prefix the reads as locals.my_bucket.
For sensitive infrastructure this makes sense, i surely wouldn't want to write other code like this.
That could be easily done by the editor in a statically typed language like Go, so there is no point bloating the language with it. Just turn on an overlay that displays the types of all names. I believe LSP adds this to many languages/editors already.
There's also a bit of Fitt's Law in here as well - I find it a lot harder to select, or put my cursor in, a single letter variable. So if I want to rename `i` to something else, I must carefully select `i`, whereas with a longer variable I find it easier to put my cursor in the middle of `index` and hit F2.
I started using ii as my iterator variable name for similar reasons. Easier to highlight and Ctrl-F for. Also removing ambiguity when using i as the imaginary constant.
I think a better heuristic rather than tying it to scope is to sort of semantically huffman encode. Using an iterator is probably the most used variable name that starts with an 'i', so it gets just plain 'i'. As a _concept_ gets more specific, then it gets a longer name.
Or in languages that you can import a resource but give it a custom name. So whenever you are reading someone else's code you have to double check to understand what is going on. For instance, import DiskUtils as DU, and now all the code references DU.diskSpace()
- Longer names mean longer lines, and lines that are longer than your viewport are terrible. Less of a problem with modern ultrawide screens, but passed ~100 characters, it starts becoming a problem in some cases (ex: diffing). Personally, I have a soft limit at 80, hard limit at 120, because that's what works best for me.
- With such rules, variable length is a hint of its scope. For example, I tend to use "i" when the loop body is small, "idx" or "index" when it is a bit larger, and a more descriptive name when it exceeds one screen. This way, just by looking at a single line, I already have a hint about its context.
- Just because a variable name is short doesn't mean it is meaningless. For example "i", "j", "k", are loop indices, "x", "y", "z" are point coordinates and "dx", "dy", and "dz" are differences, "a" and "b" are both sides of a comparison function, "t" can be a temporary variable or a time depending on context, etc... The corollary is to make sure you use your single letter variables consistently. If I see an "x" in a place where a coordinate can be used and it does not refer to a coordinate, or an "i" that is not a loop index, I will be confused.
And for those that don't know - entering Basic code on the Spectrum (well the original one at least) was ALL single/shifted key shortcuts for keywords rather than typing them out.
Same thing for the ZX-80 and ZX-81. If you were careful with your text prompts, you could save several bytes by injecting a keyword instead of typing it out, but anything that was a "start of line only" could be tricky injecting into a string.
The key point is having the full iteration cycle. You can't learn from simply thinking, dreaming, and planning. You need to follow through and experience the consequences. That is what uncovers the unknown unknowns. Those things you can't plan for.
The inability to truly learn from the consequences of their actions is the primary criticism leveled against many consultants. they plan, they do but they rarely stick around for the study and act.
You can indeed learn things when your models highly accurately reflect reality (or in situations where the models themselves are their own reality). Logic and mathematics are powerful tools for making discoveries and learning.
I never wanted one to go anywhere, I've always wanted one for a tiny house / social space on my property. They always struck me as a perfect option for a unique cabin. I know there are old rail car hotels, but I've never seen one that epitomizes the pullman luxury.
I give solarized a lot of credit. Before it came out I pretty much stuck with whatever default theme my application used. After using solarized I started caring about my tools much more. Today, I tend to use Darcula most of the time for IDEs, but I also spend much more time customizing my tools beyond just the theme.