|
As someone who uses Go daily and enjoys it a lot, there's definitely an inflection point in many areas where Go's lack of abstraction becomes a pain point. One application I work on is a real-time query engine. Queries are parsed into ASTs, then reorganized into a higher-level graph reminiscent of relational algebra, then run through optimization stages, etc. Go is terrible at this in pretty much exactly the same way C is. Clearly, good software has been written in C that face the same challenges; PostgreSQL comes to mind, but I've read the PostgreSQL code, and while it's clean, I don't find it that readable or nice. Those guys work with C's limitations, of course, and that's fine. One specific example here is matching structures. I look at Haskell and Scala with envy, because you can do things like this (pseudocode!): match expr {
Or(p, And(q, r)) => And(Or(p, q), Or(p, r))
}
Similarly, writing graph-traversal (walking and transformation) logic in Go is painful. Go doesn't have sum types, so you have to dick around with interfaces (which weren't meant for this) and write big table-driven tests to ensure that all your matching cases is exhaustive.There's a lot of boilerplate, and there are times where I've been tempted to write code generators that use small DSLs that let me express everything in a higher-level way. But I've not taken that step yet. If I'd started this particular project today, the choice would have been Rust or C++. This applies to future project that smell like something that'd need this kind of expressiveness. Another area where Go disappoints is how surprisingly hard it is to write good concurrent programs that need to distribute work and handle errors in a resilient manner. Your actual logic — the meat of your program — quickly becomes obscured by error handling, ErrGroups, channel orchestration, inelegant wrapper structs, managing the lifecycle of resources (sockets and files and what not) and, ugh, contexts. Context is like a virus that morphs code into refactoring monsters every time you start weaving it through your application. I get Erlang envy when I need to do even the simplest thing, like coordinate the concurrent importing of chunks of data that is distributed to a dynamically growing/shrinking pool of worker goroutines. With all the bragging about modern CSP, Go provides nothing that can compete with Erlang supervisors, which is mightily strange for a (relatively speaking) new language supposedly invented for writing resilient networked systems. |