<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: James Mateer</title>
    <description>The latest articles on DEV Community by James Mateer (@jaeger974).</description>
    <link>https://dev.to/jaeger974</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3907675%2F722930ca-a9ee-40a3-9b3f-17eefc3ce869.png</url>
      <title>DEV Community: James Mateer</title>
      <link>https://dev.to/jaeger974</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jaeger974"/>
    <language>en</language>
    <item>
      <title>AI wrote my bug. I shipped it anyway. Here’s what I learned.</title>
      <dc:creator>James Mateer</dc:creator>
      <pubDate>Wed, 20 May 2026 11:08:43 +0000</pubDate>
      <link>https://dev.to/jaeger974/ai-wrote-my-bug-i-shipped-it-anyway-heres-what-i-learned-54ca</link>
      <guid>https://dev.to/jaeger974/ai-wrote-my-bug-i-shipped-it-anyway-heres-what-i-learned-54ca</guid>
      <description>&lt;p&gt;Last month, I let AI “help” me refactor a small but performance-critical bit of frontend code. It confidently gave me a clean, modern solution. Types checked, tests were green, and the code looked nicer than what I’d written before. I merged it.&lt;/p&gt;

&lt;p&gt;Two days later, a user reported that a key interaction was randomly failing. Turned out the bug was subtle, intermittent, and 100% introduced by that AI-generated snippet. The worst part: the code looked so reasonable that my brain just rubber-stamped it.&lt;/p&gt;

&lt;p&gt;This is how AI is in my workflow now: incredibly useful, occasionally dangerous, and something I treat more like a junior teammate than a trusted source of truth.&lt;/p&gt;

&lt;p&gt;Tools in my day-to-day workflow&lt;br&gt;
Here’s what I actually use as a JavaScript/web dev working on real projects:&lt;/p&gt;

&lt;p&gt;GitHub Copilot for inline suggestions, writing boilerplate React components, and quick refactors.&lt;/p&gt;

&lt;p&gt;Claude for “bigger brain” tasks: explaining legacy code, generating first-draft docs, and exploring alternative designs.&lt;/p&gt;

&lt;p&gt;Browser devtools + tests as the “reality check” layer when AI feels too confident.&lt;/p&gt;

&lt;p&gt;AI’s job in my workflow is to speed up the “typing” and help me explore ideas, not to replace my thinking.&lt;/p&gt;

&lt;p&gt;When AI really helped: reducing noisy event handlers&lt;br&gt;
I had a React component that attached a scroll listener and did some heavy work on every event. It wasn’t catastrophic, but it caused jank on low-end devices. I asked Copilot to suggest a lightweight throttling solution.&lt;/p&gt;

