{"slug": "ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it", "title": "AI Writes Half Our Code Now. Nobody Taught Us How to Review It.", "summary": "A developer, citing the State of AI 2026 survey of 7,258 developers, reports that AI now generates an average of 54% of respondents' code, up from 28% a year earlier, yet most engineers were trained to write code rather than review it. The writeup catalogs five recurring JavaScript and React bugs in AI-generated code—async callbacks inside forEach, missing await inside try/catch, comparator-less sort, and stale closures in useEffect—each verified by running the snippet, and pairs them with review rules to catch them.", "body_md": "AI wrote this function. It passed linting. It got approved. It shipped.\n\n``` js\nasync function getUsers(ids) {\n  const users = [];\n\n  ids.forEach(async (id) => {\n    const res = await fetch(`/api/users/${id}`);\n    users.push(await res.json());\n  });\n\n  return users;\n}\n```\n\nIt returned an empty array. Every. Single. Time.\n\nNo error. No warning. Just `[]`.\n\nIf you spotted it in 5 seconds, nice. If you didn't, you're not alone, and that's exactly the problem we want to talk about.\n\nThe [State of AI 2026](https://2026.stateofai.dev/) developer survey collected answers from 7,258 developers, including how much of their code is AI-generated. The average answer was **54%**. A year earlier, it was **28%**.\n\n(Fair caveat: an AI survey probably attracts people who use AI a lot. But even if the real number is lower, the direction is obvious.)\n\nIn one year, AI went from \"helps with boilerplate\" to \"writes more than half the code.\"\n\nBut think about how most of us learned to code. We learned to **write** it. Tutorials, courses, bootcamps, LeetCode: almost all of it trains the writing muscle.\n\nAlmost nobody trained us to **review** code we didn't write, at speed, all day. And that's now the main job.\n\nAI-generated code has a specific personality. It looks clean, it's confidently formatted, it has nice variable names, and it's wrong in subtle ways that don't throw errors.\n\nHere are 5 bugs we see AI write over and over in JavaScript and React. Every snippet below has been run, and the output is real.\n\n`forEach` doesn't wait for `async`\nThat's our opening example. `forEach` calls your async callback, gets back a promise, and **ignores it**. It doesn't wait. So `return users` runs before a single fetch finishes.\n\n**What you get:** `[]`\n\n**The fix:** use `map` to collect the promises, then `Promise.all` to wait for them.\n\n``` js\nasync function getUsers(ids) {\n  return Promise.all(\n    ids.map(async (id) => {\n      const res = await fetch(`/api/users/${id}`);\n      return res.json();\n    })\n  );\n}\n```\n\n🔍 **Review rule:** If you see `async` inside `forEach`, stop. It's almost always a bug.\n\n`try/catch` that catches nothing\n\n```\nasync function saveUser(user) {\n  try {\n    db.insert(user);\n    return { ok: true };\n  } catch (err) {\n    console.error(\"Save failed:\", err);\n    return { ok: false };\n  }\n}\n```\n\nLooks safe, right? There's error handling and everything.\n\nBut `db.insert()` returns a promise, and there's no `await`. So the function returns `{ ok: true }` immediately. When the insert fails later, the error is **outside** the `try` block. Your `catch` never runs.\n\n**What you get:** `{ ok: true }`, even when the save failed. The real error shows up as an unhandled promise rejection, which in modern Node.js crashes the process by default.\n\n**The fix:** one word.\n\n```\nawait db.insert(user);\n```\n\n🔍 **Review rule:** Any call that returns a promise inside a `try` block needs an `await`, or the `catch` is just decoration.\n\n``` js\nconst prices = [100, 25, 9, 1200, 50];\nprices.sort();\n```\n\n**What you get:** `[100, 1200, 25, 50, 9]`\n\nBy default, `.sort()` converts everything to **strings** and sorts alphabetically. `\"1200\"` comes before `\"25\"` because `\"1\"` comes before `\"2\"`.\n\nAI loves this one because it reads perfectly in plain English. \"Sort the prices.\" Done. Except it isn't.\n\n**The fix:**\n\n``` js\nprices.sort((a, b) => a - b);\n// [9, 25, 50, 100, 1200]\n```\n\n🔍 **Review rule:** `.sort()` with no comparator on anything that isn't a plain string array is a red flag.\n\n```\nfunction Timer() {\n  const [seconds, setSeconds] = useState(0);\n\n  useEffect(() => {\n    const id = setInterval(() => {\n      setSeconds(seconds + 1);\n    }, 1000);\n    return () => clearInterval(id);\n  }, []);\n\n  return <p>{seconds}</p>;\n}\n```\n\nIt even cleans up the interval. Very responsible. Very wrong.\n\nThe empty dependency array means the effect runs once, so the interval callback captures `seconds` **from the first render**, when it was `0`. Every tick sets it to `0 + 1`.\n\n**What you get:** `1`. Forever.\n\n**The fix:** use the functional updater so you always get the latest value.\n\n``` js\nsetSeconds((s) => s + 1);\n```\n\n🔍 **Review rule:** A state variable used inside `setInterval`, `setTimeout`, or an event listener in a `useEffect` with `[]` deps? Check for a stale closure.\n\n```\nfunction TodoList() {\n  const [todos, setTodos] = useState([]);\n\n  function addTodo(text) {\n    todos.push(text);\n    setTodos(todos);\n  }\n\n  // ...\n}\n```\n\n`todos.push()` mutates the existing array. Then `setTodos(todos)` passes React **the same array reference**. React compares the old and new state, sees they're the same object, and skips the re-render.\n\n**What you get:** You click \"Add\". Nothing appears on screen.\n\n**The fix:** create a new array.\n\n```\nsetTodos([...todos, text]);\n```\n\n🔍 **Review rule:** `.push()`, `.splice()`, or direct property assignment on something that came from `useState` means the UI won't update.\n\nSave this. Run through it every time AI hands you code.\n\n`await` ed? Any `catch` actually catch what you think it catches?`.sort()`, `==`, or `parseInt`) that might not do what the name suggests?` useState` being mutated directly?`[]`, `null`, `\"\"`, or `0`?\nThat last one matters most.\n\nHere's our honest take.\n\nPrompting is getting easier every month. The tools are getting better at understanding what you mean. That's great, but it also means prompting is becoming less of a differentiator.\n\nWhat's getting **more** valuable is the thing AI is still bad at: knowing when the confident, clean, well-formatted code in front of you is wrong.\n\nEvery one of the bugs above:\n\nYou can only catch them if you actually understand how JavaScript and React work under the hood. Event loop. Closures. References. Promises.\n\nThe fundamentals didn't become less important when AI showed up. They became the whole job.\n\n**What's the sneakiest bug AI has ever shipped into your codebase?**\n\nDrop it in the comments. Bonus points for a snippet. Let's build the ultimate list of \"AI code that looked fine.\"\n\n*If you want to go deeper on building with AI agents without losing your engineering skills, we cover exactly this in our [Agentic Engineering Course](https://jsmastery.com/course/agentic-engineering-course).*", "url": "https://wpnews.pro/news/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it", "canonical_source": "https://dev.to/javascriptmastery/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it-3h44", "published_at": "2026-10-29 05:00:00+00:00", "updated_at": "2026-10-29 05:11:26.368819+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-tools", "generative-ai", "developer-tools"], "entities": ["State of AI 2026", "JavaScript", "React", "Node.js"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it", "markdown": "https://wpnews.pro/news/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it.md", "text": "https://wpnews.pro/news/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it.txt", "jsonld": "https://wpnews.pro/news/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it.jsonld"}}