12k
All articles

The Fundamentals You Still Need When Coding with Agents

Review AI-generated code with confidence. Learn the web fundamentals behind HTTP, browser behavior, state, security, debugging, Git, and sound architecture.

OpenReplay Team
OpenReplay Team
The Fundamentals You Still Need When Coding with Agents

You need enough programming fundamentals to judge agent-written code, not to type it, because code that runs can still be badly designed, insecure or slow.

The usual situation: the agent says it’s done, the page loads, the tests pass, and you still couldn’t explain the diff if a reviewer asked about it. That doubt is reasonable. It usually points to a specific gap in what you know.

This article doesn’t cover prompting or tool setup. For that, see how to get the best results from AI coding tools and tips and tricks for AI coding. Instead, it takes seven web fundamentals and pairs each one with a realistic agent mistake and the knowledge you need to catch it.

Key Takeaways

  • The browser’s fetch() rejects only when the request itself fails, such as a network error, so code that never checks response.ok treats a 404 or 500 as success.
  • Any value bundled into frontend JavaScript is public, including environment variables the framework exposes to the client.
  • Hiding a button is not authorization: the server has to check permissions on every request.
  • git add -p lets you accept an agent’s changes one hunk at a time, and git revert undoes a commit without rewriting history.
FundamentalTypical agent mistakeWhat catches it
HTTP200 with an error bodyStatus code semantics
BrowserListener with no cleanupEffect lifecycle
StateServer data copied into a storeSingle source of truth
SecuritySecret in client bundleKnowing what ships to the browser
DebuggingSwallowed errorStack traces, DevTools
GitAccepting everything at onceHunk staging, revert
ArchitectureNew dependency for a one-linerPlatform APIs

Why Do HTTP Status Codes and Caching Still Matter?

Status codes and caching headers are how clients, proxies and monitoring tools know what happened to a request. An endpoint that returns 200 OK with an error message in the body tells every client, cache and monitoring tool that the request succeeded. RFC 9110 defines 2xx as success, so error tracking and retries won’t fire. Keep the HTTP status codes reference nearby when you review handlers.

The client side has a matching trap. fetch() does not reject on HTTP error statuses, only when the request itself fails, so you have to check Response.ok yourself:

const res = await fetch('/api/save', { method: 'POST', body });
if (!res.ok) throw new Error(`Save failed: ${res.status}`);

Agents also tend to poll data that rarely changes. For config or reference lists, Cache-Control (defined in RFC 9111) with ETag revalidation (returning 304 Not Modified, defined in RFC 9110) gets rid of the redundant requests. Data that genuinely changes in real time is a separate problem.

How Does the Browser Render and Handle Events?

Event listeners and DOM writes have lifecycles, and the browser charges you for ignoring them. A common agent mistake is adding a listener inside an effect that has no cleanup and no dependency array. React runs that effect after every render, so every render adds another resize listener. The fix returns a cleanup and declares its dependencies:

useEffect(() => {
  window.addEventListener('resize', onResize);
  return () => window.removeEventListener('resize', onResize);
}, [onResize]);

The returned cleanup runs before the next effect run and on unmount. The second browser pattern to spot is layout thrashing: a loop that writes a style and then reads offsetHeight, again and again. Each read after a write can force synchronous layout. The fix is to do all the reads first and the writes afterwards.

Where Should State Live and How Should Data Flow?

Every piece of data should have one owner. Copying server data into a client-side store creates a second source of truth, and the two copies drift apart as soon as one changes without the other. A typical agent version fetches a list, puts it in useState or a Zustand store, and edits it locally while a refetch updates a different copy.

React’s guidance on state structure warns against duplicating state. For server data, a cache layer such as TanStack Query or SWR owns the data and handles invalidation. For anything you can compute from existing state, derive the value during render.

Security Basics: Auth, XSS, Secrets and Untrusted Input

Frontend security depends on knowing which code runs in the browser and which runs on the server. Any value bundled into frontend JavaScript is public. In Next.js, environment variables are server-only by default. Adding the NEXT_PUBLIC_ prefix inlines a variable’s value into the client bundle at build time, so an agent that puts that prefix on an API key has published the key.

