<?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: Ntty</title>
    <description>The latest articles on DEV Community by Ntty (@ntty).</description>
    <link>https://dev.to/ntty</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3781917%2F59cbac53-d413-4b6d-91d4-eba3dffb6f91.jpeg</url>
      <title>DEV Community: Ntty</title>
      <link>https://dev.to/ntty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ntty"/>
    <language>en</language>
    <item>
      <title>Stop building the 'Perfect' SaaS and start charging for it</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sun, 23 Aug 2026 11:00:55 +0000</pubDate>
      <link>https://dev.to/ntty/stop-building-the-perfect-saas-and-start-charging-for-it-3nbd</link>
      <guid>https://dev.to/ntty/stop-building-the-perfect-saas-and-start-charging-for-it-3nbd</guid>
      <description>&lt;h2&gt;
  
  
  The Trap of the 'One More Feature'
&lt;/h2&gt;

&lt;p&gt;I spent six months building a project a few years ago that never saw a single user. I had a fully automated CI/CD pipeline, a perfectly normalized database schema, and a custom-built authentication system because I didn't trust the third-party options. I felt like I was making progress because I was writing code every day.&lt;/p&gt;

&lt;p&gt;Here is the truth: writing code is not the same as building a business. For most developers, coding is the comfortable part. Marketing, pricing, and talking to strangers are the scary parts. So, we hide in the IDE. We tell ourselves that the product is not ready yet. We think, 'If I just add this one more feature, people will actually pay for it.'&lt;/p&gt;

&lt;p&gt;This is a lie. Most of the features you think are essential are actually noise. Your users do not care about your clean architecture or your test coverage. They care about whether your tool solves a specific, painful problem in their day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MVP is usually too big
&lt;/h2&gt;

&lt;p&gt;Most developers define a Minimum Viable Product (MVP) as a fully functional version of their final vision. That is not an MVP. An MVP should be the smallest possible thing that provides value. &lt;/p&gt;

&lt;p&gt;If you are building a tool to automate reports, you do not need a fancy dashboard with drag-and-drop widgets. You need a script that takes a CSV and emails a PDF. If someone is not willing to pay for the ugly, manual version of your solution, they certainly will not pay for the polished version.&lt;/p&gt;

&lt;p&gt;I learned this the hard way. I once spent three weeks building a complex onboarding flow with tooltips and progress bars. When I finally launched, I found out that the users did not even want the main feature of the app. I wasted three weeks polishing a door to a room nobody wanted to enter.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually validate
&lt;/h2&gt;

&lt;p&gt;Validation is not asking your friends if they like your idea. Your friends will lie to you because they like you. Real validation is a transaction. &lt;/p&gt;

&lt;p&gt;Here are three ways to validate without spending months on code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Manual Bridge&lt;/strong&gt;: Do the work by hand. If your SaaS is supposed to automate a task, do that task manually for a client. If they pay you for the manual result, you have a business. Now you can write code to automate what you just did.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Pre-Sale&lt;/strong&gt;: Create a landing page that describes the value. Put a 'Buy Now' button that leads to a waitlist or a pre-order form. If people click that button, you have a signal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The concierge approach&lt;/strong&gt;: Work with one single user. Build exactly what they need, deploy it, and watch them use it. Ignore everyone else until that one person is getting value.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pricing as a feature
&lt;/h2&gt;

&lt;p&gt;Many devs are terrified of pricing. We want to offer a generous free tier because we want 'growth'. But free users are often the most demanding and the least likely to help you build a sustainable product.&lt;/p&gt;

&lt;p&gt;Charging money is a filter. It separates the people who have a real problem from the people who are just curious. When someone pays you, they are giving you a mandate to fix their problem. &lt;/p&gt;

&lt;p&gt;Do not start with a complex pricing table. Start with one flat fee. It removes the friction of decision-making for the user and the friction of bookkeeping for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Build the smallest possible version of your idea. Launch it while you are still slightly embarrassed by how simple it is. If it fails, you lost two weeks instead of six months. If it succeeds, you have a roadmap written by your customers, not your assumptions.&lt;/p&gt;

&lt;p&gt;Focus on the value, not the stack. If you find yourself spending more time on your build pipeline than on your landing page, you are procrastinating via engineering.&lt;/p&gt;

&lt;p&gt;For those building tools that involve waiting for AI responses or long processes, keep the UX simple. A clear indicator like the one at &lt;a href="https://waitspin.com" rel="noopener noreferrer"&gt;https://waitspin.com&lt;/a&gt; is often all you need to keep a user from refreshing the page while your backend works.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stop Treating AI Editors Like Magic Wands</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sat, 22 Aug 2026 11:00:58 +0000</pubDate>
      <link>https://dev.to/ntty/stop-treating-ai-editors-like-magic-wands-1aco</link>
      <guid>https://dev.to/ntty/stop-treating-ai-editors-like-magic-wands-1aco</guid>
      <description>&lt;h2&gt;
  
  
  The Honeymoon Phase
&lt;/h2&gt;

&lt;p&gt;I spent the first two weeks with Cursor thinking I had found a cheat code. I was hitting Cmd-K, typing a vague request, and watching the code rewrite itself. It felt like I was managing a junior developer who worked at light speed. &lt;/p&gt;

&lt;p&gt;Then the bugs started appearing. Not the obvious syntax errors, but the logic gaps. The AI would change a variable type in one file and forget to update the interface in another. Because I was skimming the diffs instead of reading them, I started shipping regressions that I would have caught in five seconds using a traditional editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trap of the Diff-Review
&lt;/h2&gt;

&lt;p&gt;When you use an AI editor, the primary activity shifts from writing code to reviewing diffs. This is a dangerous shift if you are not careful. &lt;/p&gt;

&lt;p&gt;Reviewing a diff is cognitively different from writing the logic. When you write code, you are building a mental model of the data flow. When you review a diff, you are often just checking if the code looks right. This is where the "hallucination creep" happens. The AI suggests a change that looks elegant, fits the pattern of the project, and passes the initial test, but misses an edge case that only happens in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Workflow
&lt;/h2&gt;

&lt;p&gt;To stay in control, I had to change how I interact with the tool. Here is the system I use now to ensure I actually understand what is being added to my repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Pseudo-Code Prompt
&lt;/h3&gt;

&lt;p&gt;Instead of asking the AI to "implement the payment logic," I now prompt it with the logic steps I want. &lt;/p&gt;

&lt;p&gt;Example: "Create a function that takes the cart object, validates the stock levels via the API, calculates the tax based on the user's state, and returns a final total. Use the existing TaxCalculator class."&lt;/p&gt;

&lt;p&gt;By defining the steps, I am still the architect. I am not delegating the thinking, just the typing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Small Atomic Changes
&lt;/h3&gt;

&lt;p&gt;It is tempting to highlight 100 lines of code and ask for a refactor. Do not do this. The larger the change, the more likely the AI is to omit a crucial line of logic or introduce a subtle bug. &lt;/p&gt;

&lt;p&gt;I now limit my AI edits to small, atomic chunks. If a feature requires five changes, I do five separate prompts. This makes the diffs manageable and the reverts easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The "Explain it Back" Rule
&lt;/h3&gt;

&lt;p&gt;Whenever the AI suggests a complex block of logic that I did not explicitly dictate, I ask it to explain why it chose that specific approach. If the explanation sounds generic or doesn't make sense, I delete the code and write it myself. If you cannot explain why a piece of code is there, it does not belong in your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Danger of Context Overload
&lt;/h2&gt;

&lt;p&gt;AI editors have access to your entire folder. While this is great for finding where a function is defined, it can lead to "context pollution." &lt;/p&gt;

&lt;p&gt;Sometimes the AI sees a deprecated pattern in an old file and decides to replicate that pattern in your new feature because it thinks that is the project style. I have found that manually adding only the relevant files to the context window is far more effective than relying on the automatic index. It forces you to think about the dependencies of the feature you are building.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;AI editors are tools for acceleration, not replacement. The goal is to reduce the friction of boilerplate and repetitive patterns, not to stop thinking about how the software works. &lt;/p&gt;

&lt;p&gt;If you spend more time clicking "Accept" than you do reading the actual lines of code, you are creating a technical debt bomb that will explode the first time you have to debug a production outage at 3 AM. Keep the architect in the driver's seat and use the AI as a high-speed typist.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stop Over-Engineering Your Indie Project</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Thu, 20 Aug 2026 11:00:22 +0000</pubDate>
      <link>https://dev.to/ntty/stop-over-engineering-your-indie-project-3j0h</link>
      <guid>https://dev.to/ntty/stop-over-engineering-your-indie-project-3j0h</guid>
      <description>&lt;p&gt;I spent three weeks setting up a Kubernetes cluster and a complex event-driven architecture for a project that had exactly zero users. I told myself I was building for scale. In reality, I was just procrastinating on the hard part: building a feature people actually want to use.&lt;/p&gt;

&lt;p&gt;When you work as an indie developer, your biggest enemy is not technical debt. It is the lack of a user base. Technical debt only matters if you have a product that survives long enough to be slowed down by it. Most indie projects die long before they hit the scale where a monolithic app becomes a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trap of the 'Perfect' Stack
&lt;/h2&gt;

&lt;p&gt;It is easy to get caught up in the hype. You see a thread on X or a blog post about a new framework that promises better type safety or faster build times. You spend a weekend migrating your state management because the new library feels cleaner. &lt;/p&gt;

&lt;p&gt;But here is the truth: your users do not care if you use Redux, Zustand, or just a global object. They do not care if your backend is written in Go, Rust, or a basic Node.js script. They care if the button works and if the page loads.&lt;/p&gt;

&lt;p&gt;Every hour you spend tweaking your CI/CD pipeline is an hour you are not talking to users or fixing bugs in the core loop of your app. If you are a solo dev, you are the CEO, the product manager, and the janitor. You cannot afford to be a full-time infrastructure engineer too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embrace the Boring Stack
&lt;/h2&gt;

&lt;p&gt;The goal for an indie project is to minimize the distance between an idea and a deployed feature. This means choosing tools you already know. &lt;/p&gt;

&lt;p&gt;If you know Rails, use Rails. If you know Laravel, use Laravel. If you are comfortable with a simple Express server and a Postgres database, stick with that. Using a tool you have mastered allows you to think about the problem instead of the documentation. &lt;/p&gt;

&lt;p&gt;Avoid the temptation to use your indie project as a learning playground for a new language unless the goal of the project is actually learning. If the goal is to ship a product, use the boring stuff. Boring is stable. Boring is fast to write. Boring is easy to debug at 2 AM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture is a Luxury
&lt;/h2&gt;

&lt;p&gt;In a corporate environment, we are taught to separate concerns, create abstract layers, and build modular services. This is necessary when 50 developers are touching the same codebase. It prevents people from stepping on each others toes.&lt;/p&gt;

&lt;p&gt;When you are alone, these abstractions are often just walls you build between yourself and your code. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not build a microservices architecture for a CRUD app.&lt;/li&gt;
&lt;li&gt;Do not create a complex plugin system before you have a single plugin.&lt;/li&gt;
&lt;li&gt;Do not build a generic wrapper for your API calls that handles every possible edge case when you only have three endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write the simplest code that solves the problem. If it becomes a mess later, that is a high class problem because it means you have enough users to justify the time it takes to refactor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 'Ship It' Checklist
&lt;/h2&gt;

&lt;p&gt;Next time you feel the urge to spend a day refactoring your folder structure or adding a new layer of abstraction, ask yourself these three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does this change directly improve the user experience?&lt;/li&gt;
&lt;li&gt;Will this save me more than an hour of work per week in the long run?&lt;/li&gt;
&lt;li&gt;Am I doing this because it is necessary, or because I am afraid to launch?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the answer to all three is no, stop. Close the IDE and go find a way to get your first ten users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Choose a tech stack you already know, build a monolith, and avoid any infrastructure that requires more than ten minutes to set up. Your job is to validate the idea, not to build a masterpiece of software engineering. Ship the ugly version first.&lt;/p&gt;

</description>
      <category>indie</category>
      <category>productivity</category>
      <category>startup</category>
    </item>
    <item>
      <title>SEO for Developers: Stop Worrying About Keywords and Fix Your Rendering</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Wed, 19 Aug 2026 11:00:56 +0000</pubDate>
      <link>https://dev.to/ntty/seo-for-developers-stop-worrying-about-keywords-and-fix-your-rendering-4d1i</link>
      <guid>https://dev.to/ntty/seo-for-developers-stop-worrying-about-keywords-and-fix-your-rendering-4d1i</guid>
      <description>&lt;p&gt;Most developers hate SEO because it feels like voodoo. We are told to "optimize for keywords" or "build backlinks," which sounds like marketing fluff. But there is a side of SEO that is purely engineering. Technical SEO is about making sure a bot can discover, crawl, and render your page without hitting a wall.&lt;/p&gt;

&lt;p&gt;If you are building a modern web app with a framework like Next.js, Nuxt, or Remix, you are already halfway there. But there are specific technical traps that can kill your rankings regardless of how good your content is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Client-Side Rendering Trap
&lt;/h2&gt;

&lt;p&gt;Google can execute JavaScript, but it does not do it instantly. There is a process called the two-wave index. First, Google crawls the HTML. If your page is just a blank div with an id of "root," the bot sees nothing. It then puts the page in a queue for rendering, which happens later when resources are available.&lt;/p&gt;

&lt;p&gt;If your critical content depends on a slow API call that happens in a useEffect hook, you are risking a partial index. The bot might timeout before your data loads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; Use Server-Side Rendering (SSR) or Static Site Generation (SSG) for any page you want to rank. If you must use CSR, ensure your meta tags and primary headings are present in the initial HTML payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crawl Budget and the Zombie Page Problem
&lt;/h2&gt;

&lt;p&gt;Search engines do not spend infinite time on your site. They have a "crawl budget." If you have 10,000 pages of low-quality, auto-generated content (like filter combinations on an e-commerce site), the bot wastes its budget on those instead of your high-value pages.&lt;/p&gt;

&lt;p&gt;I once worked on a project where we had thousands of duplicate pages because of trailing slashes and inconsistent casing in URLs. The bot was crawling the same page four different times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement canonical tags. Tell the bot: "Even if you found this via a weird URL, this is the official version."&lt;/li&gt;
&lt;li&gt;Use a robots.txt file to block paths that provide no value, like /admin or /search-results.&lt;/li&gt;
&lt;li&gt;Set proper HTTP status codes. A 404 should be a 404, not a 200 OK page that says "Not Found."&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Core Web Vitals: The Performance Metric
&lt;/h2&gt;

&lt;p&gt;Google now uses actual user experience metrics as a ranking factor. The most frustrating one for developers is usually Cumulative Layout Shift (CLS).&lt;/p&gt;

&lt;p&gt;CLS happens when a user starts reading a paragraph, and then an image or an ad loads, pushing the text down. It is a jarring experience, and Google penalizes it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always define width and height attributes on images.&lt;/li&gt;
&lt;li&gt;Reserve space for dynamic elements using skeleton screens or min-height CSS.&lt;/li&gt;
&lt;li&gt;Avoid inserting content above existing content unless it is in response to a user action.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Metadata Basics
&lt;/h2&gt;

&lt;p&gt;You do not need to be a copywriter to handle metadata. You just need a system. &lt;/p&gt;

&lt;p&gt;Every page needs a unique title tag and a meta description. If you are building a dynamic site, create a helper function that generates these based on your data. For example, if it is a product page, the title should be "Product Name | Site Name." &lt;/p&gt;

&lt;p&gt;Do not forget the Open Graph (OG) tags. While these do not directly affect Google rankings, they affect how your links look on social media, which drives the traffic that leads to backlinks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop treating SEO as a marketing task. Treat it as a performance and accessibility task. &lt;/p&gt;

&lt;p&gt;If you want your site to rank, focus on this checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the main content in the initial HTML source? (View Source to check).&lt;/li&gt;
&lt;li&gt;Do all images have dimensions to prevent layout shift?&lt;/li&gt;
&lt;li&gt;Are you using canonical tags to prevent duplicate content?&lt;/li&gt;
&lt;li&gt;Does every page return a proper 200, 404, or 301 status code?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you fix the technical foundation, the marketing team's keyword strategy actually has a chance to work.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Vibe Coding: Why Natural Language is the New Compiler</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Tue, 18 Aug 2026 11:00:53 +0000</pubDate>
      <link>https://dev.to/ntty/vibe-coding-why-natural-language-is-the-new-compiler-5c82</link>
      <guid>https://dev.to/ntty/vibe-coding-why-natural-language-is-the-new-compiler-5c82</guid>
      <description>&lt;h2&gt;
  
  
  The Shift to Intent-First Development
&lt;/h2&gt;

&lt;p&gt;For years, the barrier to building software was syntax. You had to know exactly where the semicolon went or how the specific framework handled state. Now, we are entering an era of "vibe coding." It sounds fluffy, but it is actually a shift toward intent-first development. &lt;/p&gt;

&lt;p&gt;In this mode, the developer focuses on the high-level logic, the user flow, and the architecture, while the LLM handles the boilerplate and the API specifics. You are no longer typing every character. You are describing a state, reviewing the output, and iterating based on the result. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Danger of the Magic Button
&lt;/h2&gt;

&lt;p&gt;When you start building via prompts, it is easy to fall into the trap of blind acceptance. You prompt for a feature, the AI spits out 100 lines of code, it works on the first try, and you hit merge. &lt;/p&gt;

&lt;p&gt;This is where most developers mess up. If you do not understand the code the AI wrote, you are not the lead developer anymore. You are a passenger. The moment a bug appears in production, you will be staring at a codebase you did not actually write, trying to debug logic you never conceptualized. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to Vibe Code Without Breaking Things
&lt;/h2&gt;

&lt;p&gt;To make this work, you need a specific workflow. You cannot just "vibe" and hope for the best. You need a feedback loop that keeps you in control.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Pseudo-Code Bridge
&lt;/h3&gt;

&lt;p&gt;Do not go straight from a vague idea to a prompt. Write a brief technical spec in plain text first. &lt;/p&gt;

&lt;p&gt;Instead of saying "Make a login page," say "Create a login component using Tailwind. It needs a validation check for email format, a loading state for the submit button, and it should call the /auth/login endpoint." &lt;/p&gt;

&lt;p&gt;By defining the requirements, you are setting the boundaries. The AI provides the implementation, but you provided the architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Atomic Iteration
&lt;/h3&gt;

&lt;p&gt;Avoid the "mega-prompt." If you ask an AI to build a whole dashboard in one go, you will get a generic, buggy mess. &lt;/p&gt;

&lt;p&gt;Build in tiny increments. Ask for the data model. Then the API route. Then the basic UI. Then the styling. Then the error handling. This allows you to verify the code at every step. If the AI goes off the rails, you only have to revert five lines of code, not five hundred.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The "Explain it Back" Rule
&lt;/h3&gt;

&lt;p&gt;If the AI generates a complex regex or a weird useEffect hook that you do not immediately understand, stop. Ask it: "Why did you choose this approach over X?" &lt;/p&gt;

&lt;p&gt;If the explanation is vague, the code is probably a hallucination or a suboptimal pattern. Force the AI to justify its architectural choices. This turns the tool from a code generator into a pair programmer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Skillset
&lt;/h2&gt;

&lt;p&gt;Being a great developer in this environment is less about memorizing documentation and more about system design. You need to know how a database should be structured, how caching works, and how to secure an endpoint. &lt;/p&gt;

&lt;p&gt;If you do not know the fundamentals, vibe coding will lead you into a wall. But if you do know them, you can build things ten times faster because you are no longer bogged down by the friction of syntax. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop treating AI as a magic box that writes your app. Treat it as a junior developer who is incredibly fast but occasionally lies. &lt;/p&gt;

&lt;p&gt;Your job has shifted from writing code to reviewing code and defining intent. The win is not in how fast you can generate a feature, but in how well you can maintain the system after it is generated. Keep your prompts specific, your iterations small, and your skepticism high.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>llm</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop Over-Engineering Your State Management</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Mon, 17 Aug 2026 11:00:20 +0000</pubDate>
      <link>https://dev.to/ntty/stop-over-engineering-your-state-management-2f4m</link>
      <guid>https://dev.to/ntty/stop-over-engineering-your-state-management-2f4m</guid>
      <description>&lt;p&gt;I spent three years of my career reaching for Redux or Zustand the moment a project felt "medium sized." I thought that was what professional developers did. I would set up slices, actions, and complex store configurations before I even had a working UI. &lt;/p&gt;

&lt;p&gt;Most of the time, I was solving a problem that did not exist. I was managing server cache in a global store, which led to bugs where the UI showed stale data because I forgot to trigger a fetch on a specific page transition. &lt;/p&gt;

&lt;h2&gt;
  
  
  The State Confusion
&lt;/h2&gt;

&lt;p&gt;The biggest mistake we make is treating all state as the same. State is not just one big bucket of data. It falls into three distinct categories: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;UI State: Is this sidebar open? Which tab is active? This belongs in the local component. &lt;/li&gt;
&lt;li&gt;Server Cache: What is the user's profile name? What are the items in the cart? This is just a local copy of data that lives in a database. &lt;/li&gt;
&lt;li&gt;Global App State: The current authenticated user or a preferred theme. This is actually very small.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we put Server Cache into a global store, we create a synchronization nightmare. We end up writing a dozen lines of boilerplate just to update a single string in a database.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Simple Hierarchy
&lt;/h2&gt;

&lt;p&gt;Instead of jumping to a library, try this hierarchy of decision making. &lt;/p&gt;

&lt;p&gt;First, keep it in the component. If only one or two components need the data, use local state. If you are passing props down three levels, that is a smell, but it is often better to just pass the props than to introduce a global store that makes the component non-portable.&lt;/p&gt;

&lt;p&gt;Second, use a dedicated server state tool. If you are using React, tools like TanStack Query handle caching, loading states, and re-fetching automatically. They remove the need to store the results of an API call in a global store. The tool becomes the cache, and your components just hook into the data they need.&lt;/p&gt;

&lt;p&gt;Third, use Context or a small store for truly global data. Your theme or user session does not change every second. Using a simple provider for this is enough. &lt;/p&gt;

&lt;h2&gt;
  
  
  A Real Example of Over-Engineering
&lt;/h2&gt;

&lt;p&gt;I once saw a project where the developer used a global store to track the value of a search input field. Every single keystroke triggered a global action, which updated the store, which re-rendered half the application. &lt;/p&gt;

&lt;p&gt;It was a disaster for performance. The fix was simple: move the input value to a local &lt;code&gt;useState&lt;/code&gt; hook and only trigger the search function when the user hits enter or after a debounce period. &lt;/p&gt;

&lt;p&gt;We often confuse "centralized" with "organized." Centralizing everything in one store does not make it organized. It just makes it a single point of failure that is hard to debug.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Audit Your Current Project
&lt;/h2&gt;

&lt;p&gt;If you feel your state management is getting bloated, do this audit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look at your global store. For every piece of data, ask: "Does this come from an API?" If yes, move it to a server state manager.&lt;/li&gt;
&lt;li&gt;Ask: "Is this used in more than two distant branches of the component tree?" If no, move it to local state or lift it up one level.&lt;/li&gt;
&lt;li&gt;Ask: "Does this data need to persist across page refreshes?" If yes, it belongs in a cookie or localStorage, not just a JS variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Complexity is a cost. Every line of boilerplate you write is a line you have to maintain. Start with the simplest possible way to move data. Use local state first, server state tools second, and global stores only as a last resort. Your bundle size will be smaller, and your brain will be less stressed.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stop treating LLMs like a database</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sun, 16 Aug 2026 11:00:55 +0000</pubDate>
      <link>https://dev.to/ntty/stop-treating-llms-like-a-database-1f61</link>
      <guid>https://dev.to/ntty/stop-treating-llms-like-a-database-1f61</guid>
      <description>&lt;p&gt;I spent three weeks building a feature that relied on an LLM to return structured data about a specific set of API endpoints. During testing, it worked perfectly. In production, it started hallucinating fields that did not exist, and the whole frontend crashed because the JSON was malformed.&lt;/p&gt;

&lt;p&gt;My mistake was treating the model like a database. I expected it to recall specific facts and return them in a strict format every single time. That is not how these models work. They are probability engines, not lookup tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Probability Trap
&lt;/h2&gt;

&lt;p&gt;When you ask an LLM for a specific fact, it is not querying a disk. It is predicting the next most likely token based on weights. If the prompt is slightly different, or if the model version updates, that probability shifts. &lt;/p&gt;

&lt;p&gt;If your application logic depends on the AI always remembering that "User ID is a UUID v4", you are building on sand. The model might get it right 99 times, but the 100th time it will return a string like "The User ID is a UUID v4: 123-abc" and your &lt;code&gt;JSON.parse()&lt;/code&gt; call will explode.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pattern: Separation of Knowledge and Reasoning
&lt;/h2&gt;

&lt;p&gt;To make AI features stable, you have to separate the knowledge (the facts) from the reasoning (the processing).&lt;/p&gt;

&lt;p&gt;Instead of asking the AI to remember your business rules, feed those rules into the prompt as context. This is the core idea behind RAG, but you do not always need a complex vector database to do it. Sometimes a simple system prompt with a list of constants is enough.&lt;/p&gt;

&lt;p&gt;Here is how I restructured my approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Externalize the Truth&lt;/strong&gt;: Put all factual data in a JSON file or a database. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inject Context&lt;/strong&gt;: Fetch the necessary data and inject it into the prompt. Tell the AI: "Using only the following data, perform X task."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema Enforcement&lt;/strong&gt;: Stop hoping for valid JSON. Use a library that enforces a schema (like Zod in TypeScript) to validate the output before it ever touches your application state.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Handling the "Creative" Drift
&lt;/h2&gt;

&lt;p&gt;Even with a strict schema, models drift. I noticed that as I added more context to my prompts, the AI started ignoring the middle section of the instructions. This is a known issue called "lost in the middle."&lt;/p&gt;

&lt;p&gt;To fix this, I started using a technique called few-shot prompting. Instead of telling the AI "Return a list of errors", I gave it three concrete examples of a request and the exact expected response. &lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Input: "The server is down"&lt;br&gt;
Output: { "category": "infrastructure", "severity": "high" }&lt;/p&gt;

&lt;p&gt;Input: "I forgot my password"&lt;br&gt;
Output: { "category": "user-auth", "severity": "low" }&lt;/p&gt;

&lt;p&gt;This anchors the model. It stops guessing the format and starts mimicking the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing for Non-Determinism
&lt;/h2&gt;

&lt;p&gt;Unit tests for AI are different. You cannot test for equality because the output changes. I started implementing "LLM-based evaluation". &lt;/p&gt;

&lt;p&gt;I wrote a separate, more powerful model (like GPT-4) to act as a judge for my smaller, faster production model. The judge model does not check if the strings match. It checks if the &lt;em&gt;intent&lt;/em&gt; and the &lt;em&gt;facts&lt;/em&gt; are correct based on a rubric. &lt;/p&gt;

&lt;p&gt;If the production model says "The price is 10 dollars" and the judge knows the price is 10.00, it passes. If it says "The price is 12 dollars", it fails. This is the only way to scale AI features without manually reading a thousand logs a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;If your code breaks because the AI forgot a detail or changed a word, your architecture is the problem, not the model. &lt;/p&gt;

&lt;p&gt;Move your facts out of the model weights and into your code. Use the LLM for the transformation and reasoning, but keep the source of truth in a place where you can actually version control it. Treat the AI as a flaky intern: give them clear instructions, provide examples, and always double check their work with a validator.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stop Using AI to Write Code, Start Using It to Navigate</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sat, 15 Aug 2026 11:00:56 +0000</pubDate>
      <link>https://dev.to/ntty/stop-using-ai-to-write-code-start-using-it-to-navigate-58no</link>
      <guid>https://dev.to/ntty/stop-using-ai-to-write-code-start-using-it-to-navigate-58no</guid>
      <description>&lt;h2&gt;
  
  
  The trap of the 'Generate' button
&lt;/h2&gt;

&lt;p&gt;When I first started using AI-powered editors like Cursor, I fell into the same trap as everyone else. I would write a prompt, hit generate, and watch a wall of code appear. It felt like a superpower. For the first hour, productivity spiked. By the end of the week, I was spending more time debugging subtle hallucinations than I would have spent writing the code from scratch.&lt;/p&gt;

&lt;p&gt;The problem is that AI is great at syntax but often blind to the architecture of your specific project. It suggests a library you are not using or creates a function that ignores a critical edge case in your data model. When you let the AI drive, you stop thinking about the 'why' and start focusing on 'does this run'.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shifting to AI-assisted navigation
&lt;/h2&gt;

&lt;p&gt;I changed my approach. Instead of asking the AI to write the feature, I started using it to navigate the codebase. This is where the real value lies. &lt;/p&gt;

&lt;p&gt;In a large project, the hardest part is not writing the logic. It is finding where that logic should live. I now use the AI to ask questions like:&lt;/p&gt;

&lt;p&gt;"Where is the logic that handles user session timeouts?"&lt;br&gt;
"Which components are currently consuming the AuthProvider?"&lt;br&gt;
"If I change the schema of the User table, which services will break?"&lt;/p&gt;

