Comment by jact
8 hours ago
It certainly isn’t impossible to write good code in Go. Perhaps the code base I was working on was bad — it didn’t seem obvious to me that it was. Go is not a bad language in the way that brainfuck is a bad language.
I think Java and C# offer clearly more straightforward ways to extend and modify existing code. Maybe the primary ways extension in Java and C# works are not quite the right ones for every situation.
The primary skill necessary to write modular code is first knowing what the modular interfaces is and second being able to implement it in a clean fashion. Go does offer a form of interfaces. But precisely because it encourages you to be highly explicit and avoid abstraction, it can make it difficult for you to implement the right abstraction and therefore complicate the modular interfaces.
Programming is hard. I don’t think adopting a kind of ascetic language like Go makes programming easier overall. Maybe it’s harder to be an architecture astronaut in Go, but only by eliminating entire classes of abstraction that are sometimes just necessary. Sometimes, inheritance is the right abstraction. Sometimes, you really need highly generic and polymorphic code (see some of the other comments for issues with Go’s implementation of generics).
I've worked with Java, C#, C++, etc., and I find that for all its faults, Go's minimalism strikes a balance between abstraction and concreteness that works just fine.
In practice, I've never struggled to write modular, extensible software. Like in any language you have to think about the boundaries between modules and layers, and how to design the interfaces between them to avoid spaghetti soup. It's not more difficult in Go, just different. Java's OO approach kind of inextricably pulls you towards AbstractSingletonProxyFactoryBean situations that just feel wrong to replicate in Go. A lot of the "performative" software structure kind of falls away and you end up with very concrete, readable code.
Go is often derided for being "too simple", but I think this kind of simplicity is underrated in our industry. I'm a fan of the Niklaus Wirth approach to software development. Go is basically a reskinned Modula 2 with GC and concurrency, and that it's the Wirth influence that drives its core design.
To be clear, Go is chock full of warts and faults, some of them quite egregious. But they're mostly about the practical aspects of the language (invasive error handling, lack of sum types and pattern matching, the badness of channels) that don't really relate to what you're talking about.