Hiding a button in the UI is not authorization. Anyone can call the API directly, so the server has to check permissions on every request. This failure falls under OWASP Top 10:2025, A01 Broken Access Control.

Assigning user input to innerHTML makes the browser parse it as markup, and that includes attributes like onerror that run JavaScript. textContent inserts the same input as plain text. JSX escapes interpolated strings by default, and dangerouslySetInnerHTML turns that protection off. The OWASP XSS Prevention Cheat Sheet covers the rest.

How Do You Debug Code You Didn’t Write?

Debugging means finding the cause of a bug, not making the symptom go away. Agents often “fix” an error by wrapping it in a try/catch that swallows it, or by adding optional chaining that hides an undefined value instead of tracing where it came from. The error disappears from the console, but the bug is still there.

Before you accept a fix, read the stack trace, reproduce the bug, and look at the Network panel in Chrome DevTools to see what the request and response actually contained. Some bugs only show up for real users. Session replay shows what agent-written code does for those users in production, such as a retry loop hammering an endpoint or a form that silently fails, and that is often where gaps in these fundamentals become visible.

Git Well Enough to Review and Undo an Agent’s Changes

Git is how you accept part of an agent’s work and undo the rest. Agents tend to make sweeping edits, and accepting them in one go hides unrelated changes. Four commands cover most of what you need:

git diff                 # read every change
git add -p               # stage hunk by hunk
git restore -p src/x.ts  # discard unwanted hunks
git revert <commit>      # undo a committed change

git add -p asks you about each hunk before staging it, and git restore -p discards working-tree hunks one at a time. git revert adds a new commit that reverses an earlier one. That makes it safe on shared branches, whereas reset rewrites history.

Enough Architecture to Spot an Over-Built Solution

Good architecture solves today’s problem with what the project already has. Agents often reach for a new dependency, or a factory or strategy layer, to handle a one-off task. Installing a date library to format a single date is a typical case, since Intl.DateTimeFormat does that natively. When a diff adds files, packages or abstractions, ask whether the existing code could do the job in fewer files. If it could, reject the change or ask for a smaller one.

Habits That Keep You in Charge

  • Ask the agent to explain its choices. If you can’t judge the explanation, you’ve found the fundamental to study next.
  • Read the diff before accepting. Review every hunk, every time.
  • Make small changes by hand. Typing a fix yourself keeps your understanding current.

Tests turn your judgment into checks that run on every change.

Conclusion

Agents can write the code, but you’re responsible for what it does. Learn HTTP semantics, the browser’s rendering model, state ownership, security boundaries, debugging, Git and the restraint to keep things small, and you’ll be able to reject a bad diff and explain why. Next time an agent hands you a change, start by reading git diff and pick out one decision you can’t yet explain.

FAQs

Does axios have the same HTTP error problem as fetch?

No. By default, axios rejects the promise for any response status outside the 200 to 299 range, so a 404 or 500 lands in the catch block. The validateStatus option controls this and can be overridden. An API that returns 200 with an error message in the body still resolves successfully in both axios and fetch, so the server must send correct status codes.

Is it safe to put API keys in Vite environment variables?

Only if the variable has no VITE_ prefix. Vite exposes VITE_ prefixed variables to client code through import.meta.env and replaces them statically at build time, so their values end up in the client bundle. Unprefixed variables are not exposed to client code. Like NEXT_PUBLIC_ in Next.js, the prefix opts a value into publication and does not protect it, so secrets must stay on a server.

How do I render user-supplied HTML safely when textContent is not enough?

Sanitize the HTML before inserting it. OWASP recommends DOMPurify: pass the string through DOMPurify.sanitize and use the result with innerHTML or dangerouslySetInnerHTML. Do not modify the sanitized output afterwards, because changes can reintroduce dangerous markup. Keep the sanitizer library patched, since new bypasses are discovered regularly. Rich text editors and user-authored Markdown are the typical cases where this is needed.

Why does my React effect run twice in development?

In development, React Strict Mode mounts components an extra time to expose effects that are missing cleanup. This does not happen in production. If the second run creates duplicate listeners, requests or subscriptions, the effect needs a cleanup function that undoes its setup. Removing Strict Mode or adding a ref guard to skip the second run only hides the bug.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.