Skip to main content
CodeOath
← All posts

Architecture & Patterns110 min total · 26 parts

ACID, SOLID, and Design Patterns: A Complete Software Design Reference

Part 26 of 26 · ~3 min

Common Mistakes and Interview Traps

  • Treating ACID's Consistency as a stand-in for "the numbers mean what we meant." It only enforces what the schema actually declared as a rule — a transaction can sail through every constraint check and still be a logically bad decision, like a three-hour hold nothing in the schema forbids.
  • Reaching for Serializable by default because it sounds safest. It's the only level that blocks every anomaly in the table earlier in this reference, and it buys that by making transactions queue behind each other far more than most workloads can actually afford. The right level is the cheapest one still safe for what a given operation does — and that floor is lower than people assume, and different per engine (InnoDB defaults to Repeatable Read, not Read Committed).
  • Firing off related writes as separate statements instead of wrapping them in one transaction. This is where atomicity actually goes missing in production code, nearly every time — people understand the guarantee fine once they're inside a transaction, they just forget to open one before the writes that needed it.
  • Assuming LSP is satisfied once the code compiles. LockedShift : Shift compiles without complaint — the violation only shows up at runtime, the moment code written against Shift assumes every Shift can be safely rescheduled.
  • Using "Dependency Inversion," "Dependency Injection," and "the DI container" as if they were three names for one thing. They're a principle, a technique, and a piece of tooling respectively — and the principle holds even in a codebase with no container at all, as long as constructors ask for interfaces instead of building concrete classes themselves.
  • Defaulting to the Singleton pattern for anything that merely feels application-wide. A container-managed singleton registration delivers the identical one-instance guarantee without the hidden global access point, and it's the better default in nearly every case.
  • Reaching for a deeper subclass tree the moment a second kind of variation shows up. Two independent axes of behavior are exactly the situation composition — Strategy, Decorator, either one — handles cleanly, and inheritance handles only by multiplying subclasses.
  • Wiring up an Observer subscription and never tearing it down. A subject that outlives the thing listening to it keeps that listener pinned in memory indefinitely, with no exception anywhere to flag it — just a dashboard that should have been garbage collected quietly still receiving events.
  • Assuming Clone() fully detaches a copy from its original. Unless the clone method explicitly rebuilds every reference-type field — a skills list, anything nested — the "copy" is still quietly sharing that data with whatever it was cloned from.
  • Writing a Chain of Responsibility with no terminal case. A request that falls off the end of the chain with no default handler doesn't raise an error — it just silently resolves to nothing, a far harder bug to notice than a thrown exception would be.
  • Reaching for Visitor without weighing what it costs. It makes new operations cheap and new element types expensive — the wrong trade when the type list is still the side actively growing.

Curious how the constraints and locking behavior from Part 1 show up once you're actually writing queries against them? SQL Fundamentals: Joins, NULL, Aggregate Functions, and Subqueries and Understanding SQL Indexes and Query Performance go a level deeper on that end of things. And for hands-on practice naming a principle violation or a pattern on sight — a batch of "what's broken here" scenarios included — head to the code lab.