Hacker News new | past | comments | ask | show | jobs | submit login
Go Annoyances (borud.no)
31 points by lycopodiopsida on Feb 12, 2022 | hide | past | favorite | 16 comments



I’m not sure I understand the criticism around documentation in Go, although I’m admittedly not familiar with Javadoc. If you need to document a function parameter beyond its name, most Go authors (this is true of the standard library as well) just add a quick note in the function doc comment. And if you need to add a whole slew of notes for a whole mess of parameters, that’s a good indication that the function may need refactoring. As for the return value, if that’s not obvious, is there a deeper issue with the function itself?

If you need to explain at length what the parameter should conform to, it may need to be sub-typed so it may validate its own complex constraints on construction, or in Go 1.18, it could potentially be generic and constrained.

Would be very interested if the author could clarify the need for structured parameter documentation with some examples.


I rather like the lack of markup in godoc. I think there should be a wee bit more than it currently has (lack of lists and headers springs to mind), but that's about it. There's a proposal to add this, btw [1]

I certainly dislike stuff such as:

  // Basename returns the last portion of the path (that is, everything
  // after the last / or \, depending on the platform).
  //
  // @param path string The pathname to modify.
  // @return string The modified pathname.
  func Basename(path string) string
Which almost invariable ends up happening; the usual way this happens is something along the lines of "there is not enough documentation!", "I know, let's add a linter to enforce it!", useless documentation ensues.

Writing stuff as prose rather than a "bullet-list" in general is also better, IMO. I often find "structured" documentation like this much more sloppy in practice, as too often people will just slap on some @-things and confuse that for "documentation". Writing one or two paragraphs is often clearer.

[1]: https://github.com/golang/go/discussions/48305


I really want to see a thoughtful discussion of Go annoyances, but this isn't it. This is just a very idiosyncratic, short list of gripes, a grab bag, without any underlying consistency.


Seth Vargo recently wrote a pretty good summary[0] of things he’d like to see changed in a theoretical Go 2.0. I don’t strictly agree with everything he says, but it’s all pretty sensible and well thought out. (Interestingly, he also critiques Go’s anemic logging options.)

[0]: https://www.sethvargo.com/what-id-like-to-see-in-go-2/

Associated HN discussion: https://news.ycombinator.com/item?id=30205232


Thanks. I'd read that one previously, and had much the same "this is a grab bag of idiosyncratic gripes" to it, too.

The "don't copy range values" one is particularly indicative. I think the whole point of copying range's values is to avoid all the ugly, ugly problems with modifying the object being iterated over if you don't copy them. Wishing for real references to the iterated-upon object in a range is one of those things that you should maybe think about before asking the genie for it.


> Why on earth do you then have to invent a new syntax for time formats that requires you to memorize a “magic” timestamp, and try to remember if it follows the broken US practice of illogical month/day ordering.

I find this kind of critizism to be unfounded as it seems the author have not actually used the feature but is just complaining about it.

This is how it is used, and as you see there is no preference for "the broken US practice of illogical month/day ordering":

    n := time.Now()
    localTimeFormat := "2006-01-02 15:04:05"
    formatted := n.Format(localTimeFormat)


The point is that in order to remember the order that the dates should be put in, you need to remember google's 'reference' layout .. Jan 2 15:04:05 2006 MST ... in other words:

1) Month, 2) Day of Month, 3) Hour, 4) Minute, 5) Second, 6) Year

So yes, you DO need to remember that the numbers are 'month/day' ordered, in order to, from memory, derive that it's 2006-01-02, and not 2006-02-01. With strftime, we effectively standardised "%Y-%m-%d"


> google's 'reference' layout

Nothing to do with Google here, by the way. It's just the default format of the Unix date command.

So if you can't remember the order, just switch to your shell and run `LC_ALL=C date`.


Not quite. With date, the timezone comes before the year.

LC_ALL=C date => Sun Feb 13 14:27:18 GMT 2022


IMHO there are better things to pick on Go for. The choice of using capitalization for public/private is probably the largest imho. When you want to change a field you have to change all references to it too. You could argue an IDE makes that easy, but what about when patching with Git or other external tools, now your simple patch is context specific. The second biggest is then probably the module system. To this day I'm still confused when a local project has an import from a github URL. Is that using my local github.com/user/myfolderlocally or is that legit pulling the old version I have on github, gets more confusing with cross repo modules. Then the whole /internal paths for modules is also annoying, I sometimes want to use an 'internal' thing from another repo, but I can't because Go artificially limits me and the previous author thought 'nope no touchy' and I'm just left with forking for a tiny little import - gah. Finally is probably the ethos of the community itself - never change anything and keep it all dog simple or get chastised for suggesting anything outside of what is currently the norm. The power is often handed to the authors of packages and the language itself, over the users of packages - and there's essentially no escape hatches anywhere - "do it this way or your design is wrong".


Everyone will have different gripes based on previous experience.

I once religiously wrote Doxygen (aka javadoc) comments for all my C code. Eventually I realized it was just very verbose red tape that added little value. In C no-one bothers to actually generate or read the generated Doxygen HTML output. It's just waste. Granted in Java this is not the case as javadoc is more permeated into the culture. Anywho, personally I'm glad the Go designers went with something more lightweight that focuses on the essentials. All just personal preferences...

WRT logging, can it be done right? I think in most circumstances the right answer is to not log anything at all. Logging poisons the code you are writing, forcing the user of your code to relate to the same logging APIs as you choose. Maybe they will have 10s, 100s of different logging APIs to relate to in the final program. If you are writing reusable code for others I think the answer is to avoid logging to the largest extent possible. Otherwise do something really simple that the user of your code can control if they want or not.


Especially given I just commented on another thread that I was surprised at a suggestion Go might “become the next PHP”, these are much more compelling complaints than what I usually encounter.

I’m not a Go dev so I only have a fuzzy view into the actual dev experience. But I would never have imagined that you’re expected to make struct types public in order to return instances. That’s a baseline expectation of hiding implementation details right? Along with logging levels, I’m shocked that this is more painful than in typical JS/TS setups.


> I would never have imagined that you’re expected to make struct types public in order to return instances

You can return unexported ("private") instances; for example this is perfectly valid:

  type unexport struct {
      Str string
  }
  
  func (unexport) Method() string { return "export" }
  
  func NewUnexport() unexport {
      return unexport{Str: "asd"}
  }

And you can get/set the exported Str field from another package without problems, as well as call the exported Method.

You don't even need to make an unexport package type and can use an anonymous struct or type declared in the function too, although you can't add any methods like this and is often cumbersome because you need to declare the anonymous struct more than one.

And, of course, you can make parts of a struct private by just not exporting them. It's really not all that different to how OOP languages work with public/private, except that visibility is dictated in the name itself.


You can make the type itself public without making the fields public. This means someone could hypothetically create one of your structs without using the "New" function you provide, but it's not an issue in practice. And if you really want to avoid exporting your struct at all, you can always just return an interface.


> And if you really want to avoid exporting your struct at all, you can always just return an interface.

This is what I think most TypeScript libraries should be doing, but every bit of inertia makes it unlikely. In all honesty I think type systems should be designed around contracts/protocols and make concrete types private by default. Sure it’s a lot of ceremony, but it’s less ceremony than human communication in emails and issue threads to clarify that undocumented features are undocumented on purpose.


Want to see logging done right? IMO, Microsoft.Extensions.Logging is just the right amount of abstraction to be easily understood and extremely extensible.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: