Comment by atombender
19 hours ago
So you used Go once, briefly, and yet you feel competent to pass this judgement so easily?
As someone who's been doing Go since 2015, working on dozens of large codebases counting probably a million lines total, across multiple teams, your criticisms do not ring true.
Go is no worse than C when it comes to extensibility, or C# or Java for that matter. Go programs are only extensible to the extent (ha) developers design their codebases right. Certainly, Go trades expressivity for explicitness more than some languages. You're encouraged to have fewer layers of abstraction and be more concrete and explicit. But in no way does that impede being able to extend code. The ability to write modular, extensible programs is a skill that must be learned, not something a programming language gives you for free.
It sounds like you worked on a poorly constructed codebase and assumed it was Go's fault.
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.