“Declaring a feature that’s in customers’ hands “done,” without monitoring, or with flaky tests, or tons of highly redundant code, or other obvious pending work, doesn’t magically get that work done. That work will always be there. It’ll just show up as surprises in your Maintenance Roadmap at an unknown date, when your team has mentally moved on and stopped thinking about the feature.”

Finish things, do them properly. Make problems go away.


Highlights for Rust for Rustaceans

For example, there cannot be two parallel flows with mutable access to a value. Nor can there be a flow that borrows a value while there is no flow that owns the value.
Freeing the memory twice could have catastrophic consequences.
If you just want to leave some valid value behind, std::mem::take 2 is a good candidate. It is equivalent to std::mem::replace(&mut value, Default::default()); it moves value out from behind the mutable reference but leaves a new, default value for the type in its place.
but as we dive deeper into the more complex parts of Rust, you will need a more rigorous mental model to work with.
The aim of this chapter has been to establish a solid, shared foundation that we can build on in the chapters to come.
False sharing occurs when two different CPUs access different values that happen to share a cache line; while they can theoretically operate in parallel, they both end up contending to update the same single entry in the cache.
Simply stated, the orphan rule says that you can implement a trait for a type only if the trait or the type is local to your crate.
For example, consider a type like SshConnection, which may or may not have been authenticated yet. You could add a generic type argument to SshConnection and then create two marker types: Unauthenticated and Authenticated. When the user first connects, they get SshConnection. In its impl block, you provide only a single method: connect. The connect method returns a SshConnection, and it’s only in that impl block that you provide the remaining methods for running commands and such.
you can see the building blocks in the RawWakerVTable type in the standard library.
In a way, unsafe is misleading as a keyword when it is used to allow unsafe operations through unsafe {}; it’s not that the contained code is unsafe, it’s that the code is allowed to perform otherwise unsafe operations because in this particular context, those operations are safe.
In practice, the safety and performance trade-off for unchecked methods is rarely worth it. As always with performance optimization, measure first, then optimize.
and then document them rigorously.
Not all code is written in Rust. It’s shocking, I know.
Instead, as shown in Listing 3-2, we can introduce a generic parameter on Rocket, Stage, and use it to restrict what methods are available when.
Rust Fuzz Book (https://rust-fuzz.github.io/book/)
Rust Cookbook (https://rust-lang-nursery.github.io/rust-cookbook/), which suggests idiomatic so
the Tokio project has published mini-redis (https://github.com/tokio-rs/mini-redis/), an incomplete but idiomatic implementation of a Redis client and server that’s extr
Philipp Oppermann’s Writing an OS in Rust (https://os.phil-opp.com/) goes through the whole operating system stack in great detail while teaching you good Rust patterns in the process. I also highly recommend Amos’s collection of articles (https://fasterthanli.me/tags/rust/) if you want a wide sampling of interesting deep dives written in a conversational styl

Learning about Rust types and dynamic dispatch

So I had some code very similar to the following that wouldn’t compile and me with my old Python head was a bit surprised why this was the case. It was a bit more complicated to figure it out in my example but this simplified version makes it pretty clear.

trait SomeTrait {}

impl SomeTrait for u8 {}
impl SomeTrait for u16 {}

fn function() -> impl SomeTrait {
    if true {
    } else {

Why did I think it would work? Because both types implement the same trait, it’ll come down to the same thing in the end and that should be fine, right? I think that’s Python talking.

The Rust compiler needs to know how much space every function’s return type requires. 


Let’s think about it from a Rust perspective which means think about the memory layout of this. We’re on the stack here and in this case it may only be a difference of a byte, it’s very possible to have two vastly different types implement the same trait. That can’t possibly work.

The answer then of course is to:
1. Move things into the heap with `Box. That doesn’t fully solve it because then both arms have a different type Box<u8> and Box<u16> respectively. But crucially now they’re always the same size.
2. Change the return type to a trait object that both types conform to with dyn.

trait SomeTrait {}

impl SomeTrait for u8 {}
impl SomeTrait for u16 {}

fn function() -> Box<dyn SomeTrait> {
    if true {
    } else {

This works and is dispatched dynamically.

Thanks by the way to the people in the Tokio Discord for being extremely patient with me.

I agree with this take by Jacob Kaplan-Moss that you should be able to estimate very accurately and then just not do it most of the time. Learning how to estimate is a non-negotiable part of building an intuition for software engineering. It’s not the estimation that we need, it’s the intuition.

The other reason why we wouldn’t do it all the time is because estimation (AND tracking, oftentimes people estimate without a tracking mechanism) has a real cost attached to it both to the team doing the estimations and to the org as a whole. Relying on estimations makes the entire organization less agile.

The follow-up post has a bunch of ways how you can estimate better but it doesn’t reference my preferred one: critical chain


That’s a very astute observation of the state and culture of the Go programming language. I got out of Go way before I hit anything like this (though the Channel Axioms are something everybody is going to deal with). For me Go is a not very interesting intermediary language between Python and Rust.

In particular the crude simplicity is something that I always found suspect. It’s the same you would hear from PHP programmers, “It works, doesn’t it?” If getting something to work is such a feat that you can’t or won’t consider anything more than that, that’s not an environment I want to work in.