&lt;p&gt;By using the AI as a high-speed index for my own code, I stay in control of the architecture. I find the right file, I understand the context, and then I write the actual implementation. The AI helps me get to the starting line faster, but it does not run the race for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 'Review-First' workflow
&lt;/h2&gt;

&lt;p&gt;If you do use the AI to generate a snippet, you have to change how you review it. Most developers accept a diff if it looks correct at a glance. That is a mistake. &lt;/p&gt;

&lt;p&gt;I now treat AI-generated code as if it were written by a junior developer who is very confident but occasionally lies. My review process looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check for imports: Did it import a package I do not have? &lt;/li&gt;
&lt;li&gt;Trace the data flow: Where did this variable come from? Is it actually defined in the scope?&lt;/li&gt;
&lt;li&gt;Search for 'magic' logic: Did it invent a method that does not exist on the object?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you stop trusting the output blindly, you start noticing the patterns the AI uses. You realize it often over-engineers simple tasks. By manually refining the AI's output, you keep the codebase clean and maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better prompts for better context
&lt;/h2&gt;

&lt;p&gt;To make this work, you need to give the AI the right context. Generic prompts get generic results. Instead of saying "Fix this bug", I started being specific about the constraints.&lt;/p&gt;

&lt;p&gt;I use prompts like:&lt;/p&gt;

&lt;p&gt;"Refactor this function to reduce complexity, but do not add any new dependencies and keep the return type as a Promise."&lt;/p&gt;

&lt;p&gt;Giving the AI a set of boundaries prevents it from taking wild guesses. It forces the tool to work within the existing patterns of your project rather than trying to rewrite your style to match its training data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The concrete takeaway
&lt;/h2&gt;

&lt;p&gt;AI editors are not replacement for thinking. They are the world's best grep tool. &lt;/p&gt;

&lt;p&gt;Stop using the AI to generate 50 lines of code at once. Instead, use it to locate the exact line that needs to change, understand the surrounding context, and then write the fix yourself. You will spend less time fixing 'AI bugs' and more time actually building features. The goal is to reduce the distance between an idea and the implementation, not to outsource the implementation entirely.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stop building features and start building 'Waiting States'</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Fri, 14 Aug 2026 11:00:58 +0000</pubDate>
      <link>https://dev.to/ntty/stop-building-features-and-start-building-waiting-states-nmc</link>
      <guid>https://dev.to/ntty/stop-building-features-and-start-building-waiting-states-nmc</guid>
      <description>&lt;h2&gt;
  
  
  The AI Latency Problem
&lt;/h2&gt;

&lt;p&gt;Most of us building AI tools right now are obsessed with tokens per second. We spend hours tweaking prompts and swapping models to shave two seconds off a response. But here is the reality: users are used to waiting. Whether it is a LLM generating a long report or a codebase being indexed, there is always a gap.&lt;/p&gt;

&lt;p&gt;Most developers treat this gap as a bug. We throw a generic loading spinner on the screen and hope the user does not refresh the page. This is a waste of prime real estate. In a traditional app, a loading state is a failure of performance. In an AI app, the loading state is a core part of the user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Psychology of the Wait
&lt;/h2&gt;

&lt;p&gt;There is a huge difference between 'unoccupied time' and 'occupied time'. If a user stares at a blank screen for five seconds, it feels like twenty. If that same user is reading a relevant tip, seeing a progress bar that actually moves, or getting a preview of what is happening, the perceived wait time drops significantly.&lt;/p&gt;

&lt;p&gt;When I started building my first few AI-integrated tools, I ignored the loading states. I focused on the output. I noticed my churn rate was high not because the output was bad, but because users felt the app was 'hanging'. They did not trust the process because I gave them zero feedback during the latency window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning Friction into Value
&lt;/h2&gt;

&lt;p&gt;You can use these wait-states to solve actual business problems. Instead of a spinner, try these patterns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Educational Onboarding&lt;/strong&gt;: Use the 3-5 second gap to show a 'Did you know?' tip about a feature the user has not tried yet. This is a natural way to increase feature adoption without annoying pop-ups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency Logs&lt;/strong&gt;: Show the AI's 'thought process'. Instead of 'Loading...', show 'Searching documentation...', then 'Analyzing context...', then 'Drafting response...'. This builds trust in the result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Micro-Upsells&lt;/strong&gt;: If a user is on a free tier, the wait-state is the perfect place to mention that a Pro plan reduces latency or allows for faster models.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Technical Implementation
&lt;/h2&gt;

&lt;p&gt;Do not hardcode your loading messages. If you do, you will end up with a mess of if-else statements. Create a simple queue of messages or a state machine that cycles through a list of strings based on the current step of your backend pipeline.&lt;/p&gt;

&lt;p&gt;If you are using React or Vue, build a dedicated &lt;code&gt;WaitState&lt;/code&gt; component that accepts a &lt;code&gt;type&lt;/code&gt; prop. This allows you to switch from a 'generic' wait to a 'processing' wait without rewriting your UI logic every time you add a new API call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Monetization Angle
&lt;/h2&gt;

&lt;p&gt;If you are building a B2B tool, your 'wait-state' is actually a place to demonstrate value. For example, if your tool optimizes code, show a live counter of 'Potential bugs being checked' during the wait. You are not just making them wait; you are proving that the tool is working hard for them. This justifies your pricing.&lt;/p&gt;

&lt;p&gt;When developers treat the latency as a product feature rather than a technical debt, the entire feel of the app changes. You stop fighting the model speed and start managing the user's attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Audit your app today. Find every place where a user sees a spinner for more than two seconds. Replace that spinner with either a progress update, a feature tip, or a transparency log. Stop treating the gap as a void and start treating it as a communication channel.&lt;/p&gt;

&lt;p&gt;If you want a cleaner way to handle these transitions, check out &lt;a href="https://waitspin.com" rel="noopener noreferrer"&gt;https://waitspin.com&lt;/a&gt; for some inspiration on better loading experiences.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stop Over-Engineering Your State Management</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Thu, 13 Aug 2026 11:00:56 +0000</pubDate>
      <link>https://dev.to/ntty/stop-over-engineering-your-state-management-1ffo</link>
      <guid>https://dev.to/ntty/stop-over-engineering-your-state-management-1ffo</guid>
      <description>&lt;h2&gt;
  
  
  The Trap of the Global Store
