4 ms·
I find the opposite is true. It too often means the focus is on fiddly and tedious book-keeping - instead of writing some code that says “please do a thing”, I
by matthewmacleod 7y ago
I find the opposite is true. It too often means the focus is on fiddly and tedious book-keeping - instead of writing some code that says “please do a thing”, I write some code that says “please perform these 20 steps to do a thing in excruciating detail even though you are much better at deciding how to do this than I am”. It’s noise that detracts from the readability of the code far too often for my taste.
- zer01 7y agoThis has absolutely been my experience as well. Golang is good at being fast, but to say that it helps write better code because of its missing batteries/features is just silly I think. "I want to interact with a REST API and pull a field out of its response JSON" is an incredibly common workflow, and yet to do that in golang is far from trivial. You need to define serializer types and all sorts of stuff (or you can take a route I've seen encouraged where people to use empty interfaces, which can cause runtime exceptions). Same deal with a worker pool. Concurrency is great, but instead of providing a robust, well written solution as part of the language itself, it gives you a toy like this https://gobyexample.com/worker-pools https://gobyexample.com/worker-pools (still the most common result on Google) that is only 80% of the way there. Then you find yourself bolting things onto it to cover your features (we need to know if things fail, so let's just add another channel. We also need finality, whelp, another channel it is), and before you know if you have an incomprehensible mess.
- sagichmal 7y ago> "I want to interact with a REST API and pull a field out of its response JSON" is an incredibly common workflow, and yet to do that in golang is far from trivial // Interact with a REST API and pull a field out of its response JSON. func interact(url string) (field string, err error) { resp, err := http.Get(url) if err != nil { return "", fmt.Errorf("error making HTTP request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("error querying API: %d %s", resp.StatusCode, resp.Status) } var response struct { Field string `json:"the_field"` } if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return "", fmt.Errorf("error parsing API response: %w", err) } return response.Field, nil } IMO this is a good level of abstraction for a language's standard library. Each of the concrete steps required for the process are simply and adequately represented. Each can fail, and that failure is idiomatically managed directly and inline, which, when applied to an entire program, significantly improves reliability. If you find yourself doing this often, you can easily write a function to do the grunt work. Probably func getJSON(url string, response interface{}) error > Same deal with a worker pool. Concurrency is great, but instead of providing a robust, well written solution as part of the language itself, it gives you a toy like this Go's concurrency primitives are very low level. This can be bad, but it can also be good: not all worker pools, for example, need the same set of features.
- dkarl 7y agoI agree with this 100%. Go is great for micro-readability: "what do these ten lines of code do." Go is horrible for macro-readability: what does this module do, what does this service call do. If you compare a fixed number of lines of code, I wouldn't be surprised if Go always wins out for readability. But if someone says, "Figure out the business logic behind this feature implemented in Go," get ready to spend a lot of time scrolling through low-level code. I always thought code written as page after page of low-level details was bad code. I thought the same thing about code written as class after class after class of OO hierarchy. But people talk about Java and Go as if it's impossible to write unreadable code in them. I don't think code has to contain a single hard-to-understand statement to be "unreadable." After all, code that is unreadable because of abuse of powerful language constructs isn't literally "unreadable." You call it that because reading it requires an unreasonable amount of time and effort. The same thing can (and should) be said about code that requires an unreasonable amount of effort for any reason. To me, it's just different ways that programmers can waste your time. One programmer might waste your time by combining powerful language features in cryptic ways; another might waste your time by hiding crucial structure in a vast sea of details. What's the difference?
- sangnoir 7y ago> But if someone says, "Figure out the business logic behind this feature implemented in Go," get ready to spend a lot of time scrolling through low-level code. I've found "go doc" amazing for this use-case; I only ever trawl through the source-code for a high-level understanding as a last resort - usually because the code is undocumented or under-documented.
- hackinthebochs 7y ago>I always thought code written as page after page of low-level details was bad code. I completely agree with this. The best code is code you don't have to read because the structure of the code makes navigation easy and functional boundaries obvious. A language that doesn't provide strong support for declaring functional boundaries results in code that is much harder to read because you have to comprehend a lot more of it to know what's going on.
- 7y ago