Advanced everything in Backend Dev, page 12
Rust Build Scripts: Compiling More Than Just Rust
A build.rs script is a pre-compilation hook for tasks outside Rust's scope, like compiling C code or generating Rust modules. It's essential for FFI or code generation. A key footgun: cfg! checks the host, not the target, breaking cross-compilation.
Rust's Scoped Threads: Borrowing Across Threads Safely
Scoped threads let you borrow local variables from a parent thread without complex wrappers. The scope guarantees all spawned threads are joined before it exits, satisfying the borrow checker. Use it to parallelize work on stack data.
Go's Memory Model: Don't Be Clever
Go guarantees your program behaves predictably—as if on one CPU—if you prevent data races. Use channels or sync primitives to serialize access when goroutines share data. The footgun is relying on timing instead of explicit synchronization.
Send vs. Sync: Rust's Thread Safety Contracts
Send means a value can move to another thread; Sync means references to it can be shared. They are the compiler's contracts for preventing data races. The compiler checks them when you spawn threads.
Rust Marker Traits: Properties as Types
Marker traits are empty labels telling the Rust compiler about a type's capabilities, like being copyable or thread-safe. They have no methods; their presence is the signal. They're key for concurrency (Send/Sync) and memory (Copy/Sized) safety checks.
Rust Associated Types: One Trait, One Concrete Type
Associated types link a placeholder type to a trait, ensuring any implementation provides one specific type. This cleans up code, like in Rust's Iterator trait. The footgun: a type can only implement a trait with an associated type once.
Composable Error Types with `thiserror` in Rust
thiserror generates boilerplate for custom Rust error types, letting you define specific, matchable errors for a library. Use it when callers need to handle different failure modes. The footgun is using it for simple app errors where anyhow would suffice.
Rust's `panic!`: When to Crash Your Program Intentionally
Rust's panic! is an emergency stop for unrecoverable bugs, intentionally crashing the current thread. It's for impossible states where continuing is dangerous, not for recoverable errors like failed I/O—use Result for that.
Go's Panic/Recover: For Exceptional Errors Only
Go's panic/recover is a last-resort error mechanism, not a try/catch replacement. A panic unwinds a goroutine's stack until a recover in a defer'd function catches it. It's used to keep a server alive when one request fails catastrophically.
Rust's NLL: Smarter Borrows Based on Use, Not Scope
Non-Lexical Lifetimes (NLL) make Rust's borrow checker smarter. A borrow's lifetime ends after its last use, not at the end of its code block. This allows modifying data after a borrow is finished, even if the reference variable is still in scope.
Rust's Interior Mutability: Mutating 'Immutable' Data
Interior mutability lets you modify data through an immutable reference, moving Rust's borrow checks from compile-time to runtime. It's used in single-threaded code when the compiler can't verify safe access.
Go's GC: Low-Latency Collection with Tri-color Marking
Go's GC uses a tri-color algorithm to find unused memory concurrently, avoiding long pauses. It's crucial for low-latency services. The main footgun is breaking the invariant: a 'finished' (black) object must never point to a new (white) one without notifying…
Rust Cargo Workspaces: A Monorepo Control Panel
A Cargo Workspace is a control panel for a multi-crate Rust project, unifying dependencies and build artifacts. Use it for related binaries and libraries to ensure consistent builds.
Go's `internal` Directory: Private by Convention
Go's internal directory creates private packages within your module, making them inaccessible to external projects. Use it for helper logic you don't want to support as a public API.
Rust's Arc<T>: Share Data Ownership Across Threads
Rust's Arc<T> lets multiple threads share ownership of heap data. It's a smart pointer that counts references atomically. Use it for shared caches or config. The footgun: Arc only makes sharing safe, not mutation—you still need a Mutex for that.
Rust's Rc<T>: Shared Ownership on a Single Thread
Rust's Rc<T> enables shared ownership within a single thread. Think of it as a counter on a heap-allocated resource: cloning an Rc increments the count, and the resource is freed only when the count hits zero. Use it for graph nodes with multiple owners.
Go's sync.Map: A Specialized Concurrent Map
Go's sync.Map is a concurrent map optimized for keys written once and read many times. It's ideal for long-lived caches, but it's not a generic replacement for a map with a mutex. The footgun is using it for frequent writes, which can be slower.
Using Box<T> for Heap Allocation in Rust
Rust's Box<T> is a smart pointer that moves data from the stack to the heap. It's essential for creating recursive types, like linked lists, whose size would otherwise be infinite. The main footgun is in FFI: never wrap a C-allocated pointer in a Box.
Rust's Turbofish (`::<>`): When the Compiler Needs Help
The turbofish (::<>) is your tool to resolve ambiguity when Rust's compiler can't infer a type or trait. Use it when a type implements multiple traits with same-named methods, forcing the compiler to pick the one you specify.
Zero-Cost Abstractions: Pay at Compile Time, Not Runtime
Zero-cost abstractions let you write high-level code that compiles to the same machine code as low-level optimizations. This is key in Rust for safe APIs without runtime overhead.
We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.
See open roles