&lt;/h2&gt;

&lt;p&gt;I spent three years of my career thinking that every single piece of data in a web application needed to live in a global store. Whether it was a user profile or whether a dropdown menu was open, it all went into Redux or Vuex. I thought I was being organized. In reality, I was creating a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;When you put everything in a global store, you create invisible dependencies. You change a value in one place, and a component three levels deep in a different branch of the UI tree re-renders for no reason. You end up spending more time debugging the state flow than actually building features.&lt;/p&gt;

&lt;h2&gt;
  
  
  The State Hierarchy Rule
&lt;/h2&gt;

&lt;p&gt;To avoid this, I started following a simple rule: keep state as close to where it is used as possible. &lt;/p&gt;

&lt;h3&gt;
  
  
  1. Local Component State
&lt;/h3&gt;

&lt;p&gt;If a piece of data is only used by one component (or its immediate child), use local state. This includes toggle switches, form input values before submission, and hover states. If you move a 'isModalOpen' boolean to a global store, you have to remember to manually reset it when the component unmounts, or the modal will pop up unexpectedly the next time the user visits that page.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lifted State
&lt;/h3&gt;

&lt;p&gt;If two sibling components need the same data, lift the state to their common parent. Pass the data down via props and pass a callback function to update it. It feels like 'prop drilling' at first, but for 2 or 3 levels, it is far more explicit and easier to trace than a global dispatcher.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Context or Provider Pattern
&lt;/h3&gt;

&lt;p&gt;Use this for truly global data that rarely changes. Think of themes (dark/light mode), authenticated user info, or localization settings. Context is great for avoiding prop drilling, but it is not a replacement for a state management library because it is not optimized for high-frequency updates. If you put a fast-changing timer in a Context provider, you will likely trigger a re-render of your entire app every second.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. External State Libraries
&lt;/h3&gt;

&lt;p&gt;Only reach for a dedicated store (Zustand, Redux, Pinia) when you have complex data dependencies. For example, a collaborative text editor or a complex dashboard where an action in the sidebar must instantly update a chart in the main view and a notification in the header. &lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with Server State
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes I made was treating server data (API responses) the same as UI state. &lt;/p&gt;

&lt;p&gt;Storing API data in a global store usually leads to 'stale data' bugs. You fetch a user list, store it in Redux, and then update a user on the server. Now your global store is out of sync. &lt;/p&gt;

&lt;p&gt;Instead, use a caching layer or a data-fetching hook. Let a dedicated tool handle the loading states, error handling, and cache invalidation. Your global store should only hold the minimal amount of data needed to coordinate the UI, not a mirror of your entire database.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 'Delete' Test
&lt;/h2&gt;

&lt;p&gt;Whenever I am tempted to add a new slice to a global store, I ask myself: 'If I deleted this component, would any other part of the app break?' &lt;/p&gt;

&lt;p&gt;If the answer is no, the state belongs in the component. If the answer is yes, I check if it can be handled by a simple Provider. If it is still too complex, only then does it go into the global store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop starting your projects with a global store by default. Start with local state. Lift it up when it becomes painful. Move it to a Provider when it becomes repetitive. Only implement a full state management library when you can point to a specific, complex data flow that cannot be solved with the built-in tools of your framework. &lt;/p&gt;

&lt;p&gt;Less code in your store means fewer bugs and a faster app.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>SEO for Developers: Stop obsessing over keywords and fix your Core Web Vitals</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Wed, 12 Aug 2026 11:00:35 +0000</pubDate>
      <link>https://dev.to/ntty/seo-for-developers-stop-obsessing-over-keywords-and-fix-your-core-web-vitals-55bd</link>
      <guid>https://dev.to/ntty/seo-for-developers-stop-obsessing-over-keywords-and-fix-your-core-web-vitals-55bd</guid>
      <description>&lt;p&gt;Most developers hate SEO because it feels like magic or marketing fluff. We get told to "add more keywords" or "get more backlinks," which are tasks for content writers and PR people. But there is a massive technical side to SEO that is entirely within our control. &lt;/p&gt;

&lt;p&gt;If your site is slow, has layout shifts, or uses a div for everything, no amount of keyword stuffing will save your rankings. Google cares about user experience. Here is how to handle the technical side of SEO without becoming a marketing expert.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Layout Shift Nightmare
&lt;/h2&gt;

&lt;p&gt;Cumulative Layout Shift (CLS) is one of the most frustrating metrics for users and a signal for search engines. You know when you are about to click a button, but an image finally loads, the page jumps, and you click an ad instead? That is a CLS failure.&lt;/p&gt;

&lt;p&gt;To fix this, stop letting the browser guess the size of your elements. Always define width and height attributes on images. If you are using responsive images with &lt;code&gt;width: 100%&lt;/code&gt;, use the &lt;code&gt;aspect-ratio&lt;/code&gt; CSS property. This reserves the space before the asset downloads, keeping the page stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic HTML is not optional
&lt;/h2&gt;

&lt;p&gt;I see too many modern apps that are just a sea of &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tags. While the browser can render this, search engine crawlers struggle to understand the hierarchy of your information.&lt;/p&gt;

&lt;p&gt;Use the correct tags. A &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; tag tells the crawler where the primary content lives. An &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; tag defines a self contained piece of content. Use &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; through &lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt; in a logical order. Never use an &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; just because you like the font size; use CSS for styling and HTML for meaning. When you use a &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; tag, the crawler knows exactly where your site navigation is, which helps it index your internal links more efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Client-Side Rendering Trap
&lt;/h2&gt;

&lt;p&gt;If you are building a heavy Single Page App (SPA) with React, Vue, or Angular, you might be killing your SEO. While Google can execute JavaScript, it is not as reliable or fast as parsing static HTML. Some crawlers give up if the content takes too long to render.&lt;/p&gt;

