This sounds a bit inflammatory. For the benefits of us beginners, why do you consider that those tools are the right thing and golangci-lint should be avoided?
One example: golangci-lint
includes a linter called ireturn
which warns when you return interface
types from functions. It references Rob Pike’s opinion on the proverb “Accept Interfaces Return Struct/Concrete Types”.
To which he responded
I’m not a great fan of that one. It’s subtle and tricky to explain compactly. And although popular, it’s not often easy to apply well. Plus: Why structs? There are many other concrete types in Go […] It’s very hard to be clear about where it applies, and it often doesn’t.
It’s a bit comical that this manufactured lint rule appeals to authority by linking to a Rob Pike conversation … which ultimately disagrees with the proverb that influenced the lint rule.
Linter rules are a bunch of opinions that aren’t agreed upon, while native go tools are for better or worse the “law of the land”. Nobody will ask you to love the law, but you’ll abide by it as long as it remains unchanged.
That has nothing to do with avoiding golangci-lint though. That they have a lint available doesn’t mean you have to use that lint, as can be seen by TFA disabling a bunch of them.
And that something is a compiler error doesn’t mean everyone agrees with it, just that whoever wanted it got it through before the language was published.
Furthermore the existence of go vet
completely breaks your quip by both being “a buch of opinions that aren’t agreed upon” (because it’s a linter) and “the law of the land” (because it’s a native go tool).
I’ll gladly concede that go vet
is a linter and won’t bother arguing my ill defined concept of “land law” with respect to its checks :)
However every compiler error is indisputably the law of the land. Because you can disagree with compiler errors all day long, but without changing the compiler, any argument against them is moot. There is a high barrier to changing compiler errors; in that sense they are very much law.
As I said:
you’ll abide by it as long as it remains unchanged.
there are many issues with it, however the primary problem is that it bundles an old fork of staticcheck and disables many of their default lints. it also includes a bunch of linters that don’t really do anything.
here is one of several instances I know of from the staticcheck maintainer on twitter and I don’t even pay that much attention, I’m sure if you searched golangci-lint on the staticcheck issue tracker you’d find more
I’m not the maintainer, however, I feel sympathy for him. that being said, golangci-lint isn’t doing anything wrong or illegal, it’s open source software, you’re free to use it even in ways the original author doesn’t intend or approve of. that being said, you aren’t necessarily entitled to support
Sounds like a weak way to promote own tool. Just saying.
Not a very charitable take.
I don’t know anything about the specifics of that debate, and I haven’t (yet?) noticed problems using staticcheck with golangci-lint. But when I started using golangci-lint in December of last year, I immediately noticed that the results for revive were different if I used it under golangci-lint than if I used it alone. (Briefly, revive under golangci-lint was silent where there should have been warnings.) The problem persisted, and I ended up with this note in a git commit.
At the moment, the revive and golangci configurations are separate, and
they have some overlap. They don't seem to play nicely together, and
I don't want to spend too much time debugging that now. But I should
come back to this later.
As you can imagine, I never came back to it. The only way that I can get things to work correctly is (still) that I run revive alone and then I run golangci-lint for the rest of the linters I use. That’s not the end of the world, but it does suggest to me that the staticcheck maintainer is not making things up. golangci-lint seems to alter how (some?) tools operate under it. That may make sense—or even be necessary for some reason—but it can also be a pain. I like golangci-lint a lot, but it causes some problems too.
One of the appealing things when first getting into Go was the lack of configuration required for external tools like linters, and just using the built-in gofmt, govet staticcheck and use gopls in your editor.
Not sure I’d want to run all these in this fashion, but I guess that’s preference.
Interesting point of view. Yeah, Go works perfectly out of the box and the tooling is also great (sure, there are things that can be better but comparing to other ecosystems it’s definitely better).
As I mentioned in the post: linters are these small wheels when you’re learning to ride a bike. If you’re ok without them - what is the point to attach configure them?
By example for most it’s ok to have misspell in the code, for me too mostly. But if I can make my code slightly better for a small price, so why not? :)
I don’t think it’s just “small wheels when you’re learning how to ride a bike”, because the Go project refuses to add warnings they can’t really add new diagnostics which would break existing code, and there’s a lot of common errors in go code you may want to guard against, which requires a linter.
E.g. append
errors, ignoring error
return values, creating interface values from possibly nil typed pointers, closing over loop variables, dead stores, passing locks by value, as well as more defensive practices you may want to impose in larger codebases like full slices, …
Warnings are added via vet. “closing over loop variables” and “passing locks by value” are both covered. edit: they refuse to add vet warnings that have the potential for false positives.
Yeah, I can see both sides of this:
-WAll
and everyone needs to run it to ensure correctness.Rinse and repeat. :-)
I think it’s more subtle than that. I think Go situation is isomorphic to Rust.
In Rust, compiler emits errors and warnings. False positives are not allowed. New warnings for old code are added over time. This creates a problem that, if you deny warnings during a build, and warning in dependency can lock you out of a new compiler. For this reason rust has a special flag which tells it to emit warnings in user’s own code, but not in dependencies. So, errors are for all code, warnings are for your code.
Go does exactly the same thing, except that it’s a separate subcommand (vet
) rather than a special flag for the compiler.
Totally agree. There are so many errors in Go that are only caught by the linter and not the compiler. The linter is necessary.
Many of the things discussed here, and elsewhere, are actually highlighted by Goland, which is one reason I’m a loyal JetBrains user.
Thank you for a share! I have one small addition. For dependabot config, the open-pull-requests-limit
option can also help to reduce the noise.
Oh wow, that’s a gem. Thank you!
I was overhappy to see how it’s easy to configure and added to my repositories right after I read half of the article.
(in case someone will ask https://github.com/cristalhq/.github/blob/main/.github/workflows/vuln.yml)
Going to finish tests for https://github.com/cristalhq/dbump and add ClickHouse, MySQL connectors.
And, hopefully, rewrite reflect part in https://github.com/cristalhq/aconfig (wish me a luck)
Not a small change, but: getting a dog.
With a dog, I have to go on walks outside way more often than I did before, and it’s doing me a lot of good physically, but also mentally: I don’t know what it is, but I don’t think about work when I’m on the trail with my boy. It’s also an amazing source of love and comfort after a tense Scrum planning or refinement.
We’ve a puppy for 1.5month and yes, he is a life-changer. But before getting a dog I suggest to dig into this topic and understand: can you take care of someone who doesn’t understand your language(s) (not only the voice, but gestures so on).
I’m curious why Base62 and not simply Base64UrlSafe, which has a constant time implementation in libsodium.
Base64UrlSafe
Hm, constant time, what do you mean by that? Also have tried to find the code (regarding b64) but no luck :(
See for example https://blog.ircmaxell.com/2014/11/its-all-about-time.html
It is mostly important for decoding key material if stored encoded, so technically it may not be necessary here to have the encoder/decoders be constant time, but well, better safe than sorry when dealing with security sensitive code.
Going to create next major release for JWT in Go (https://github.com/cristalhq/jwt) with a few memory optimizations.
Also probably play with another libs in todo.
BTW, for the such and similar situations go-critic has checks rangeValCopy
and rangeExprCopy
See docs: https://go-critic.github.io/overview
Thanks, I integrated it into my codebase. The default sizeLimit of 512 seems rather large, I would expect to see something like 64.
https://github.com/contribsys/faktory/blob/master/.golangci.yml
go-critic has a support for config per checker, look for @rangeExprCopy.sizeThreshold
on the overview page :)
And from what I see there is no mention of go-critic config param (oops), we’ll update docs soon.
Just in case if you didn’t know: you can change the default size with -@rangeExprCopy.sizeThreshold
parameter.
To get a list of checkers, run: gocritic doc
.
To get info about a checker, run: gocritic doc <checkerName>
.
So, in case of the rangeExprCopy you do “gocritic doc rangeExprCopy” and it tells what parameters are available.
Hm, 7hrs ago I saw a paywall….but now don’t.
(there is a little chance that modern web was loading too slow that I’ve decided it’s blocked for me)
Well, make sense per discussion linked in commit message.
BTW, there is an official (?) llvm backend made by Go team and which is needed by Google, what was the point to support inside LLVM repo?
https://olegk.dev - simple Hugo generated web-site. Hosted no Github + Cloudflare DNS
Obvious one: https://www.cloudflare.com/dns/
I’ve started using Starship and I’m pretty happy with last few weeks.
Wow, what a feature! That’s a pretty cool addition to Postgres debugging.
PG 16 should be ~Nov 2023, right?
The roadmap page states: