Advanced everything in Backend Dev, page 11
Hashing Data with Node.js's `crypto` Module
Hashing creates a unique, fixed-size fingerprint of data. It's a one-way process used to verify data integrity or store passwords securely without saving the plain text. The footgun is using weak algorithms like MD5 or SHA1 for security-sensitive tasks.

Top-Level Await: `await` Without an `async` Function
Top-level await lets you use await directly in an ES module, no async function needed. Use it to initialize resources like database connections on startup. The footgun: the entire module's execution blocks until the promise resolves, delaying startup.

Promise.any(): Get the Fastest Successful Result
Promise.any() is a race where only finishers count. It returns the value of the first promise to succeed, ignoring any that fail. Use it to query redundant endpoints and take the first successful response.

Promise.allSettled(): Never Fail a Batch of Promises
Promise.allSettled() waits for every promise in a set to finish, success or fail, without short-circuiting. Use it for independent tasks, like multiple API calls, where you need the outcome of each.

Promise.race(): First Promise to Settle Wins
Promise.race() returns a promise that mirrors the outcome of the first promise in a set to finish—the winner takes all, whether it resolves or rejects. Use it to set a timeout on a network request.

NPM Scopes: Namespacing Packages to Avoid Collisions
NPM scopes act like a personal folder for your packages, using the @scope/package format to avoid name collisions. They are essential for publishing private packages for your team or grouping related public ones.
Node.js Circular Dependencies: The Unfinished Export
When module A requires B, and B requires A, Node.js avoids an infinite loop by returning an unfinished version of one module's exports. This happens in complex apps with tightly coupled modules. The code doesn't crash; it fails later with a TypeError.
Node.js Cluster: Scaling on a Single Machine
The cluster module turns a single-threaded Node.js app into a multi-process server that uses all CPU cores. It's ideal for scaling network applications on one machine by sharing a single port.
Worker Threads: True Parallelism in Node.js
Worker threads give Node.js a separate brain for heavy lifting, letting you run CPU-intensive code without blocking the main event loop. Use them for tasks like image processing, not I/O. The footgun is assuming memory is shared; it isn't.
Libuv: The Engine Behind Node.js Async I/O
Libuv is the C library that powers Node.js's non-blocking I/O. It translates JavaScript's event loop into high-performance async calls for the host OS. The footgun is thinking this makes Node multi-threaded; it uses an event loop and a thread pool.
Daemonizing Go/Rust Apps: Let the OS Do It
Daemonizing an app means running it as a background service, detached from your terminal. This is essential for web servers or job processors. The common footgun is writing custom daemon logic instead of using a system service manager like systemd.
The FromRequest Trait: Consuming Request Bodies in Axum
Axum's FromRequest trait defines how to create a type by consuming an HTTP request body. It's the core of extractors like Json<T> that deserialize POST data. The footgun: you can only use one FromRequest extractor per handler, as it consumes the body.
Rust's Tower Service: One Trait for Clients, Servers, and Middleware
Tower's Service trait is a universal API for async requests. It models any 'request -> future<response>' flow, unifying clients, servers, and middleware. Use it for HTTP servers or database clients. The footgun: ignoring poll_ready bypasses backpressure.
cbindgen: Auto-generate C/C++ Headers for Rust
cbindgen automatically generates C/C++ headers for your Rust code, saving you from writing tedious FFI boilerplate. Use it when exposing a Rust library to other languages. Its feature set is ad-hoc, so it may not support your specific edge case out of the box.
Rust's `bindgen`: Auto-Generate FFI to C/C++
bindgen is a translator that reads C/C++ headers and writes the unsafe Rust FFI code to call them. It's used to integrate Rust with existing C libraries, like system APIs or legacy code, saving you from writing bindings by hand.
Go Assembly: A Semi-Abstract Instruction Set
Go's assembler isn't a direct mapping to machine code; it's a semi-abstract instruction set. A MOV might become a clear or load. This is what you see with go tool compile -S. The footgun is assuming your assembly maps 1:1 to the final machine code.
Rust's Pin: Fixing a Value's Memory Address
Pin<P> tells the Rust compiler a value must not move from its memory location. Think of it as nailing an object to a specific spot on the memory shelf. This is crucial for self-referential types, like those in async runtimes.
Rust Const Generics: Parameterize by Value, Not Just Type
Const generics let Rust types be parameterized by values, not just other types. This allows writing code generic over array sizes, like Matrix<T, const N: usize>, ensuring dimensions are checked at compile time.
Rust Procedural Macros: Code That Writes Code
Procedural macros are compile-time functions that write Rust code for you. They power common patterns like Serde's #[derive(Serialize)]. The main footgun is hygiene: generated code can clash with local variables, so authors must use absolute paths to be…
Go Execution Tracer: Pinpointing Concurrency Bottlenecks
Go's Execution Tracer creates a visual timeline of your program, capturing goroutine state changes, syscalls, and GC events. It's essential for diagnosing subtle concurrency issues like lock contention. The main footgun is misusing annotations for work.
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