&lt;p&gt;If your content is dynamic but needs to be indexed, move to Server-Side Rendering (SSR) or Static Site Generation (SSG). This ensures that when a bot hits your URL, it receives a fully formed HTML document. If you cannot move away from a pure CSR architecture, look into pre-rendering tools that generate static versions of your pages during the build process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metadata and Social Graph
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;meta name="description"&amp;gt;&lt;/code&gt; tags are the primary way your site appears in search results. If you leave these blank or use a generic "Home Page" title, your click-through rate will plummet.&lt;/p&gt;

&lt;p&gt;Beyond basic SEO, implement Open Graph (og:) and Twitter Card tags. These do not directly boost your rank, but they control how your links look when shared on social media. A link with a proper image and a concise summary gets more clicks, which leads to more traffic, which indirectly signals to search engines that your content is valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The robots.txt and Sitemap Duo
&lt;/h2&gt;

&lt;p&gt;Do not let search engines waste their "crawl budget" on pages that do not matter. Your &lt;code&gt;/admin&lt;/code&gt; panel, your &lt;code&gt;/search&lt;/code&gt; results pages, and your &lt;code&gt;/thank-you&lt;/code&gt; pages should not be indexed.&lt;/p&gt;

&lt;p&gt;Use a &lt;code&gt;robots.txt&lt;/code&gt; file to tell bots where they are not allowed to go. Pair this with a &lt;code&gt;sitemap.xml&lt;/code&gt; file. A sitemap is essentially a map of your site that tells the crawler, "Here are the 50 pages I actually care about." This ensures that new content is found and indexed much faster than waiting for the crawler to find a link to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop thinking of SEO as a marketing task. Treat it as a performance and accessibility task. If you focus on fast load times, zero layout shift, and semantic HTML, you are doing 80 percent of the technical work. The rest is just writing good content.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop writing prompts and start building agentic content loops</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Tue, 11 Aug 2026 11:00:53 +0000</pubDate>
      <link>https://dev.to/ntty/stop-writing-prompts-and-start-building-agentic-content-loops-33h6</link>
      <guid>https://dev.to/ntty/stop-writing-prompts-and-start-building-agentic-content-loops-33h6</guid>
      <description>&lt;h2&gt;
  
  
  The prompt engineering trap
&lt;/h2&gt;

&lt;p&gt;Most developers start with a single prompt. You tell an LLM to "write a technical guide about X," you get a generic result, and then you spend an hour manually editing the hallucinations. This is not a workflow. It is just a faster way to get a bad first draft.&lt;/p&gt;

&lt;p&gt;When I first tried to automate my technical blog, I thought the solution was a longer prompt. I spent days perfecting a 500 word system instruction. It still failed because the LLM cannot verify its own claims in a single pass. It just predicts the next token.&lt;/p&gt;

&lt;p&gt;To get production-ready content, you need to move from a linear prompt to an agentic loop. This means breaking the task into roles: a researcher, a writer, and a critic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture of a Content Loop
&lt;/h2&gt;

&lt;p&gt;An agentic workflow treats content as a state machine. Instead of one big call, you chain several small, specialized calls that check each other's work.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Research Agent
&lt;/h3&gt;

&lt;p&gt;This agent does not write. Its only job is to find facts. Give it access to your codebase or a set of documentation URLs. Ask it to produce a structured JSON object of key technical constraints, API endpoints, and edge cases. If it cannot find a specific fact, it must flag it as "missing" rather than guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Draft Agent
&lt;/h3&gt;

&lt;p&gt;This agent takes the JSON from the researcher and turns it into prose. Because the facts are already locked in, the writer cannot hallucinate as easily. The goal here is structure and flow, not accuracy. Accuracy was handled in the previous step.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Critic Agent (The Most Important Part)
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens. The critic agent is given the original research data and the draft. Its prompt is simple: "Find three things in this draft that contradict the research or sound like marketing fluff." &lt;/p&gt;

&lt;p&gt;If the critic finds errors, the draft is sent back to the writer with the feedback. This loop continues until the critic gives a thumbs up. This is a self-correcting system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing this with Code
&lt;/h2&gt;

&lt;p&gt;You do not need a heavy framework to start. A few Python scripts or a Node.js loop will work. The key is the data hand-off.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Research Phase&lt;/strong&gt;: Output a Markdown list of facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draft Phase&lt;/strong&gt;: Use those facts as context blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review Phase&lt;/strong&gt;: Use a boolean check (Pass/Fail). If Fail, loop back to Draft.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One common mistake is letting the agent decide when it is finished. Agents are too polite. They will say "This looks great!" just to end the task. You need to force the critic to be pedantic. Tell it that its only reward is finding mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling to GEO (Generative Engine Optimization)
&lt;/h2&gt;

&lt;p&gt;We are moving from a world of SEO to GEO. People are not just clicking links; they are asking Perplexity or ChatGPT for a summary of a solution. These engines prioritize cited, factual, and structured data.&lt;/p&gt;

&lt;p&gt;To optimize for this, your agentic loop should specifically target "cite-able" moments. Instead of saying "Our API is fast," the agent should be forced to say "Our API responds in 40ms as shown in the benchmark tests." &lt;/p&gt;

&lt;p&gt;When you provide concrete data and clear citations, LLMs are more likely to pick up your content as a primary source for their users. This is how you win in the age of AI search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop trying to find the perfect prompt. Instead, build a pipeline: Research -&amp;gt; Draft -&amp;gt; Critic -&amp;gt; Refine. By separating the factual research from the creative writing, you eliminate 80% of hallucinations and create content that actually helps developers.&lt;/p&gt;

&lt;p&gt;I use Citedy (&lt;a href="https://www.citedy.com" rel="noopener noreferrer"&gt;https://www.citedy.com&lt;/a&gt;) to help manage the sourcing and citation side of this process, ensuring the facts stay grounded.&lt;/p&gt;

&lt;p&gt;Build the loop, not the prompt.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
