Hacker News new | past | comments | ask | show | jobs | submit login

> In Go, if I see a call to `import ("foo/bar"); bar.baz()`, all I know is that ONE of the files in the folder `foo/bar` contains a function `baz`, with no direction on which it is.

This is a code smell for poor file organization in your "foo/bar" module - in a well organized project, it should be obvious which file in a module contains a given function[1]. Go doesn't force file=module paradigm (preferring the folder to be the basis), however, it doesn't preclude having one file per module, if that's what you prefer. If you're reading someone else's poorly organized code, you can always use grep.

1. Say, you have an `animal` module, the first place you check for `NewCow()` is `animal/cow.go`




> Go doesn't force file=module paradigm (preferring the folder to be the basis),

Yes, this is what that complaint was about?

> however, it doesn't preclude having one file per module, if that's what you prefer.

> 1. Say, you have an `animal` module, the first place you check for `NewCow()` is `animal/cow.go`

This whole subthread was about reading other people's Go code. Of course your own code is going to look organized to yourself!

> If you're reading someone else's poorly organized code, you can always use grep.

Yeah, ripgrep tends to be what saves me in the end. Still annoying to have to break it out all the time.


> Yes, this is what that complaint was about?...This whole subthread was about reading other people's Go code.

So the complaint, restated is "Go doesn't prevent other people from writing bad code?" Am I getting you right? If so, well, I have nothing to say about that.

edit: I do actually have something to say. I just remembered having to work with an 82,000-line long Perl module file that would defeat any IDE. Fun times. No language can save you from poorly organized projects, whether the modules are file-based or folder-based.


I would say it's closer to "Go doesn't do a really simple thing that nudges people towards writing more readable code, while having basically no tradeoffs".

Considering the far more tedious tradeoffs that Go does force on users in the name of supposed readability (for example: the lack of generics), I'd consider that a pretty big failure.

I don't expect them to be perfect. I do expect them to try.


FYI: Go's lack of generics was not related to readability - the Go team didn't have a solution they liked, so instead of saddling the language with a half-assed solution forever, they waited for a more elegant solution. Also: the design of Go generics was recently approved (as in the past month).

It's no secret that Go is targeted at "programming at large". Go's design favors larger, fewer modules, how those modules are structured is left to teams/individuals. I may be lucky to work with a great team, but I always find the code where I expect to find it. When I'm starting from scratch, I utilize modules, <$VERB>er interfaces, structs and receiver functions: I cannot remember ever running into an ambiguous scenario where I'm unsure where a particular piece of code ought to go.


Like the parent, I read more Go than I write, and I have never seen a single-file-per-module (unless the entire project is one file). And sometimes it's obvious what file a function is from (like in your examples), but a lot of times it isn't. For example is `GiveFoodToCow` in food.go or cow.go? Maybe there are patterns that experienced gophers know, but that adds cognitive load. And would having a 1 file per module paradigm have made go any more complicated?


food.go and cow.go do not belong in the same (sub)module, IMO. That said, each team (and project) have unique sensibilities - consistency and familiarity help here. My gut feeling is that the "belongingness" of feeding a cow is closer to the cow than the food, unless your food.go is full of "GiveFoodToCow(), GiveFoodToChicken(),...GiveFoodToX()" which is gross. With that complexity, you're better of with a Feeder interface and implement Feed() in cow.go (and chicken.go, etc). If you cannot distill the logic to a single interface, you're probably better off with a receiver (or regular) function in cow.go, because having a list of GiveFoodToX() with different args in food.go is the worst possible design you could go with.

> And would having a 1 file per module paradigm have made go any more complicated?

I was being facetious. Under normal circumstances, no one should use one file per module in Go, but if Rubyists are feeling home-sick while writing Go, the option is available to them ;)




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: