Press enter or click to view image in full size
For a long time, I assumed that good software engineering mostly meant writing, testing, and reviewing code. If I was not actively implementing a feature, a refactor, or a new component, it felt like I was falling behind. Spending too much time thinking instead of building made me uneasy, even when the questions I kept circling around did not go away just because I ignored them.
That discomfort followed me through much of my career.
I have spent a large part of it working with PostgreSQL as a database engineer. Migrations, replication, backups, performance tuning, and systems where being almost right is usually worse than being obviously wrong. Over time, that kind of work quietly changes how you think. You stop asking only whether something works and start asking under what conditions it stops working, and what it costs when it does.
I did not consciously frame that as a mindset shift at the time. It just felt like responsibility.
What PostgreSQL Teaches You About Failure
PostgreSQL is not a forgiving system, and that is a good thing.
Migrations that look trivial can lock tables in production. Replication that seems fine most of the time can lag just enough to cause real damage. Backups that have never been restored are theoretical backups. Small schema changes can ripple through application code in ways that only show up under load.
You learn quickly that confidence is cheap and verification is not.
Working with Postgres teaches you lessons that are hard to unlearn:
- Correctness is not a property of individual changes, but of the system as a whole.
- Optimistic assumptions tend to surface at the worst possible time.
- The cost of failure is often nonlinear.
- Most problems stay quiet until they become expensive.You also learn that some of the most important work happens before anything breaks. Planning, constraints, guardrails, and rollback paths rarely look impressive, but they are what keep systems operable.
Here’s what careful migration work actually looks like:
- PostgreSQL migration with safety checks
BEGIN;
- Check table size before altering
SELECT pg_size_pretty(pg_total_relation_size('orders'));
- Add column with default (non-blocking in PG 11+)
ALTER TABLE orders ADD COLUMN status varchar(20) DEFAULT 'pending';
- Verify before commit
SELECT count(*) FROM orders WHERE status IS NULL;
- Only commit if verification passes
COMMIT;The pattern is always the same: check assumptions, make the change, verify the result, and only then commit. This becomes second nature.
Migrations and the Estimation Problem
Migrations make these lessons unavoidable.
Every database migration is an estimation problem. How long will it take. How risky is it. Where will the effort actually go. What happens if we are wrong.
Despite that, estimates are often built on heuristics, past experience, and optimism. Precision is implied even when it does not really exist. Everyone involved knows there is uncertainty, but it is rarely structured or made explicit.
Sales still needs a number. Clients still need to budget. Engineers still need to plan. So we collectively smooth over the uncertainty and move forward.
The issue is not that estimates are imperfect. That is inevitable. The issue is that we often do not surface why something is risky, only how long we hope it will take. When things go sideways, that missing context is what makes the failure painful.
This pattern felt familiar to me long before AI entered the picture.
When AI Systems Started Feeling Familiar
When I started working with AI-assisted tooling (code generation, automated refactoring, LLM-based transforms), the early results were impressive. Outputs looked reasonable. Demos worked. The systems sounded confident.
But once I tried to rely on them for anything non-trivial, the behavior started to feel unstable.
The same prompt sometimes produced different outputs. Retrying a failing task didn’t reliably improve it. When the model expressed high confidence, the output wasn’t necessarily correct. Small changes in context led to disproportionately different outcomes.
At first, this felt like a new class of problem. Something fundamentally different from the systems I had worked with before.
Then it stopped feeling new.
The Moment of Recognition
What finally clicked for me was realizing that these were not uniquely AI problems.
They looked exactly like the failure modes I had spent years learning to manage in databases and distributed systems, just expressed through a different interface.
The issue was not that models were sometimes wrong. That is expected. The issue was that the surrounding systems often assumed they would be right.
Get Payal Singh’s stories in your inbox
Join Medium for free to get updates from this writer.
In PostgreSQL:
- We do not assume data is valid; We enforce it with constraints.
- We do not assume migrations are safe. We design rollbacks.
- We do not assume the query planner will choose optimally; We verify with EXPLAIN ANALYZE.
- We do not assume data is valid; We enforce it with constraints.
- We do not believe backups exist until we have restored them. We build systems that expect failure and remain controllable when it happens.
Many AI pipelines, by contrast, are built on optimistic assumptions. When something goes wrong, it is often detected late, usually by a human, and without enough context to understand why it happened or how risky it really is.
That gap between generation and control is where things get expensive.
Comparing System Architectures — How they Differ
┌────────────────────────────────────────────────────────────────┐
│ PostgreSQL System Architecture │
├────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌──────────────────┐ │
│ │ Constraints │ │ Transactions │ │ Isolation Levels │ │
│ │ (NOT NULL, │ │ (BEGIN/ │ │ (READ COMMITTED, │ │
│ │ FK, CHECK) │ │ COMMIT) │ │ SERIALIZABLE) │ │
│ └────────────────┘ └────────────────┘ └──────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌──────────────────┐ │
│ │ Monitoring │ │ Rollback │ │ Human Escalation │ │
│ │ (pg_stat_*, │ │ (ROLLBACK, │ │ (Alerts, review │ │
│ │ logs) │ │ savepoints) │ │ before prod) │ │
│ └────────────────┘ └────────────────┘ └──────────────────┘ │
│ │
│ Result: Failure is expected, detected, and recoverable │
└────────────────────────────────────────────────────────────────┘VS
┌─────────────────────────────────────────────────────────────┐
│ Typical AI Pipeline (Optimistic) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Input │ │
│ └──────┬──────┘ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Model │ (assumed correct) │
│ └──────┬──────┘ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Output │ ───► Production (fingers crossed) │
│ └─────────────┘ │
│ │
│ Result: Failure detected late, by humans, expensively │
└─────────────────────────────────────────────────────────────┘Where Correctness Actually Lives
Over time, one idea kept surfacing for me.
Correctness in AI systems does not live in the model.
It lives in the system around it.
In databases, that system includes transactions, constraints, isolation levels, monitoring, and human escalation paths. In AI systems, the components are different, but the principles are not.
What matters is what assumptions the system makes, how it detects when those assumptions are violated, how uncertainty is surfaced, and where humans are intentionally brought back into the loop.
Model intelligence is only one input. Reliability is an emergent property of the whole system.
Failure Mode Mapping
| PostgreSQL Failure | AI Pipeline Equivalent |
|-------------------------------|----------------------------------|
| Table lock during migration | Response latency under load |
| Replication lag | Inconsistent outputs across runs |
| Untested backup | Untested evaluation suite |
| Schema drift over time | Prompt drift / context decay |
| Query planner misestimate | Model confidence ≠ correctness |
| Constraint violation | Output fails validation |AI Pipeline with Database-Style Controls
┌──────────────────────────────────────────────────────┐
│ AI Pipeline with Postgres-Style Controls │
├──────────────────────────────────────────────────────┤
│ │
│ ┌───────────┐ │
│ │ Input │ │
│ └─────┬─────┘ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Input Validation (CHECK constraints) │ │
│ └──────────────────┬───────────────────┘ │
│ ▼ │
│ ┌───────────┐ │
│ │ Model │ │
│ └─────┬─────┘ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Output Schema Check (type enforcement)│ │
│ └──────────────────┬───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Confidence Gate (isolation levels) │ │
│ │ - High confidence → auto-approve │ │
│ │ - Low confidence → human review │ │
│ └──────────────────┬───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Rollback Path: rule-based fallback │ │
│ │ if model fails repeatedly │ │
│ └──────────────────┬───────────────────┘ │
│ ▼ │
│ ┌───────────┐ │
│ │ Output │ │
│ └───────────┘ │
│ │
└──────────────────────────────────────────────────────┘That framing helped me understand why I kept getting pulled toward questions about evaluation, estimation, and failure modes instead of only trying to make models better.
Rethinking What Engineering Work Looks Like
This also changed how I think about engineering effort.
Some work produces visible artifacts quickly. Features, endpoints, dashboards. Other work changes what the system can safely assume. That second category often looks slower, but it quietly removes risk.
Spending time on estimation, uncertainty, and control does not always read as productivity in the short term. But it is the difference between a system that merely runs and one that can be operated with confidence.
As systems become more probabilistic, not less, that distinction starts to matter more.
Where This Leaves Me
I do not consider myself an AI researcher. I’m still applying the same instincts that database work sharpened for me. Respect uncertainty. Design for failure. Be honest about what systems can and cannot guarantee.
As AI becomes more embedded in production workflows, I find myself paying attention to familiar questions in unfamiliar contexts. Not because the tools are magical, but because the failure modes are.
Once you learn to see systems this way, it is hard to unsee it.