# AI Writes Half Our Code Now. Nobody Taught Us How to Review It.

> Source: <https://dev.to/javascriptmastery/ai-writes-half-our-code-now-nobody-taught-us-how-to-review-it-3h44>
> Published: 2026-10-29 05:00:00+00:00

AI wrote this function. It passed linting. It got approved. It shipped.

``` js
async function getUsers(ids) {
  const users = [];

  ids.forEach(async (id) => {
    const res = await fetch(`/api/users/${id}`);
    users.push(await res.json());
  });

  return users;
}
```

It returned an empty array. Every. Single. Time.

No error. No warning. Just `[]`.

If 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.

The [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%**.

(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.)

In one year, AI went from "helps with boilerplate" to "writes more than half the code."

But 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.

Almost nobody trained us to **review** code we didn't write, at speed, all day. And that's now the main job.

AI-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.

Here 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.

`forEach` doesn't wait for `async`
That'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.

**What you get:** `[]`

**The fix:** use `map` to collect the promises, then `Promise.all` to wait for them.

``` js
async function getUsers(ids) {
  return Promise.all(
    ids.map(async (id) => {
      const res = await fetch(`/api/users/${id}`);
      return res.json();
    })
  );
}
```

🔍 **Review rule:** If you see `async` inside `forEach`, stop. It's almost always a bug.

`try/catch` that catches nothing

```
async function saveUser(user) {
  try {
    db.insert(user);
    return { ok: true };
  } catch (err) {
    console.error("Save failed:", err);
    return { ok: false };
  }
}
```

Looks safe, right? There's error handling and everything.

But `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.

**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.

**The fix:** one word.

```
await db.insert(user);
```

🔍 **Review rule:** Any call that returns a promise inside a `try` block needs an `await`, or the `catch` is just decoration.

``` js
const prices = [100, 25, 9, 1200, 50];
prices.sort();
```

**What you get:** `[100, 1200, 25, 50, 9]`

By default, `.sort()` converts everything to **strings** and sorts alphabetically. `"1200"` comes before `"25"` because `"1"` comes before `"2"`.

AI loves this one because it reads perfectly in plain English. "Sort the prices." Done. Except it isn't.

**The fix:**

``` js
prices.sort((a, b) => a - b);
// [9, 25, 50, 100, 1200]
```

🔍 **Review rule:** `.sort()` with no comparator on anything that isn't a plain string array is a red flag.

```
function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setSeconds(seconds + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return <p>{seconds}</p>;
}
```

It even cleans up the interval. Very responsible. Very wrong.

The 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`.

**What you get:** `1`. Forever.

**The fix:** use the functional updater so you always get the latest value.

``` js
setSeconds((s) => s + 1);
```

🔍 **Review rule:** A state variable used inside `setInterval`, `setTimeout`, or an event listener in a `useEffect` with `[]` deps? Check for a stale closure.

```
function TodoList() {
  const [todos, setTodos] = useState([]);

  function addTodo(text) {
    todos.push(text);
    setTodos(todos);
  }

  // ...
}
```

`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.

**What you get:** You click "Add". Nothing appears on screen.

**The fix:** create a new array.

```
setTodos([...todos, text]);
```

🔍 **Review rule:** `.push()`, `.splice()`, or direct property assignment on something that came from `useState` means the UI won't update.

Save this. Run through it every time AI hands you code.

`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`?
That last one matters most.

Here's our honest take.

Prompting 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.

What'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.

Every one of the bugs above:

You can only catch them if you actually understand how JavaScript and React work under the hood. Event loop. Closures. References. Promises.

The fundamentals didn't become less important when AI showed up. They became the whole job.

**What's the sneakiest bug AI has ever shipped into your codebase?**

Drop it in the comments. Bonus points for a snippet. Let's build the ultimate list of "AI code that looked fine."

*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).*
