Rust’s Flexibility vs. Go’s Simplicity
Many programming languages offer immense flexibility, but this often leads to a wide variety of solutions. Frequently, it’s frameworks that provide the necessary structure for productive, efficient, and maintainable teamwork. This is precisely why I still find Go brilliant after all these years—its idiomatic guidelines leave little room for interpretation. The language is so simple that there’s hardly any ambiguity. With just a lightweight set of conventions (or even none at all), you can achieve excellent results.
When I dove into Rust in 2021—my second attempt—I discovered many exciting aspects. The toolchain had improved significantly, and I spent months exploring the language in depth. The experience was so positive that I wanted to integrate Rust into more projects. However, unlike Go’s clear conventions, Rust presented a vast landscape of possibilities. Searching for well-defined rules, I realized they seemed almost nonexistent. The prevailing attitude appeared to be that “working code is good enough.”
The acceptance of different coding styles within the same project clashed with my preference for structure. The idea that any functioning Rust code is inherently superior didn’t convince me. Rust began to feel overly intrusive, so I scaled back my efforts for a while.
After some time away, I revisited Rust with fresh eyes. Many of its fundamentals didn’t bother me as much as I’d thought. The biggest hurdle, ironically, was the community. While enthusiasm is great, the zeal to “convert” everyone wasn’t for me. Learning to tune that out helped immensely—and perhaps things have calmed down a bit since then.
Another challenge was meta-programming with macros. Not only are there multiple kinds, but you also need to learn a separate syntax for them. Experienced Rust developers’ advice on idiomatic usage was often unclear, leaving me unsure about best practices.
Finally, Rust lacks a clear stance on imperative versus functional programming. I’ve seen countless convoluted iterator chains that added unnecessary complexity—contrary to my preference for simplicity. While iterators are powerful, they’re often overused, partly due to the celebrated “zero-cost abstraction” principle. The assumption is that such abstractions compile to code as efficient as hand-written alternatives, but in reality, they can sometimes incur hidden costs. Blindly trusting this claim is a mistake.
Now, as I give Rust a third chance, I’m defining my own idiomatic approach: using features purposefully to highlight the language’s strengths—like memory safety and performance—while deliberately ignoring certain options to reduce unnecessary variety. After all, I believe Go’s success stems from its simplicity. By applying a similar philosophy to Rust, I aim to make the language work for me.