Intermediate concepts in Backend Dev, page 3

Promise .catch(): Handling Rejections
.catch() is the try...catch for promises, intercepting errors (rejections) in a chain. Use it at the end of a promise chain to handle failures from preceding steps, like a failed API call. The footgun: placing it mid-chain can swallow errors.
Node.js util.promisify: From Callbacks to Promises
util.promisify converts callback-based functions into Promise-based ones, letting you use async/await with older Node.js APIs. It's a bridge for legacy code following the standard (err, value) callback pattern. The footgun: it fails on non-standard signatures.
Rust Slices (&[T]): Views Without Ownership
A Rust slice is a borrowed view into a contiguous sequence of data, like an array or Vec, without taking ownership. Use it to write functions that operate on parts of a collection efficiently. The footgun: a slice cannot outlive the data it points to.
Two-Phase Locking (2PL): Preventing Database Race Conditions
2PL is a database's pessimistic strategy for safe concurrency. A transaction acquires all necessary locks before releasing any, ensuring operations don't clash. It's used to guarantee consistency.

Nested Pydantic Models: Composing Complex Data
Use a Pydantic model as a field type inside another to build complex, nested structures. This is essential for modeling JSON with sub-objects, like a user with an address.

Async/Await: Write Non-Blocking Code That Reads Synchronously
async/await lets you write non-blocking code that reads like simple, synchronous logic. It's used for network requests or database queries without freezing your app. The biggest footgun is using await inside a function you forgot to declare as async.
Rust's Two String Types: String vs. &str
Think of String as an owned, growable text buffer on the heap, while &str is a borrowed, fixed-size view into string data. This distinction is key to Rust's memory safety. Functions often take &str to flexibly accept both types.

Database Deadlock: The Two-Way Standoff
A deadlock is a 'Mexican standoff' where two transactions can't finish because each is waiting for a resource the other has locked. This happens in systems with concurrent writes. The database will kill one transaction, forcing your app to handle the retry.

Pydantic's Data Coercion: From Raw Data to Python Types
Pydantic automatically converts raw data, like strings from a JSON request, into the Python types you declare. It's how FastAPI turns a JSON body into a typed Python object.
Rust Enums: Attaching Data Directly to Variants
A Rust enum variant can carry its own data, acting like a mini-struct. This is perfect for modeling states with different payloads, like a Result that holds either a value or an error. The footgun is using a separate struct to pair an enum with.

MVCC: Read and Write Data Without Blocking Each Other
MVCC avoids slow, traditional locks by giving each transaction its own consistent data snapshot. This allows readers and writers to work at the same time without blocking each other, boosting performance in databases like PostgreSQL.

Pydantic: Configuring Models with `model_config`
Think of model_config as the settings panel for your Pydantic models, letting you change validation rules like string length or immutability. Use it to enforce global constraints or make models immutable. The footgun is using the old class Config: from V1.

Promise.all(): Wait for Multiple Promises at Once
Promise.all() runs multiple promises in parallel, resolving only when all have succeeded. It's for when you need data from several API endpoints to render a single component.
Strict Two-Phase Locking (S2PL): Safety Over Speed
Strict Two-Phase Locking (S2PL) forces a transaction to hold all its locks until it fully commits or aborts. This prevents cascading aborts in databases but at the cost of concurrency, as other transactions are blocked for longer periods.
The Query Optimizer: Your Database's Internal GPS
A query optimizer is your database's internal GPS, turning your SQL "what" into the fastest "how." It chooses the best execution plan—like join order or index usage—for every query. The footgun: stale statistics can trick it into picking a slow route.
Rust Item Visibility: Private by Default
In Rust, all items are private by default. Think of modules as locked rooms; you need the pub keyword to unlock the door. This is crucial for creating a public API or letting modules interact.
FastAPI: Use UploadFile for Efficient File Uploads
FastAPI handles file uploads as 'form data', giving you a streamable UploadFile object instead of a raw byte blob. Use this for endpoints like image or document submissions. The footgun is reading large files into memory instead of streaming them.
path.join() vs. path.resolve(): Concatenation vs. Calculation
path.join() glues path segments together, while path.resolve() calculates an absolute path. Think string building vs. cd commands. Use join for relative paths and resolve for absolute ones.
Composite Indexes: One Index for Multiple Columns
A composite index is like a phone book sorted by last name, then first name. It's for queries filtering on multiple columns, like finding a specific person. The footgun is creating separate indexes, which is far less efficient than a single composite one.
Rust Methods: Attaching Behavior to Data
Rust methods are functions attached to your data structures, defined in an impl block. Instead of do_thing(my_struct), you call my_struct.do_thing(). The key footgun: instance.name() calls a method, but instance.name accesses a field.
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