9 ms·
If you’re the type of engineer who prides themselves on the raw amount of code you write, then Go is for you. If you’d rather focus on solving problems creative
by dcow 5y ago
If you’re the type of engineer who prides themselves on the raw amount of code you write, then Go is for you. If you’d rather focus on solving problems creatively and expressively, Go is not your tool.
I don't mean this as slight against those people that really enjoy writing lots of (Go) code. It’s just my observation after being in a few different contexts where Go was the language of choice. Personally Go is too verbose for me and this is especially painful/apparent when you get to writing the multitude of tests required to ensure your code works since Go’s type system/compiler doesn't lend you much in the way of helping ensure code correctness.
Go is essentially the new Java.
- tacitusarc 5y agoThis feels largely like a mischaracterization, and does not align with my experience. I'd change it to say, if you are focused on solving the problems creatively rather than using the language creatively, Go is a viable option. But if you're interested in creative usage of the language itself, Go is not right for you.
- axaxs 5y agoI agree with this. Go works like my brain, and I don't mind that. Sure you can do X in some fancy way in other languages, but that just leads to feature creep. I've never read Go code I didn't understand at first glance. I cannot say that about a single other language.
- dcow 5y agoAnd this is totally fine if you're okay reading and writing noticeably _more_ code to solve the same problems. There's nothing wrong with favoring verbosity over expressiveness, it's just not my style. I disagree that expressiveness lends to feature creep, I've personally never seen that happen, but that's another topic. For me, the verbosity of Go would be a lot more justified if it aslo had some sort of memory safety system in place (similar to Rust) that could help prevent concurrency related errors. I understand that you're supposed to used channels for everything in Go, but last time I wrote a channel heavy concurrent server the compiler did nothing to prevent me from mutating shared state across different go-routines and I was unable to land on a pure channel based implementation (I needed a run_once to initialize some shared state and a WaitGroup to track active listeners, and this was the case in all the other impls I audited/referenced as well). I just don't feel like I'm getting a lot of value in exchange for the verbosity when writing Go.
- axaxs 5y agoThat's a completely fair assessment. I don't fault 'you guys' at all because I don't expect your brain works like mine. Read: I don't think you're wrong and I'm right...never. What I fear myself is feature creep. A design by committee that ruins the language for me, and is never good enough for you.
- loopz 5y agoIf sharing state, you're much better off using locks and test with go's race detector. There'll be subtle bugs or contention though, unless you don't share state. If not, you might try 0mq, immutable lists or any other facility. Channels are just the in-process idiomatic way to communicate state, but not required at all.
- fpoling 5y agoIn my somewhat brief experience with Go I realized that one better avoid channels even for supposedly idiomatic cases. For example, try to implement a priority queue with channels. Or why it is not possible to use the select statement against a file descriptor? Another problem is proliferation of unnecessary threads that are entirely avoidable when using mutexes.
- loopz 5y agoI agree. One should have good use cases for channels, and they're overused just to get new people started with goroutines. Mutexes go a long way, and underpins channels anyways.
- unscaled 5y agoChannels are also hardly foolproof. You need to internalize the (non-obvious) channel axioms[1], and there are many other pitfalls and annoyances like: - Needing to determine ownership of closable objects passed across channels. - Defining what special token (or OOB signaling mechanism) is used for marking end of data. - Synchronizing who is closing the channel Go channels are quite painful to use and often a simple lock would do better. This write-up[2] summarizes the issues with them quite nicely: [1] https://dave.cheney.net/2014/03/19/channel-axioms https://dave.cheney.net/2014/03/19/channel-axioms [2] https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-should-feel-bad/ https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-s...
- cultofmetatron 5y ago> Go works like my brain can't really fault you on that either. features/looks etc. it really comes down to wether it matches how you think. I can make big claims about functional languages being superior for x y and z but if I'm being really honest with myself. its more about that fact that it fits how my brain already models problems.
- dcow 5y agoI get what you're poking at and I think we're mostly saying the same thing. However I want to point out that at the level of the stack we're discussing, the application of the chosen language is essentially: plumbing. The user-facing "creative" bits I think you're referring to (those in the system at large, which may or may not use Golang middleware) are most likely a react or mobile app. I'm not trying to devalue the self worth of individuals who write Go code by suggesting that the problems their products are solving aren't creative and fun. Not at all. Rather, my point is that the application of their Go code to build yet another solution for processing requests and serving responses ends up as pretty mundane and verbose imperative program logic that requires non-trivial amounts of effort to properly test and verify. Creativity in the "plumbing" slice of the stack to me looks like concise, readable, expressive code that leverages a type system to model a problem domain and then incorporates expressive logic governing how the types interact, the correctness of which is mostly enforced by the compiler itself and where testing is only required to ensure properties the type system can't capture or to make sure traits of a given type are implemented correctly. Go just simply isn't a language that allows for that level of "creativity" in building what would otherwise just be pretty mundane service plumbing.
- noisy_boy 5y agoI think we shouldn't point fingers at Java when it comes to Go's verbosity. I can simply do dict.contains("foo") in Java vs having to go through a verbose hoop: if val, ok := dict["foo"]; ok { //do something here } Common operations like filtering/transforming a collections are very concise in Java - I'm certain doing so in Go will take atleast 5x as many lines: collection.stream().filter(...).map(...).collect(...) Don't get me started on having to go through iota hoops to declare enums.
- dcow 5y agoLast time I wrote Java was before it had nice things so I may be slightly out of date in my assessment of its verbosity. I really wish it had decorator syntax like Kotlin does: class Foo(val delegate: Collection) : Collection by delegate { override fun length() = delegate.length() + 42 } val foo = Foo(delegate: LinkedList()) foo.add(1) foo.add(2) for e in foo { print(e) } foo.removeAll() foo.length() // = 42 I think a lot of the verbosity I remember was due to the sheer size of the type of interfaces you'd encounter in practice and an inability to easily compose them without implementing your own set of forwarding decorators (io stream style). That and getters/setters or rather the lack of any language-level support for dynamic properties.
- vips7L 5y agoDo you really want to inherit all the functions of Collection? Isn't this the anti-pattern everyone complains about on inheritance vs composition? This just looks like it's confused about whether it is a collection or has a collection. Personally, I'd just rather take a collection by composition and only expose the small part of the API I actually want. I guess though this is the standard decorator pattern you'd normally see from GoF.
- dcow 5y agoIt also breaks LSP when you “extend but reduce”. Not saying there aren't uses for “have-a”. More that writing a decorator in Java is awful.
- konart 5y ago>If you’d rather focus on solving problems creatively and expressively, Go is not your tool. >It’s just my observation Well, my observation after dealing with js and ruby projects (ruby was my main language a few years ago) - those creating and expressive languages lead to fewer lines, sure, but in the end you are dealing with a pile of crap nobody want's to touch because some of the developers were so creative and wanted to express themselves more than they wanted to solve the problem. Go is a tool if you actually want to solve the problem and make sure people after can quickly understand how and why you solved it. Rather than stand in awe of your creation.
- takeda 5y agoI see what you mean with ruby, it encourages to be clever, and I had some exposure to work on somebody's "clever" code. I'm not as familiar with js, but feels similar to me as well. What makes things worse they are both dynamic languages, but there's a middle ground. It feels like Rust for example (I'm still planning to learn it) looks like have the right amount of functionality. Java or even C. I think what you experienced is the extreme case of it.
- candiodari 5y agoThis is just the old conflict between ops and dev. A software dev wants a little code to express a lot, while maintaining some central guarantees, and doesn't really care about edge-cases beyond not having to code them explicitly. Needless to say, a few edge cases will turn out not to be what the dev intended, no matter how smart they are. Tests focus on the central guarantees and nothing else. Ops is the next guy who comes in, who is only ever supposed to keep everything running. Changing things is second priority, if it's anywhere at all on the priority list. (S)he will HATE any edge case they don't know exactly what happens because it can be bad, and it's the source of all their work. They want to manually code every edge case, and have that covered by a test. C/C++ ("smart" C++ specifically), Haskell, Lisp, ... are for the software devs. Go, Java, C#, ... are for the software ops folks. A large bank should probably be using Java. Someone trying to start up a new bank may prefer Haskell. I don't see this conflict resolve any time soon. Personally I find the large bank situation somewhere between soul-crushing and suicide-inducing. But I've met plenty of people very happy in such situations, and great for them. I may even consult for them, because for 1-2 months or so software ops can be quite interesting. Figuring out how to introduce changes in a software ops org is ... usually a challenge in addition to figuring out how the software system should change. You always come out well, because there's always large improvements that can be made because nobody's doing that. They're busy triple-checking that the next parent-teacher conference of employee 271 doesn't interfere with the oncall schedule. And frankly, I could (and probably can still) use a few lessons in "this edge-case fuckup is not acceptable and you missed it !". I've been humbled several times by steering a large problem past all security measures of a software ops organization in the past.
- tored 5y ago> Go’s type system/compiler doesn't lend you much in the way of helping ensure code correctness Do you have any examples? Not a golang programmer myself.
- eternalban 5y agoGo's weak type system encourages use of dynamic type ops (such as casting interface{}, etc) and obviously the compiler is out of the loop at compile time so it can't help.
- theshrike79 5y agoI've written my fair share of Go over the years and I've cast to interface{} exactly zero times.
- simiones 5y agoExplicitly, I believe you, but I'd bet you've often implicitly cast to interface{} (even some very legitimate cases like json.Marshal() are still technically casts to interface{}).
- fpoling 5y agoWhat makes me sad about Go is that the verboseness comes not from the language but from its formater. If the formater allowed to write in one line if err != nil { return err }, it would drop the number of code lines by the third.
- lenkite 5y agoPlease omit the last line. Go is actually far more verbose than modern java when you are comparing anything bigger than a single snippet of code. Modern functional Java is fairly concise. Go is not - though maybe this will change with generics and functional packages after Go 2.0.
- cryptos 5y agoGo is like Java 1.2 from 1998.