productize.blog
AI · Skills Map

You didn't skip the decision.
You made it without looking.

Andrew Ng says software fundamentals still matter because you need them to steer a coding agent. The harder half of his sentence is about knowing which tradeoffs exist at all. A missing answer you can see. A missing question is invisible, and the code compiles either way.

Yim· written with Dobby (AI Oracle)/Aug 30, 2026

The code ran. The tests were green. You shipped it, and for three weeks nothing happened. Then the bill for one service climbs with no matching climb in users. Or a page that loaded instantly takes four seconds, and only for your oldest customers. Or two people open the same screen at the same moment and see different numbers.

Nobody wrote a bug. There is no stack trace, no failing test, no line in the diff that looks wrong. Go back and read the change that caused it and you find something small, tidy and entirely reasonable. That is the shape of the problem this piece is about, and it has one cause: a decision was made in your repository by something that was not you, and nothing about it looked like a decision at the time.

Productize reads the vibe coding vs agentic coding split as a question of ownership rather than of skill. This is the second half of a reading of Andrew Ng's AI engineering skills map: Part 1 covered the map and the AI-specific skills on it. This one covers the software half, where the silent decisions live.

Part 1The clause the whole essay rests on

Ng's essay on software fundamentals opens with a question and answers it in one sentence. That sentence does two jobs, and most people read only the first.

Even when you use a coding agent to write all your code, understanding software fundamentals is important for steering your agent to make the tradeoffs you want
or to even know what tradeoffs exist to be made.

The first half is the familiar argument: know enough to point the agent in the right direction. The second half is a stranger claim. The dangerous case is not being wrong about a tradeoff. It is not knowing one was there.

A missing answer is recoverable, because you can see the gap. A missing question is not, because it has already been answered. If you do not know how to configure a cache, you notice, look it up, decide. If you do not know a cache has to be invalidated, nothing prompts you. The agent picked a value, the tests pass, the page is fast, and the wrongness is scheduled for three weeks out.

Ng names the mechanism plainly: the novice who vibe codes gets working simple applications and, with them, bad tradeoffs, because "the developer didn't know such tradeoffs even existed and therefore did not steer the agent to make the right decisions for their application context". He gives the vocabulary once and never returns to it: "latency, availability, consistency, reliability, maintainability, simplicity, and/or cost". Those seven are what every decision below trades against each other.

Part 2Does agentic coding enable you, or conscript you?

It conscripts you. Ng frames the widening of your role as an opportunity, and that framing is too gentle for what happens in a repository.

His version: "Agentic coding enables many developers who previously played more specialized roles (like front-end developer or mobile developer) to play a broader, full-stack role." As a description of capability, true and cheering.

Ng does not say the next part; we do. Enables implies you could decline. You cannot. The cache-invalidation decision and the state-placement decision land in your repository whether or not you know they exist, because the agent has to write something and it will not stop to ask. There is no version of using a coding agent where you decline the decision. There is only a version where you make it without looking. Which changes the advice. Not you may now expand your role, but the expansion already happened, so the only question is whether you are watching.

An agent's lean when nobody is watching is predictable: toward whatever is most written about. The tutorial answer, the single-user answer, the one-process answer. Silence from you is not deferral. It is a decision made by whatever the model has read most of.

Here is what that looks like. You ask for a faster dashboard. The agent adds a five-minute cache in front of the summary query, held in the app's own memory. On your laptop it is correct: one copy of the app, one user. In production there are four copies behind a load balancer. A user edits a record, the write lands on copy two, and the next request routes back to copy one, where the edit has not happened. So they do it again. Now there are two records. Nothing errored.

The tell is cruel: severity scales with how many copies you run, so it worsens right after you scale up, sending everyone into the scaling change instead of the caching one. The instruction that would have prevented it is not be careful with caching. It is: name the write that invalidates this cache, implement it in the same change, and never keep shared state in one process's memory.

Part 3Why is data the one pillar that fails in silence?

Because its failure has no output. Every other part of the stack eventually produces something loud: a timeout, an error page, a bill. A data architecture that is missing something produces a confident, plausible answer, and nothing in the system looks different from success.

Ng gives data a privilege the other pillars do not get. He calls it "a foundation that software is built on top of, that is relatively hard to change (even if agents help with migrations)", then makes the essay's one AI-era claim: "Your AI systems will get their own input context from your data source, so if data architecture is chosen poorly, the AI doesn't know what it doesn't know."

