(Like this article? Read more Wednesday Wisdom!)
For some reasons best left undiscussed I am coding Rust at the moment. Fortunately, I am not a total stranger to Rust, having introduced it to my team at Facebook a few years ago. At that time we were drowning in a fiery pit of Python and there was a desperate need for some strong-typing sanity and decent asynchronous performance. To combat this, I reviewed all the options available and settled on Rust as the best choice. To be honest, I thought Go was technically the better choice, but, as I wrote before, you don’t choose a language, you choose an ecosystem, and Rust clearly had/has the better ecosystem inside Facebook.
Rust is a fantastic language but it is not for the timid. It is the only language I know that has a deep concept of ownership of memory and therefore it is able to track who is owning what and whether there is a chance of memory leaks or referring to memory that is no longer owned by you. Because of this it doesn’t need a garbage collector as it has 20/20 vision into what memory is still in scope. All of this wreaks havoc on ye olden coding patterns, which makes Rust hard to learn because (in my case) years of coding assembler and C left me with patterns and practices that are unsafe and that only (mostly) work because of implementation details that are not guaranteed. I recently got another taste of that when I recompiled an old C codebase of mine using the address sanitizer. I immediately found dozens of bugs, most of which were large enough to drive a dump truck through.
When I started coding Rust I once spent days fighting with the borrow checker which insisted that some data I thought I had a pointer to was really no longer mine to do with what I pleased. After countless hours of debugging, reading, thinking, and hacking, I finally found that there was one particular scenario where I gave the data to someone who then took ownership of it. Coincidentally, something more or less similar happened to me today when I got a pointer to some data in a struct that sat at the end of a vector. In some branches, my code would pop that last element off of the vector, but then tried to construct a log message using that very same pointer, which by now pointed inside a removed element. The Rust compiler helpfully refused to compile that code, explaining to me that that reference was no longer valid.
How cool is that!
As a consequence, getting your code to compile with Rust can be a hassle. The Rust community has done sterling work improving the compiler’s error messages, but believe me, it can still get rather arcane, especially when you start using Rust’s features for writing asynchronous code. But, and here is the good news, when your code compiles, it pretty much runs. Sure, there can still be logic errors, but no null pointer exceptions, no memory corruptions, and no crazy race conditions. Rust is not just type safe, it is memory safe!
It helps if you are using a good IDE. I am a huge fan of JetBrains IDEs and RustRover does not disappoint. Visual Studio Code with the Rust Analyzer isn’t terrible either.
All of this makes the Rust learning curve kinda steep. This makes many people complain that Rust is too hard to learn. And that is actually what I want to talk about today.
We live in a time where everything has to be easy. Math should be easy, learning foreign language is apparently easy (with the right tools), making bread can be easy, and of course coding is now easy too. It’s like a virus: Effort is out, easy is in.
Years ago I gave a talk to a room full of high school kids about why math was important. I had created a presentation that showed how some fairly basic math could be used to make an image classifier that could reliably recognize pictures of the Eiffel tower. During the Q&A section I was asked if all of this was not very hard, which I wholeheartedly agreed to. “It’s not easy”, I told them, “but it’s doable.” Then I added: “I earn six figures and that’s because I can do something that is actually hard. Nobody is going to give you lots of money for stuff that is easy.”
I thought kids might be more motivated by the economic advantages of being able to do stuff that is hard than by the mere intellectual satisfaction of that accomplishment.
I regularly hear the complaint that something is hard and it annoys the living daylights out of me. Yes, maybe, so what? Sure, things shouldn’t be harder than they need to be, but I am not in favor of making things worse just because that makes them easier to do. If there is a right way and an easy way, choose the right way! I sure don’t want the people building houses, bridges, and airplanes to start thinking of doing a crappier job because it is just too hard to do the right thing.
Boeing seems to have been doing that and we all knew how that worked out.
Here is a message to everyone who is thinking about getting into software engineering: It is hard. Programming is hard, figuring out the requirements is hard, writing correct code that is maintainable is hard, making code reliable is hard, and of course making it fast enough is really hard. It really is all very hard. If you got into this profession because of the bullish career prospects for software engineers and because someone told you that it is easy, I got news for you: The former is still true, but the latter is not. And the former is only still true if you know how to do the hard stuff.
Becoming a good software developer is hard and, importantly, that’s okay. It is a real profession that will take you decades to become really good at and you will need to learn a lot about how computers actually work, the ins and outs of networks, and many crazy algorithms. On top of that you will need to learn how to communicate effectively, work in teams, write a halfway decent document, create a project plan, and execute against a deadline. It’s really not a 12-week Python course and then coasting to a comfortable retirement. But, and here is the good news, it is totally worth it; economically as well as intellectually.
It is totally fine to start your career learning Python; it is relatively easy to learn and with a little bit of knowledge you can already write simple working programs. But at the end of the day, even Python programming is hard. It might be easy to get into, but it is hard to master and that is just because there is no easy way to solve complex problems. The laws of the universe just don’t afford it.
In order to become a great software engineer you need great knowledge about a great many things, most of which are hard. So learn C++, learn Haskell, and learn Rust. Yes these languages are hard, terribly hard even, but once you master them, you are playing with power! It is worth the effort and you might even learn something that will make you get better at what you are doing today…
Loved this post. Apart from the practical aspects, there's such a satisfaction in solving something that's hard, so why should it be viewed as a bad thing?
Thanks a lot for this and for your other great posts!
This is ‘easily’ one of your better entries! Thank you, will definitely save for future reference