tezvyn:

⚙️Backend Dev

Backend engineering, APIs, and databases

1085 bites

More in Backend Dev — page 45

Go & Rust2 min read

Rust Async Runtimes: The Engine for `async/await`

Rust's `async/await` is just syntax; an async runtime like Tokio is the engine that runs the code. It polls `Future`s until they complete, managing I/O and scheduling. This is essential for web servers.

Go & Rust2 min read

Rust's async/await: Cooperative Concurrency

Rust's async/await is cooperative concurrency, where tasks explicitly yield control with `.await`. This is ideal for I/O-bound work like managing thousands of network connections. The biggest footgun: calling an `async` function without `.await` does nothing.

Go & Rust2 min read

Go Channels: Buffered vs. Unbuffered

Unbuffered channels are a synchronous rendezvous, blocking until both sender and receiver are ready. Buffered channels are an async mailbox, letting senders drop messages and go. The footgun is using a buffer to hide a deadlock instead of fixing it.

Go & Rust2 min read

Rust Channels: Thread-Safe Communication

Rust channels are like a thread-safe conveyor belt for sending data between threads. Use them to pass work to workers or aggregate results. The footgun: the receiver blocks forever if any sender isn't dropped, as the channel only closes when all senders are…

Go & Rust2 min read

Rust's std::thread::spawn: Create and Manage OS Threads

std::thread::spawn creates a new OS thread to run code concurrently, returning a JoinHandle to wait for completion. Use it for background tasks or parallel computations. The footgun: dropping the handle detaches the thread, risking resource leaks.

Go & Rust2 min read

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.

Go & Rust2 min read

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.

Go & Rust2 min read

Rust's `impl Trait`: Hiding Concrete Types

Rust's `impl Trait` specifies a type by its behavior, not its name. Use it in function arguments for cleaner generics (`fn f(x: impl Debug)`) or in return types to hide complex types like closures and iterators, avoiding heap allocation.

Go & Rust2 min read

Static Dispatch: Zero-Cost Abstraction via Monomorphization

Static dispatch resolves function calls at compile time, avoiding runtime overhead. Rust does this via monomorphization, creating specialized code for each concrete type. This is the default for generics, but the trade-off is larger binary sizes.

Go & Rust2 min read

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.

Go & Rust2 min read

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 & Rust2 min read

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.

Go & Rust2 min read

Result: Handling Recoverable Errors in Rust

Rust handles recoverable errors with the `Result<T, E>` enum, forcing you to deal with both success (`Ok`) and failure (`Err`) paths. This shows up when a function like `File::open` might fail.

Go & Rust2 min read

Rust's Question Mark Operator (?): Propagate Errors, Not Boilerplate

The `?` operator cleans up Rust error handling by propagating `Err` values. Instead of a verbose `match` block, you append `?` to a `Result` or `Option`, and it automatically returns the error if present, letting you focus on the happy path.

Go & Rust2 min read

Go Error Wrapping: Preserving Context, Not Just Text

Go's error wrapping adds context without losing the original error's type. Use `fmt.Errorf` with `%w` to create a chain of errors, then inspect it with `errors.Is` or `errors.As`. The footgun is using `%v`, which just formats the error as a string.

Go & Rust2 min read

Handling Errors with Rust's Result Enum

Rust's `Result` enum makes error handling explicit. Instead of returning a value that might be an error code, functions return either `Ok(value)` or `Err(error)`. It's used for recoverable failures like I/O.

Go & Rust2 min read

Rust's Option<T>: Handling Absence Safely

Rust's Option<T> is a type-safe box that holds either a value (Some(T)) or nothing (None), eliminating null pointer errors. Use it for function returns that might fail or for optional struct fields. The footgun is `.unwrap()`, which panics on None.

Go & Rust2 min read

Go's `error` Interface: Errors Are Values

In Go, an error is any value that can describe its own failure string. Functions like `os.Open` return an `error` to signal problems. The footgun is only checking for `nil` and ignoring the rich, structured data a custom error type can provide.

Go & Rust2 min read

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.

Go & Rust2 min read

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.