The mechanism is stronger than the usual complaint that bad data gives bad answers. A model's output is a function of its context, and its context is assembled by code running against your data layer. So the outer edge of what the system can know is the edge of what that layer can return, and nothing inside the model can see that edge from the inside. A person who does not know something can notice the gap. A model handed a truncated context does not experience a truncation. It experiences a complete context.

The sharpest form of this is one sentence long. An empty result set is the same bytes whether the answer is genuinely none, or the question was never answerable from that schema. No query language can express the difference, because the distinction lives in the collection history, and the collection history is not in the database.

This is the exact opposite of the failure we wrote about in why your AI agent lies to you. There the model invents something that was not in front of it. Here it invents nothing: it answers correctly, over a smaller world, with no signal that the world was smaller. Which is why a better model does not fix it. A better model given the same context reaches the same answer with more polish. It is a data problem that presents as a model problem, so teams misdiagnose it and spend months tuning prompts at it.

Four ways a fact becomes invisible, worth naming on sight:

The everyday version of all four is NULL. In real schemas it stands in for at least five meanings: not applicable, unknown, not yet collected, collected and genuinely empty, and lost in a migration. A model reading a NULL cannot tell them apart. Mostly, neither can we. Which makes one review question unusually productive on a generated schema: what does NULL mean in this column, and is it more than one thing?

Ng states the problem and prescribes nothing, leaving a warning about an invisible failure with no instrument attached. The best instrument we know sits at the boundary where an agent reads. A retrieval tool asked to filter on a dimension the source does not have should return an explicit this field is not available here, never an empty list. That converts a silent absence into a token in the context, which the model can read, report and route around.

Then prove that instrument can fire. Ask something whose answer you know lies outside the retained window, and assert that the system reports it cannot see that far. A retrieval layer that has never once reported a limit has not shown it can detect one.

Part 4The rest of the map, in one story

Architecture is where the essay makes its quietest good point: "the right architecture is a moving target, depending on the phase of the project". The prototype shape is not the first-production shape, and "that too may change as the application scales". Cheap generation is an argument for committing later, not bigger.

Ng stops there. The part we would add is where irreversibility actually sits. One-way doors are not spread evenly through a system. They cluster at its edges. A published URL, an API shape a second client adopted, an ID a user can see, the tenant key in the first migration, where the bytes physically live, what you promised to delete. Internals stay reversible far longer than people assume, and interfaces become irreversible far sooner. The rule that falls out: spend deliberation at the edges, speed in the middle.

Prototypes are the trap inside that rule, because they feel disposable. Their code is. Their published URLs and the real user data they ingested are not: the moment a prototype touches personal data it picks up obligations that outlive every line that created them.

Underneath it is an asymmetry agentic coding created and did not advertise. Generation got dramatically cheaper. Migration got a little cheaper, since an agent rewrites call sites but cannot negotiate a contract change with consumers you do not control. Operating cost did not move at all: it is a function of surface area, and surface area does not care how the code was authored. So cheap generation did not make good architecture cheaper. It made wrong architecture cheaper to acquire and left it exactly as expensive to own. Nobody hand-built seven services for a prototype, because nobody had the weekend. The friction of typing was acting as a limiter on ambition, and removing the friction removed the limiter, not the cost.

The last two pillars fail the same way, and we have written about both, so only the shape here. Ng asks for a testing strategy. The failure we keep meeting is not too few tests but tests that cannot go red, and checks that report green for the wrong reason. In production, an alert that has never fired and an alert that is broken look identical from outside, because both produce silence. Neither is a knowledge gap. Both are the cache question again: what would have to be true for this to tell me something?

Part 5What can you ask of a diff tomorrow?

Ask questions you can answer by reading, without running anything. Every one is recognition rather than implementation, which makes the skill acquirable on work you already do. If you cannot answer one from the code in front of you, that is the finding, and the agent's default stands.

None of those requires you to write the implementation yourself. That is the point: these fundamentals are learnable at review time, not only in a curriculum.

Ng closes by saying developers who deeply understand how software works "vastly outperform those who vibe code without understanding". He attributes it to an internal study and publishes no figures, so take it as a considered position rather than a measured result. Our version is narrower and harder to argue with: the agent makes the decision either way, and the only variable is whether anyone looked.

Part 1 covered the other half of the map: the AI-specific skills sitting on top of these fundamentals. Read it here.

Source

§

Follow along

Get new posts and free resources first

Leave your email. New posts and the occasional free resource land in your inbox. No spam.

Email only, for updates.

Comments

Join the conversation

Share a thought.

Name is shown publicly. Email stays private and is never shown.

Loading comments…