I love this description of the Go programming language from Rob Napier:
Go feels under-engineered because it only solves real problems. If you've ever worked in a wood shop, you've probably made a jig at some point. They're little pieces of wood that help you hold plywood while you cut it, or spacers that tell you where to put the guide bar for a specific tool, or hold-downs that keep a board in place while you're working on it. They're not always pretty. They often solve hyper-specific problems and work only with your specific tools. And when you look at ones that have been used a lot, they sometimes seem a little weird. There might be a random cutout in the middle. Or some little piece that sticks off at an angle. Or the corner might be missing a piece. And when you compare them to “real” tools, “general” tools like you'd buy from a catalog, they're pretty homey or homely depending on how you're thinking about it.
But when you use one of them in your shop, you learn that the random cutout is because you store it against the wall and it would block the light switch otherwise. And if you put your hand on that little extra piece that sticks out, then the board won't fall at the end of the cut. And the corner… well the corner is where you messed up when you were first making it and it's kind of ugly, but it never actually matters when you use it. And that's Go.
A few years ago I taught myself some Go. Not because I needed it but because I like poking around other ecosystems. I came across Go By Example, and it's still is one of my favorite formats to explore a new language or framework.
The examples are succinct and introduce you to a concept without overwhelming you. This format will not turn into an expert, but is just enough to get you curious and kickstart your own explorations.
I've learned a little Go myself but don't know enough about Rust to understand when you'd choose one over the other. Vercel is currently migrating a codebase from Go to Rust, it's interesting to read the reasoning behind the decision.
Go's preference for simplicity at the filesystem was creating problems for us when it came to file permissions. Go lets users set a Unix-style file permission code: a short number that describes who can read, write, or execute a file.
While this sounds convenient, this abstraction does not work across platforms; Windows actually doesn't have the precise concept of file permissions. Go ends up allowing us to set a file permission code on Windows, even when doing so will have no effect.
In contrast, Rust's explicitness in this area not only made things simpler for us but also more correct. If you want to set a file permission code in Rust, you have to explicitly annotate the code as Unix-only. If you don't, the code won't even compile on Windows. This surfacing of complexity helps us understand what our code is doing before we ever ship our software to users.
Next to PHP, Go is a low-level language—but Rust is even lower. Looks like Go is great for heavy lifting on the web, but if you're into building tools to run in different environments Rust is where you want to be.
I enjoyed Mohamed's post on using PHP and Go to have the best of both worlds.
By employing a polyglot architecture, we get the best of both worlds. PHP provides the development speed required to compete in a hyper-growth market, while Go provides more efficient resource utilization.
Another good quote from the introduction of his PHP to Go course:
PHP may be slow and memory hungry when compared to a compiled language, but that's not a result of a bad design.
It's like this by design because of all the choices it makes on your behalf to conceal complexity.
I also recommend his post on Twitter about the business decisions behind cutting costs on infrastructure.