Katabench
Start free

Blog

Field notes on the fundamentals that make you a better engineer, and a look at what we're building.

AddSingleton vs AddScoped vs AddTransient: what each promises

AddSingleton vs AddScoped vs AddTransient in plain terms: what each lifetime promises, sensible defaults, and the captive dependency bug that ships.

Read more →

C# async await mistakes that pass code review

The C# async await mistakes that pass code review: async void, fire and forget tasks, missing CancellationToken plumbing, and blocking on .Result.

Read more →

Caching strategies: cache-aside, invalidation, and stampedes

Caching strategies from the cache-aside flow to the hard parts: invalidation owned by a human and stampedes tamed by single-flight and jitter.

Read more →

Code smells: a working catalog of six, with C# examples

Code smells are symptoms, not verdicts. Six worth knowing, with C# examples: the tell for each, why it hurts, and the refactoring move that clears it.

Read more →

Connection pooling: why your app ran out of connections

Connection pooling explained from the failure end: what a connection costs, the three ways pools drain, and why the timeout blames the wrong request.

Read more →

Cyclomatic complexity: what the number actually tells you

Cyclomatic complexity counts the independent paths through a method. How to compute it by eye, what a score of 10 predicts, and how to reduce it for real.

Read more →

.NET garbage collection explained: what gen 0, 1, and 2 cost

.NET garbage collection explained: why most objects die young, what gen 0, 1, and 2 collections cost, and why the large object heap hurts latency.

Read more →

How do database indexes work? B-trees, page by page

How do database indexes work? A B-tree is a small sorted structure with huge fanout, so a lookup reads a handful of pages instead of the whole table.

Read more →

Idempotency in API design: surviving the retry you didn't send

Every serious client retries. How the idempotency key pattern and a database unique constraint keep a retried payment from becoming two charges.

Read more →

Rate limiting algorithms: how token buckets forgive bursts

Rate limiting algorithms compared: why fixed windows leak double the limit, how token buckets forgive bursts, and what a good 429 response returns.

Read more →

Unit testing best practices: test behavior, not implementation

Unit testing best practices that survive refactoring: AAA structure, behavior-first assertions, a healthy test pyramid, and determinism over flakiness.

Read more →

Primitive obsession: the bug the compiler was begging to catch

When everything is a string, a decimal, or a Guid, the type system can't tell your arguments apart. Value objects in modern C#, the bugs they delete, and when they're overkill.

Read more →

Sync over async: the .Result that works fine until the day it doesn't

Blocking on a Task with .Result or .Wait() passes every test and demos perfectly. Under real load it deadlocks old apps and starves modern ones. What actually happens and how to unwind it.

Read more →

Skip and Take will betray you: offset vs keyset pagination

OFFSET pagination reads every row it skips, so page 2,000 costs 2,000 pages of work. Keyset pagination seeks straight to the next page. The SQL, the EF Core, the trade-offs.

Read more →

The LINQ query that ran twice: multiple enumeration and other deferred-execution traps

An IEnumerable isn't a list; it's a promise to do work later. Enumerate it twice and the work happens twice, including, with EF Core, the database query.

Read more →

ReDoS: the innocent regex that can take down your API

Catastrophic backtracking turns an email regex into a denial of service: 30 characters, nearly a minute of CPU. Why nested quantifiers explode and how .NET lets you defuse them.

Read more →

Tutorial hell: why you can finish every course and still freeze at a blank file

Watching code get written trains recognition, not recall. Why tutorials feel like progress, why the skill doesn't transfer, and how to build a loop that does.

Read more →

Coding interviews are broken, but the skills they fumble are real

Whiteboard interviews measure the wrong slice of engineering. The case for practicing what predicts a good engineer: correct, fast, well-structured, secure code.

Read more →

The OWASP Top 10 through a C# lens

A practical tour of the OWASP Top 10 for .NET developers: the ASP.NET Core and EF Core patterns behind broken access control, injection, SSRF, and overposting.

Read more →

SQL injection is still alive, and it's hiding in your C#

SQL injection is supposedly solved, yet it's still in the OWASP Top 10. The C# patterns that keep it alive in EF Core and ADO.NET, and how to kill them.

Read more →

Architecture fitness functions: tests that fail the build when your layers rot

Architecture decays because nothing fails the build when the domain references the DbContext. Fitness functions with ArchUnitNET assert layering and dependency rules in CI like any test.

Read more →

Hexagonal architecture in .NET without the dogma

Ports and adapters explained in plain C#: domain in the center, ports as interfaces, adapters as infrastructure. Why it beats layered spaghetti, and when it is overkill for a CRUD app.

Read more →

Dependency inversion in C# is not about your DI container

The D in SOLID is the most quoted and least applied principle. Dependency inversion means depending on abstractions you own and pointing dependencies inward, not registering services.

Read more →

A test-first playbook for refactoring legacy C# safely

How to refactor legacy C# without breaking it: write characterization tests first, then take small behavior-preserving steps (extract method, introduce a seam, replace conditional with polymorphism).

Read more →

Green checkmarks lie: why we grade C# on performance

Every practice platform tells you your O(n²) solution is correct. None of them tell you it's bad. Here's why we built grading that fails you on performance, and why that makes you better.

Read more →

Clean code is a vibe until you measure it

Four code quality metrics you can actually automate in C#: cyclomatic complexity, nesting depth, method length, and duplication, with reasonable thresholds and a refactor that passes them.

Read more →

EF Core habits that quietly wreck performance

Nine EF Core habits that pass every test and quietly tank performance in production: missing AsNoTracking, fetching whole entities, N+1, cartesian explosion, counting in memory, and more.

Read more →

Your LINQ is fast; your query plan isn't

A perfectly written EF Core query can still do a sequential scan: no index, or a function on a column makes it non-sargable. How to read a query plan and fix it.

Read more →

IQueryable vs IEnumerable: the one return type that decides where your query runs

Returning IEnumerable, or calling ToList too early, moves filtering and paging into C# memory. How one type change turns an indexed WHERE into loading a million rows.

Read more →

The N+1 query problem in EF Core: the most expensive habit in .NET

An EF Core loop that looks innocent fires one query per row. It passes every unit test and dies in production. How N+1 happens, the SQL it generates, and the fix.

Read more →

Deliberate practice for programmers: why a green check isn't feedback

Repetition doesn't make you better; deliberate practice does. It needs immediate, specific feedback at the edge of your ability, and most coding practice fails that test badly.

Read more →

How senior .NET engineers actually keep their edge

It isn't grinding more LeetCode for correctness. Seniors practice the things production grades: performance, data-access shape, design, and security. Here's the difference.

Read more →

The premature optimization myth: what Knuth actually said

The most-abused quote in software lets developers dodge thinking about performance entirely. Here's Knuth's real argument, and why finding the 3% requires an instinct you have to train.

Read more →

Span<T>, Memory<T>, and stackalloc: when zero-allocation C# is worth it

Span<T> and stackalloc let you parse and slice without allocating, but they have real limits. Here's when zero-allocation C# earns its keep and when it's overkill.

Read more →

The allocation tax: why correct, O(n) C# can still be slow

In .NET, correct and algorithmically optimal code can still drag, because every needless allocation feeds the GC. Here's how to spot and cut allocation pressure in C#.

Read more →

Big-O isn't interview trivia: where complexity actually bites in production

Big-O gets crammed for interviews and forgotten. But quadratic C# passes your tests and melts in prod. Here's where it bites and how to make complexity an instinct.

Read more →

Get new puzzles and .NET tips in your inbox

A short note when fresh kata land, plus the C# and performance tricks behind the grading. No spam, unsubscribe anytime.