&lt;p&gt;AI-generated suggestion (good enough start)&lt;br&gt;
js&lt;br&gt;
// AI suggestion: basic throttle for scroll handler&lt;br&gt;
function throttle(fn, delay) {&lt;br&gt;
  let lastCall = 0;&lt;/p&gt;

&lt;p&gt;return function (...args) {&lt;br&gt;
    const now = Date.now();&lt;br&gt;
    if (now - lastCall &amp;gt;= delay) {&lt;br&gt;
      lastCall = now;&lt;br&gt;
      fn.apply(this, args);&lt;br&gt;
    }&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function handleScroll() {&lt;br&gt;
  // expensive calculation&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;window.addEventListener('scroll', throttle(handleScroll, 100));&lt;br&gt;
This was actually pretty decent for my use case. It avoided calling handleScroll on every scroll event and eliminated most of the jank.&lt;/p&gt;

&lt;p&gt;I still made adjustments:&lt;/p&gt;

&lt;p&gt;Extracted the throttle into a shared utility.&lt;/p&gt;

&lt;p&gt;Added proper typing and tests.&lt;/p&gt;

&lt;p&gt;Verified behavior in the browser with real scrolling patterns.&lt;/p&gt;

&lt;p&gt;Final version after review&lt;br&gt;
ts&lt;br&gt;
// utils/throttle.ts&lt;br&gt;
export function throttle void&amp;gt;(&lt;br&gt;
  fn: T,&lt;br&gt;
  delay: number&lt;br&gt;
) {&lt;br&gt;
  let lastCall = 0;&lt;br&gt;
  let timeoutId: number | null = null;&lt;/p&gt;

&lt;p&gt;return function (this: unknown, ...args: Parameters) {&lt;br&gt;
    const now = Date.now();&lt;br&gt;
    const remaining = delay - (now - lastCall);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (remaining &amp;lt;= 0) {
  lastCall = now;
  if (timeoutId !== null) {
    window.clearTimeout(timeoutId);
    timeoutId = null;
  }
  fn.apply(this, args);
} else if (timeoutId === null) {
  timeoutId = window.setTimeout(() =&amp;gt; {
    lastCall = Date.now();
    timeoutId = null;
    fn.apply(this, args);
  }, remaining);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;br&gt;
}&lt;br&gt;
AI got me 60–70% of the way. I added the rest: better handling of calls at the edges, reuse, and type safety.&lt;/p&gt;

&lt;p&gt;This is AI at its best in my workflow: drafting something reasonable that I then refine.&lt;/p&gt;

&lt;p&gt;When AI misled me: a subtle async bug&lt;br&gt;
Now the painful story.&lt;/p&gt;

&lt;p&gt;I had some code that needed to ensure a DOM element existed before measuring it. I asked Copilot for a small helper that “waits for an element to exist then resolves with it or times out.” Copilot produced something like this:&lt;/p&gt;

&lt;p&gt;AI suggestion (looked correct, wasn’t)&lt;br&gt;
js&lt;br&gt;
function waitForElement(selector, timeout = 3000) {&lt;br&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br&gt;
    const element = document.querySelector(selector);&lt;br&gt;
    if (element) {&lt;br&gt;
      resolve(element);&lt;br&gt;
      return;&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const observer = new MutationObserver(() =&amp;gt; {
  const el = document.querySelector(selector);
  if (el) {
    observer.disconnect();
    resolve(el);
  }
});

observer.observe(document.body, { childList: true, subtree: true });

setTimeout(() =&amp;gt; {
  observer.disconnect();
  reject(new Error('Element not found'));
}, timeout);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;br&gt;
}&lt;br&gt;
At a glance, it looked fine: observe DOM mutations, resolve when the element appears, reject on timeout. I skimmed it, tests passed, and I shipped it.&lt;/p&gt;

&lt;p&gt;The bug? Under certain conditions, the timeout fired after the element was found and resolved. In rare race conditions, the promise would resolve and then later be rejected, causing unpredictable error handling elsewhere.&lt;/p&gt;

&lt;p&gt;Corrected version with proper cleanup&lt;br&gt;
js&lt;br&gt;
function waitForElement(selector, timeout = 3000) {&lt;br&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br&gt;
    const existing = document.querySelector(selector);&lt;br&gt;
    if (existing) {&lt;br&gt;
      resolve(existing);&lt;br&gt;
      return;&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let settled = false;
const observer = new MutationObserver(() =&amp;gt; {
  const el = document.querySelector(selector);
  if (el &amp;amp;&amp;amp; !settled) {
    settled = true;
    observer.disconnect();
    window.clearTimeout(timeoutId);
    resolve(el);
  }
});

observer.observe(document.body, { childList: true, subtree: true });

const timeoutId = window.setTimeout(() =&amp;gt; {
  if (!settled) {
    settled = true;
    observer.disconnect();
    reject(new Error(`Element not found: ${selector}`));
  }
}, timeout);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;br&gt;
}&lt;br&gt;
Key differences:&lt;/p&gt;

&lt;p&gt;Introduced a settled flag.&lt;/p&gt;

&lt;p&gt;Cleared the timeout when resolving.&lt;/p&gt;

&lt;p&gt;Guarded both paths so the promise only settles once.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of subtle bug AI is prone to: the logic is “plausible” and looks idiomatic, but it hasn’t been truly thought through.&lt;/p&gt;

&lt;p&gt;My framework for trusting AI (or not)&lt;br&gt;
Here’s how AI fits into my decision-making:&lt;/p&gt;

&lt;p&gt;Use AI for:&lt;/p&gt;

&lt;p&gt;Boilerplate and repetitive patterns.&lt;/p&gt;

&lt;p&gt;Utility functions that I heavily review.&lt;/p&gt;

&lt;p&gt;Alternative approaches I might not think of on my own.&lt;/p&gt;

&lt;p&gt;Writing tests and docs drafts that I refine.&lt;/p&gt;

&lt;p&gt;Be skeptical when:&lt;/p&gt;

&lt;p&gt;The code touches async, concurrency, or subtle browser behavior.&lt;/p&gt;

&lt;p&gt;It involves security, authentication, or data validation.&lt;/p&gt;

&lt;p&gt;The code “just works” and I don’t fully understand why.&lt;/p&gt;

&lt;p&gt;Non-negotiables before merging AI code:&lt;/p&gt;

&lt;p&gt;Read it line by line and explain it in plain language.&lt;/p&gt;

&lt;p&gt;Add tests that would have caught the bug if the code were wrong.&lt;/p&gt;

&lt;p&gt;Run it in a realistic environment, not just unit tests.&lt;/p&gt;

&lt;p&gt;The mindset shift: AI is a junior engineer with infinite stamina but no real understanding. If it writes something you don’t fully get, that’s your bug waiting to happen.&lt;/p&gt;

&lt;p&gt;Your turn&lt;br&gt;
AI is now part of most dev workflows, for better or worse. For me, it’s worth the risk—but only when paired with a strong review habit and healthy skepticism.&lt;/p&gt;

&lt;p&gt;How are you using AI in your workflow right now, and what’s one time it either saved you hours or nearly burned you—what happened?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Scientific Method Made Me Better at Debugging Than I Expected</title>
      <dc:creator>James Mateer</dc:creator>
      <pubDate>Fri, 08 May 2026 13:21:00 +0000</pubDate>
      <link>https://dev.to/jaeger974/the-scientific-method-made-me-better-at-debugging-than-i-expected-3min</link>
      <guid>https://dev.to/jaeger974/the-scientific-method-made-me-better-at-debugging-than-i-expected-3min</guid>
      <description>&lt;p&gt;One of the first major bugs I hit as a junior developer looked simple at first.&lt;/p&gt;

&lt;p&gt;My React frontend refused to talk to my Express backend. The terminal kept throwing errors, the browser showed failed requests, and after a few hours I was convinced I had fundamentally misunderstood how APIs worked.&lt;/p&gt;

&lt;p&gt;At first, I did what I think a lot of beginners do: randomly changed things until something worked.&lt;/p&gt;

&lt;p&gt;Bad idea.&lt;/p&gt;

&lt;p&gt;Eventually I stopped, took a breath, and approached it the same way I used to approach problems in scientific environments: isolate variables and identify root causes.&lt;/p&gt;

&lt;p&gt;I started using a simple “5 Whys” approach.&lt;/p&gt;

&lt;p&gt;Problem: Frontend couldn’t connect to backend.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;
→ The request was failing.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;
→ The API endpoint returned a CORS error.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;
→ Express wasn’t configured to allow requests from the Vite frontend.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;
→ I never added CORS middleware.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;
→ I didn’t fully understand how frontend/backend communication actually worked yet.&lt;/p&gt;

&lt;p&gt;That single debugging session changed how I think about development.&lt;/p&gt;

&lt;p&gt;Instead of treating bugs like random disasters, I started treating them like experiments.&lt;/p&gt;

&lt;p&gt;import express from "express";&lt;br&gt;
import cors from "cors";&lt;/p&gt;

&lt;p&gt;const app = express();&lt;/p&gt;

&lt;p&gt;app.use(cors());&lt;/p&gt;

&lt;p&gt;app.listen(3000, () =&amp;gt; {&lt;br&gt;
  console.log("Server connected on port 3000");&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The fix itself was tiny.&lt;/p&gt;

&lt;p&gt;The lesson was not.&lt;/p&gt;

&lt;p&gt;What surprised me most about software development is that professional developers don’t seem to know everything either. Before I started coding, I honestly thought experienced engineers just remembered entire frameworks and instantly knew solutions.&lt;/p&gt;

&lt;p&gt;What I’ve discovered instead is that good developers:&lt;/p&gt;

&lt;p&gt;Read documentation constantly&lt;br&gt;
Break problems into smaller problems&lt;br&gt;
Search intelligently&lt;br&gt;
Debug methodically&lt;br&gt;
Document what they learn&lt;/p&gt;

&lt;p&gt;That last one surprised me most.&lt;/p&gt;

&lt;p&gt;I used to think documentation was just corporate busywork. Now I understand it’s one of the most practical skills in development. Half the battle of solving future problems is leaving breadcrumbs for yourself.&lt;/p&gt;

&lt;p&gt;I’ve started keeping notes on:&lt;/p&gt;

&lt;p&gt;recurring errors&lt;br&gt;
useful terminal commands&lt;br&gt;
ESLint fixes&lt;br&gt;
Git commands I always forget&lt;br&gt;
project setup issues&lt;br&gt;
debugging patterns&lt;/p&gt;

&lt;p&gt;Something as simple as this has saved me hours:&lt;/p&gt;

&lt;p&gt;git status&lt;br&gt;
git add .&lt;br&gt;
git commit -m "fix: resolved auth middleware issue"&lt;br&gt;
git push origin main&lt;/p&gt;

&lt;p&gt;Another thing that surprised me was how emotionally challenging development can be.&lt;/p&gt;

&lt;p&gt;There were days where I felt genuinely underqualified. I’d spend hours on something that turned out to be a missing bracket or incorrect import path.&lt;/p&gt;

&lt;p&gt;But I’m starting to realise that debugging is not proof that you’re failing.&lt;/p&gt;

&lt;p&gt;Debugging is the work.&lt;/p&gt;

&lt;p&gt;Every bug forces you to understand the system better than you did before.&lt;/p&gt;

&lt;p&gt;One of the most encouraging moments I’ve had so far was seeing this message after hours of troubleshooting:&lt;/p&gt;

&lt;p&gt;Server connected on port 3000&lt;/p&gt;

&lt;p&gt;Tiny win. Massive confidence boost.&lt;/p&gt;

&lt;p&gt;I’m still early in my journey, but I already think my previous experience outside tech gave me an advantage: learning how to think systematically under pressure.&lt;/p&gt;

&lt;p&gt;Turns out that skill transfers surprisingly well into software development.&lt;/p&gt;

&lt;p&gt;If you're career changing into dev, what's the biggest thing your old career taught you?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>career</category>
    </item>
  </channel>
</rss>
