<?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 Treating LLM Prompts Like Magic Spells</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Mon, 03 Aug 2026 11:00:53 +0000</pubDate>
      <link>https://dev.to/ntty/stop-treating-llm-prompts-like-magic-spells-2319</link>
      <guid>https://dev.to/ntty/stop-treating-llm-prompts-like-magic-spells-2319</guid>
      <description>&lt;p&gt;I spent three weeks trying to write the 'perfect' prompt for a complex data extraction task. I spent hours tweaking adjectives, adding 'think step by step', and begging the model to be precise. I felt like a wizard trying to find the exact sequence of words to unlock a secret door.&lt;/p&gt;

&lt;p&gt;Then I realized I was treating the LLM like a black box of magic instead of a piece of flaky software. &lt;/p&gt;

&lt;p&gt;If you are spending your day manually tweaking a single prompt in a chat window, you are not engineering. You are guessing. Here is how to actually handle prompts in a production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fallacy of the Perfect Prompt
&lt;/h2&gt;

&lt;p&gt;Many developers believe there is a single, gold-standard prompt that will work 100% of the time. This is a lie. Models update, temperature settings fluctuate, and input data varies. A prompt that works for ten test cases might fail on the eleventh because the user added a weird line break or a specific character.&lt;/p&gt;

&lt;p&gt;When you rely on a single 'magic' prompt, you create a fragile system. One small change to the model version and your entire pipeline breaks. Instead of searching for the perfect string of text, you need a system for validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat Prompts as Code
&lt;/h2&gt;

&lt;p&gt;Prompts are logic. They should be versioned just like your Python or TypeScript files. If you are hardcoding prompts inside your application logic, you are making a mistake.&lt;/p&gt;

&lt;p&gt;Move your prompts into separate configuration files or a dedicated database. This allows you to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Version control your prompts using Git.&lt;/li&gt;
&lt;li&gt;Roll back to a previous version instantly when a new prompt causes regressions.&lt;/li&gt;
&lt;li&gt;Test multiple versions of a prompt against the same dataset without redeploying the whole app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Build a Simple Eval Suite
&lt;/h2&gt;

&lt;p&gt;This is the part most developers skip because it feels tedious. You cannot improve what you cannot measure. &lt;/p&gt;

&lt;p&gt;Stop using 'vibes' to determine if a prompt is working. 'It looks better now' is not a metric. Instead, build a basic evaluation script. Create a JSON file containing 20 to 50 representative inputs and the expected outputs.&lt;/p&gt;

&lt;p&gt;Every time you change a word in your prompt, run the script. Compare the new outputs against your ground truth. &lt;/p&gt;

&lt;p&gt;If you are extracting JSON, your eval should check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the output valid JSON?&lt;/li&gt;
&lt;li&gt;Are the required keys present?&lt;/li&gt;
&lt;li&gt;Is the data type correct?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are generating text, use a second, more powerful model to grade the output of your smaller, faster model based on a rubric. This is called LLM-as-a-judge, and it is far more scalable than manual review.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of Few-Shot Examples
&lt;/h2&gt;

&lt;p&gt;If you are writing a paragraph of instructions to explain a format, stop. You are wasting tokens and confusing the model.&lt;/p&gt;

&lt;p&gt;Models learn patterns better than instructions. Instead of saying 'Please return the date in YYYY-MM-DD format and make sure the city is capitalized', just provide three examples of input and output.&lt;/p&gt;

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

&lt;p&gt;Input: I live in london and today is Jan 1st 2023&lt;br&gt;
Output: { "city": "London", "date": "2023-01-01" }&lt;/p&gt;

&lt;p&gt;Input: New york city, 12th of May 2022&lt;br&gt;
Output: { "city": "New York", "date": "2022-05-12" }&lt;/p&gt;

&lt;p&gt;This is called few-shot prompting. It reduces ambiguity and gives the model a concrete pattern to follow. It is almost always more effective than adding more adjectives to your instructions.&lt;/p&gt;

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

&lt;p&gt;Stop obsessing over the wording of a single prompt. Instead, build a pipeline: Versioned Prompts -&amp;gt; Eval Suite -&amp;gt; Iteration. &lt;/p&gt;

&lt;p&gt;If you cannot prove that prompt B is 5% better than prompt A across 50 test cases, you are just guessing. Treat your prompts as unstable code that requires tests, not as magic spells that require faith.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop over-engineering your state management</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sun, 02 Aug 2026 11:00:18 +0000</pubDate>
      <link>https://dev.to/ntty/stop-over-engineering-your-state-management-30gm</link>
      <guid>https://dev.to/ntty/stop-over-engineering-your-state-management-30gm</guid>
      <description>&lt;p&gt;I spent three years of my career adding Redux to every single project I touched. I thought that was what professional developers did. I built complex store architectures, wrote endless boilerplate for simple toggles, and spent hours debugging why a specific action did not trigger a re-render. &lt;/p&gt;

&lt;p&gt;Eventually, I realized I was solving problems I did not actually have. &lt;/p&gt;

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

&lt;p&gt;When you start a new project, the instinct is to prepare for scale. You think, "What if this app grows to 50 pages? I will need a central place for all my data." This is a classic trap. You end up building a complex system to manage data that only two components actually care about. &lt;/p&gt;

&lt;p&gt;Global state is an expensive tool. It adds cognitive load. Every time you want to change a single string, you have to jump between a slice, an action, a reducer, and the component. For most apps, this is a waste of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the simplest tool
&lt;/h2&gt;

&lt;p&gt;Most state is not actually global. It is either local or server state. &lt;/p&gt;

&lt;h3&gt;
  
  
  Local State
&lt;/h3&gt;

&lt;p&gt;If a piece of data is only used by a component and its immediate children, keep it in the component. If you find yourself "prop drilling" (passing data through five layers of components), do not immediately reach for a global store. Try moving the state up to the nearest common ancestor first. &lt;/p&gt;

&lt;h3&gt;
  
  
  Server State
&lt;/h3&gt;

&lt;p&gt;This is where most developers get confused. They store API responses in a global store. But an API response is not "state" in the traditional sense. It is a cache of data that lives on a server. &lt;/p&gt;

&lt;p&gt;Using a dedicated data fetching library handles caching, loading states, and re-fetching automatically. When you move server data out of your global store, you will find that 80 percent of your Redux or Vuex code simply disappears. &lt;/p&gt;

&lt;h2&gt;
  
  
  When to actually use global state
&lt;/h2&gt;

&lt;p&gt;Global state is for data that truly spans the entire application and changes frequently. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User authentication status&lt;/li&gt;
&lt;li&gt;Theme settings (dark vs light mode)&lt;/li&gt;
&lt;li&gt;A complex shopping cart in a large e-commerce site&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even then, you do not always need a heavy library. The Context API in React or simple reactive stores in Vue and Svelte are usually enough for these use cases. &lt;/p&gt;

&lt;h2&gt;
  
  
  A practical migration strategy
&lt;/h2&gt;

&lt;p&gt;If you are currently staring at a bloated store, do not rewrite everything overnight. Try this approach instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify one piece of state in your store. &lt;/li&gt;
&lt;li&gt;Ask: "Which components actually use this?"&lt;/li&gt;
&lt;li&gt;If it is only one branch of the component tree, move it to a local state or a Context provider wrapping only that branch.&lt;/li&gt;
&lt;li&gt;If it is just a cached API response, move it to a fetching hook.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The mental shift
&lt;/h2&gt;

&lt;p&gt;Writing less code is a skill. It is easy to add a library. It is hard to resist adding one. The goal is not to use the most powerful tool, but the one that makes the code easiest to reason about six months from now. &lt;/p&gt;

&lt;p&gt;When I stopped treating global state as the default, my development speed increased. I spent less time writing boilerplate and more time building actual features. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Before adding a state management library, try to solve the problem with local state and a good data fetching strategy. If you still feel the pain, only then should you reach for a global store.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop building 'Chatbots' and start building Agentic Workflows</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sat, 01 Aug 2026 11:00:18 +0000</pubDate>
      <link>https://dev.to/ntty/stop-building-chatbots-and-start-building-agentic-workflows-1b4n</link>
      <guid>https://dev.to/ntty/stop-building-chatbots-and-start-building-agentic-workflows-1b4n</guid>
      <description>&lt;h2&gt;
  
  
  The Wall of Single Prompts
&lt;/h2&gt;

&lt;p&gt;Most developers start with a simple pattern: user input goes in, the LLM processes it, and a response comes out. We call this a zero-shot or few-shot prompt. It works for summarizing a paragraph or writing a basic function. But the second you ask it to perform a complex task, like "Research this company and write a personalized sales email based on their latest SEC filing," it falls apart.&lt;/p&gt;

&lt;p&gt;It will hallucinate the filing, miss a key detail, or simply forget the constraints you set in the first paragraph. This is because you are treating the LLM as a magic box rather than a processor. To get actual reliability, you need to move toward agentic workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually makes a workflow 'Agentic'?
&lt;/h2&gt;

&lt;p&gt;An agentic workflow is not about a more powerful model. It is about the architecture around the model. Instead of one long prompt, you break the task into a loop of reasoning, acting, and observing.&lt;/p&gt;

&lt;p&gt;Think of it like a junior developer. You would never tell a junior, "Build the entire authentication system and tell me when it is done." You would tell them to design the schema, review it with you, write the tests, and then implement the code. &lt;/p&gt;

&lt;p&gt;In an agentic system, this looks like a cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Planning&lt;/strong&gt;: The LLM breaks the goal into smaller steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Use&lt;/strong&gt;: The LLM decides which tool (API, database, search) it needs to execute a step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observation&lt;/strong&gt;: The LLM looks at the output of the tool and determines if it solved the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correction&lt;/strong&gt;: If the output was an error or incomplete, the LLM adjusts its plan and tries again.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A Practical Pattern: The Reflection Loop
&lt;/h2&gt;

&lt;p&gt;One of the simplest agentic patterns to implement is the Reflection Loop. Instead of taking the first answer, you force the LLM to critique itself.&lt;/p&gt;

&lt;p&gt;Here is how I implement this in my projects:&lt;/p&gt;

&lt;p&gt;First, I have a "Generator" prompt. It produces the initial code or text. &lt;/p&gt;

&lt;p&gt;Second, I pass that output to a "Critic" prompt. This prompt is told to be pedantic. It looks for edge cases, security flaws, or deviations from the original requirements. It returns a list of specific improvements.&lt;/p&gt;

&lt;p&gt;Third, the Generator receives the original goal and the Critic's feedback to produce a second version.&lt;/p&gt;

&lt;p&gt;I have found that this simple loop reduces logic errors by about 30 percent compared to a single high-quality prompt. You are essentially trading latency and token cost for accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with the 'Infinite Loop' Problem
&lt;/h2&gt;

&lt;p&gt;When you give an LLM the ability to loop, you risk the infinite loop. The agent keeps trying the same failing API call over and over because it thinks it is "almost there."&lt;/p&gt;

&lt;p&gt;To prevent this, you need hard constraints. I use three specific guardrails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Max Iterations&lt;/strong&gt;: Set a hard limit (usually 5 to 10) on how many times the agent can loop. If it hits the limit, it must return a failure message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Tracking&lt;/strong&gt;: Keep a history of the tools called and the results. If the agent attempts the exact same tool call with the exact same arguments twice, force a state change or trigger a human intervention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Budgeting&lt;/strong&gt;: Monitor the context window. Agentic loops eat tokens quickly. If the history gets too long, the agent loses the original goal. I use a sliding window or summarize the previous steps to keep the context clean.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Stop trying to write the "perfect prompt." It does not exist. The prompt is just the starting point.&lt;/p&gt;

&lt;p&gt;If you want a system that actually works in production, stop treating the LLM as a writer and start treating it as a controller. Break your process into a sequence of small, verifiable steps. Give the model a way to check its own work. &lt;/p&gt;

&lt;p&gt;Build a loop, not a line.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Vibecoding: Why High-Level Intent is the New Syntax</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Fri, 31 Jul 2026 11:00:06 +0000</pubDate>
      <link>https://dev.to/ntty/vibecoding-why-high-level-intent-is-the-new-syntax-4mfa</link>
      <guid>https://dev.to/ntty/vibecoding-why-high-level-intent-is-the-new-syntax-4mfa</guid>
      <description>&lt;p&gt;I spent the last decade obsessing over syntax. I memorized the exact way to map over an array in five different languages. I spent hours debating tabs versus spaces and whether a specific design pattern was the most 'correct' way to structure a class. &lt;/p&gt;

&lt;p&gt;Recently, my workflow shifted. I started using LLMs not just for snippets, but for entire feature blocks. Some people call this 'vibecoding'. It sounds fluffy, but in practice, it is a shift from being a translator (turning a thought into code) to being an architect (defining the intent and verifying the result).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shift to Intent-Based Development
&lt;/h2&gt;

&lt;p&gt;For a long time, the bottleneck in software was the implementation. You knew what you wanted, but you had to spend three hours fighting a CSS grid or debugging a race condition in a promise chain. &lt;/p&gt;

&lt;p&gt;Now, the bottleneck is the specification. When you can generate 50 lines of working TypeScript in three seconds, the skill is no longer about knowing where the semicolons go. The skill is knowing exactly what the system should do and how it should fail. &lt;/p&gt;

&lt;p&gt;If your prompt is 'make a login page', you get a generic, buggy mess. If your prompt is 'create a login form with Zod validation for email formats, a loading state for the submit button, and a specific error boundary for 401 responses', you get a professional feature. The 'vibe' is actually just high-level technical intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Danger of the Black Box
&lt;/h2&gt;

&lt;p&gt;There is a trap here. When you stop writing every line, it is easy to stop understanding how the code actually works. I call this the 'Black Box Effect'. &lt;/p&gt;

&lt;p&gt;I recently saw a project where the developer had generated a complex state management system they did not actually understand. When a production bug hit, they were paralyzed. They could not fix the bug because they had not 'authored' the logic, they had only 'approved' it. &lt;/p&gt;

&lt;p&gt;To avoid this, you have to change how you review code. You cannot just check if it runs. You have to interrogate the AI. Ask it: 'Why did you choose this approach over X?' or 'What happens to this function if the API returns a null value?'. &lt;/p&gt;

&lt;h2&gt;
  
  
  The New Developer Skill Tree
&lt;/h2&gt;

&lt;p&gt;If the AI handles the syntax, what should we actually be studying? &lt;/p&gt;

&lt;p&gt;First, System Design. Understanding how a database interacts with a cache or how a message queue handles spikes is more important than ever. The AI can write the function, but it often struggles to design the whole system architecture without guidance.&lt;/p&gt;

&lt;p&gt;Second, Debugging and Testing. When you generate code quickly, you create technical debt quickly. Your ability to write robust integration tests is what keeps the project from collapsing. You need to be the quality assurance lead for your own AI-generated codebase.&lt;/p&gt;

&lt;p&gt;Third, Domain Knowledge. Knowing the actual business problem you are solving. The AI does not know that your users hate a specific UX pattern or that your industry has weird legal requirements for data storage. That is where your value lies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Workflow Tips
&lt;/h2&gt;

&lt;p&gt;Here is how I have integrated this into my daily routine without losing my edge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pseudo-code first. I write a list of requirements in plain English before I touch the AI. This forces me to think through the logic.&lt;/li&gt;
&lt;li&gt;Incremental generation. Never ask for a whole app at once. Ask for the data model, then the API layer, then the UI. It makes the review process manageable.&lt;/li&gt;
&lt;li&gt;Manual refactoring. I always spend 10 minutes cleaning up the generated code. I rename variables for clarity and remove redundant logic. This ensures I have actually read and understood every line.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Coding is not disappearing, but the act of typing is becoming secondary to the act of thinking. The goal is to move from 'how do I write this' to 'what should I build'. &lt;/p&gt;

&lt;p&gt;Don't let the speed of AI make you lazy. Use the time you save on syntax to dive deeper into architecture, security, and user experience. The best developers of the next few years will not be the ones who can prompt the best, but the ones who can verify the most.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>SEO for Developers: Stop Over-Engineering Your Meta Tags</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Thu, 30 Jul 2026 11:00:06 +0000</pubDate>
      <link>https://dev.to/ntty/seo-for-developers-stop-over-engineering-your-meta-tags-3172</link>
      <guid>https://dev.to/ntty/seo-for-developers-stop-over-engineering-your-meta-tags-3172</guid>
      <description>&lt;p&gt;I spent three years thinking SEO was a magic black box. I thought as long as I had a sitemap.xml and some meta tags, the search engines would just figure it out. Then I built a project that had perfect lighthouse scores but zero traffic. That is when I realized that technical SEO is not about checking boxes. It is about how a crawler perceives your data structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Web Vitals Trap
&lt;/h2&gt;

&lt;p&gt;We love our 100/100 Lighthouse scores. But here is the reality: a fast site that has no structure will still rank lower than a slower site that is easy to parse. Do not spend forty hours optimizing an image by 2kb if your heading hierarchy is a mess.&lt;/p&gt;

&lt;p&gt;Focus on Cumulative Layout Shift (CLS). Nothing kills a ranking faster than a page that jumps around while loading. If your hero image does not have defined dimensions, the browser pushes the content down. Google sees this as a poor user experience and penalizes it. Set your width and height attributes explicitly. It is a boring fix, but it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop Using Divs for Everything
&lt;/h2&gt;

&lt;p&gt;I see this in almost every modern React or Vue project. Developers use a div for a button, a div for a header, and a div for the main content. To you, the CSS makes it look like a header. To a crawler, it is just a generic box.&lt;/p&gt;

&lt;p&gt;Use semantic HTML. Use &lt;/p&gt;, , , and . When you use an &lt;h1&gt;, make sure there is only one per page. If you have five h1 tags, you are telling the crawler that five different things are the most important part of the page. That dilutes your signal.&lt;/h1&gt;



&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  The JSON-LD Secret&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Meta tags are the bare minimum. If you want to actually rank, you need Structured Data. This is where JSON-LD comes in. Instead of hoping the crawler understands your page, you tell it exactly what the page is using a script tag with type="application/ld+json".&lt;/p&gt;

&lt;p&gt;If you are building a blog, use the "BlogPosting" schema. If you are building a tool, use "SoftwareApplication". This allows search engines to create rich snippets, like showing star ratings or price points directly in the search results. This increases your click through rate far more than a slightly better meta description ever will.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Client Side Rendering (CSR)
&lt;/h2&gt;

&lt;p&gt;If you are using a framework like React or Vue without a meta-framework (like Next.js or Nuxt), you have a problem. Search engines do execute JavaScript, but they do it in two passes. First, they index the raw HTML. Then, they come back later to render the JS. &lt;/p&gt;

&lt;p&gt;If your critical content only appears after a fetch call in a useEffect hook, you are gambling with your indexing speed. If you cannot move to Server Side Rendering (SSR), use pre-rendering tools to generate static HTML for your main landing pages. You want the crawler to see the content in the first request, not the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  URL Structure and Slugs
&lt;/h2&gt;

&lt;p&gt;Stop using IDs in your URLs. A URL like /post/12345 tells a user and a crawler nothing. A URL like /post/how-to-fix-memory-leaks tells them exactly what to expect. &lt;/p&gt;

&lt;p&gt;When building your API, create a slug field in your database. Index that field. Use the slug in the URL and the h1 tag. This creates a keyword reinforcement loop that search engines love.&lt;/p&gt;

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

&lt;p&gt;SEO is not about hacking an algorithm. It is about making your site accessible and predictable. If you want better rankings, follow this checklist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use one h1 per page and follow a logical h2 to h6 hierarchy.&lt;/li&gt;
&lt;li&gt;Implement JSON-LD structured data for your primary entity types.&lt;/li&gt;
&lt;li&gt;Ensure your images have height and width to stop layout shift.&lt;/li&gt;
&lt;li&gt;Use semantic HTML tags instead of generic divs.&lt;/li&gt;
&lt;li&gt;Ensure your primary content is present in the initial HTML response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stop chasing the perfect score and start focusing on how a machine reads your page.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop treating LLMs like a Search Engine</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Wed, 29 Jul 2026 11:00:51 +0000</pubDate>
      <link>https://dev.to/ntty/stop-treating-llms-like-a-search-engine-36if</link>
      <guid>https://dev.to/ntty/stop-treating-llms-like-a-search-engine-36if</guid>
      <description>&lt;p&gt;I spent the first few months of using LLMs for coding making the same mistake most of us do. I treated the prompt box like a Google search bar. I would type 'How to implement a debounced search in React' and then copy-paste the first block of code the AI spat out. &lt;/p&gt;

&lt;p&gt;It worked 70% of the time. The other 30% was a nightmare of deprecated hooks, weird edge cases, and hallucinations that took me longer to debug than if I had just read the documentation. &lt;/p&gt;

&lt;p&gt;Here is the reality: LLMs are not databases. They are pattern matchers. When you ask a general question, you get a general (and often outdated) answer. To get production-ready code, you have to change how you communicate with the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Context Gap
&lt;/h2&gt;

&lt;p&gt;The biggest reason AI gives you bad code is a lack of context. The model does not know your project structure, your TypeScript configuration, or your team's linting rules. When you ask for a snippet, it fills those gaps with the most common patterns it saw during training. &lt;/p&gt;

&lt;p&gt;If you are using a modern version of a library but the model was trained on a version from two years ago, it will confidently give you code that throws a syntax error. &lt;/p&gt;

&lt;h2&gt;
  
  
  Shift to Specification-Driven Prompting
&lt;/h2&gt;

&lt;p&gt;Instead of asking 'How do I do X', start providing the constraints first. I call this specification-driven prompting. You should define the environment, the goal, and the boundaries before you ask for the code.&lt;/p&gt;

&lt;p&gt;Try this structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Role&lt;/strong&gt;: 'You are a senior TypeScript engineer focusing on performance.'&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt;: 'I am using React 18 with Vite and Tailwind CSS.'&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraint&lt;/strong&gt;: 'Do not use external libraries for the debounce logic. Keep it under 20 lines of code.'&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal&lt;/strong&gt;: 'Create a hook that handles a search input with a 300ms delay.'&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By narrowing the field, you stop the model from guessing. You are effectively telling it which part of its training data to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Iterative Refinement Loop
&lt;/h2&gt;

&lt;p&gt;One of the worst habits is the 'one-shot' attempt. If the first response is slightly off, most devs just tweak the prompt and try again from scratch. &lt;/p&gt;

&lt;p&gt;Instead, treat it like a code review. If the AI gives you a function that is almost right but misses a null check, do not rewrite the whole prompt. Tell it: 'The logic is correct, but it will crash if the API returns a 404. Add a guard clause for that.'&lt;/p&gt;

&lt;p&gt;This iterative approach does two things. First, it keeps the conversation focused on the specific problem. Second, it forces you to actually read the code rather than blindly trusting the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Hallucinations in Libraries
&lt;/h2&gt;

&lt;p&gt;We have all seen it: the AI suggests a method like &lt;code&gt;.toFormattedJSON()&lt;/code&gt; that does not actually exist in the library. This happens because the model sees similar patterns in other libraries and assumes it exists here too.&lt;/p&gt;

&lt;p&gt;To stop this, I started a habit of pasting the actual documentation for the specific function I am struggling with into the prompt. &lt;/p&gt;

&lt;p&gt;'Here is the documentation for the SDK method: [Paste Text]. Based on this specific API, how should I handle the authentication flow?'&lt;/p&gt;

&lt;p&gt;When you provide the source of truth, the AI stops guessing and starts processing. You move from 'creative writing' mode to 'logic processing' mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hard Truth about AI Coding
&lt;/h2&gt;

&lt;p&gt;AI is a force multiplier, but it multiplies whatever you put into it. If you put in lazy, vague prompts, you get lazy, buggy code. If you put in precise specifications, you get a tool that handles the boilerplate so you can focus on the architecture.&lt;/p&gt;

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

&lt;p&gt;Stop using single-sentence prompts. Use the 'Role, Context, Constraint, Goal' framework. If the code looks too perfect to be true, it is probably using a library method that does not exist. Always provide the documentation snippet for niche libraries to eliminate hallucinations.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>llm</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop Building Your SaaS Like a Giant Enterprise App</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Tue, 28 Jul 2026 11:00:52 +0000</pubDate>
      <link>https://dev.to/ntty/stop-building-your-saas-like-a-giant-enterprise-app-5d7p</link>
      <guid>https://dev.to/ntty/stop-building-your-saas-like-a-giant-enterprise-app-5d7p</guid>
      <description>&lt;p&gt;I spent three months building a multi-tenant architecture for a project that ended up having four users. I used a microservices approach, a distributed message queue, and a complex database partitioning strategy because I was terrified of "scaling issues" before I even had a single paying customer.&lt;/p&gt;

&lt;p&gt;I treated my MVP like it was already a Fortune 500 product. This is a common trap for developers. We love the technical challenge of scale, but in a SaaS startup, the biggest risk is not technical scale. The risk is building something nobody wants.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fallacy of Future-Proofing
&lt;/h2&gt;

&lt;p&gt;When you start, you feel the urge to make every decision a "permanent" one. You spend days debating whether to use NoSQL or PostgreSQL, or if you should use Kubernetes for a simple API. &lt;/p&gt;

&lt;p&gt;Here is the truth: your requirements will change completely once real users touch the product. That complex permission system you spent two weeks on? Your users might not even need it. That caching layer you built to handle millions of requests? It just adds latency and debugging pain while you only have ten users.&lt;/p&gt;

&lt;p&gt;Future-proofing is often just procrastination disguised as diligence. If you build for a million users on day one, you are optimizing for a problem you hope to have, while ignoring the problem you actually have: no product-market fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Boring Stack Advantage
&lt;/h2&gt;

&lt;p&gt;If you want to ship fast, use a boring stack. A boring stack consists of technologies that are stable, have massive community support, and do not require a specialized DevOps engineer to maintain.&lt;/p&gt;

&lt;p&gt;Choose a monolithic framework. Whether it is Rails, Laravel, Django, or Next.js, stay in one codebase. A monolith allows you to refactor quickly. Changing a database column across three microservices is a nightmare. Changing it in one monolith is a five-second migration.&lt;/p&gt;

&lt;p&gt;Use a relational database. PostgreSQL is the gold standard for a reason. It handles structured data, JSONB for the flexible bits, and it is incredibly reliable. Do not reach for a graph database or a specialized time-series store unless your core feature literally cannot function without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Multi-Tenancy Without the Headache
&lt;/h2&gt;

&lt;p&gt;One of the biggest points of over-engineering in SaaS is tenant isolation. You might be tempted to create a separate database for every customer to ensure "maximum security."&lt;/p&gt;

&lt;p&gt;For 99 percent of early-stage SaaS apps, a simple &lt;code&gt;tenant_id&lt;/code&gt; column on every table is enough. Use a foreign key to link data to a company or user. If you are worried about data leaking between customers, implement a global scope or a middleware that injects the &lt;code&gt;tenant_id&lt;/code&gt; into every query.&lt;/p&gt;

&lt;p&gt;This approach makes migrations simple. You run one script, and every customer is updated. If you have 500 separate databases, you now have a distributed systems problem to solve just to add a single field to a user profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Actually Refactor
&lt;/h2&gt;

&lt;p&gt;Does this mean you should write bad code? No. It means you should write simple code that is easy to delete.&lt;/p&gt;

&lt;p&gt;Write clean functions and keep your business logic separate from your framework code. If you keep your logic decoupled, you can move a specific module into a separate service later when the load actually justifies it. &lt;/p&gt;

&lt;p&gt;Wait for the pain. Do not optimize until you see the bottleneck in your logs. If a query is slow, add an index. If the server is crashing, increase the RAM. Only when you hit a hard wall should you spend a week rewriting a module for performance.&lt;/p&gt;

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

&lt;p&gt;Your goal in the first six months of a SaaS is to minimize the time between an idea and a deployed feature. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a monolith.&lt;/li&gt;
&lt;li&gt;Use a single relational database with a &lt;code&gt;tenant_id&lt;/code&gt; column.&lt;/li&gt;
&lt;li&gt;Avoid any tool that requires its own dedicated server to run.&lt;/li&gt;
&lt;li&gt;Optimize for delete-ability, not scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build the simplest version that solves the problem. The "scaling problems" are a high-quality problem to have. Get there first.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>saas</category>
      <category>startup</category>
    </item>
    <item>
      <title>Stop treating LLMs like search engines</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Mon, 27 Jul 2026 11:01:10 +0000</pubDate>
      <link>https://dev.to/ntty/stop-treating-llms-like-search-engines-3m3c</link>
      <guid>https://dev.to/ntty/stop-treating-llms-like-search-engines-3m3c</guid>
      <description>&lt;p&gt;I spent the first six months of the AI boom treating ChatGPT and Claude like a better version of Google. I would type in a problem, get a snippet of code, paste it into my IDE, and then spend twenty minutes debugging why it didn't actually work in my specific environment. &lt;/p&gt;

&lt;p&gt;Most developers do this. We treat the prompt as a search query. But LLMs are not databases of facts. They are pattern matchers. When you ask a search engine for a solution, it finds a page where someone already solved it. When you ask an LLM, it predicts the most likely next token based on a massive pile of training data. &lt;/p&gt;

&lt;p&gt;If your prompt is vague, the model fills the gaps with the most generic patterns it knows. That is why you get boilerplate code that looks correct but fails on the edge cases of your actual project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context gap
&lt;/h2&gt;

&lt;p&gt;The biggest reason AI generates buggy code is the context gap. The model does not know your project structure, your specific version of a library, or your internal naming conventions. &lt;/p&gt;

&lt;p&gt;Instead of asking "How do I implement a file upload in Node.js?", which will give you a generic example using a library you might not even use, you need to provide the constraints. &lt;/p&gt;

&lt;p&gt;I started using a pattern I call "Constraint First Prompting". I define the boundaries before I ask for the logic. &lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I am using Node 20 and Express 4.18."&lt;/li&gt;
&lt;li&gt;"I already have a middleware for auth called checkAuth."&lt;/li&gt;
&lt;li&gt;"The files must be stored in an S3 bucket, not locally."&lt;/li&gt;
&lt;li&gt;"I want the error handling to follow the format of my existing GlobalErrorHandler class."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you give the model a box to work inside, it stops guessing. &lt;/p&gt;

&lt;h2&gt;
  
  
  Chain of Thought is not just for the AI
&lt;/h2&gt;

&lt;p&gt;You have probably heard of Chain of Thought (CoT) prompting, where you tell the AI to "think step by step". While that helps the model, it is even more useful when you force yourself to define the steps first.&lt;/p&gt;

&lt;p&gt;When I have a complex feature, I no longer ask the AI to "write the function". I ask it to "outline the logic for the function in pseudocode". &lt;/p&gt;

&lt;p&gt;Once the AI gives me the logical steps, I review them. If step 3 is wrong, I correct it there. It is ten times faster to fix a line of pseudocode than it is to debug 50 lines of generated TypeScript. Once the logic is locked in, I tell it: "Now implement this exact logic in code."&lt;/p&gt;

&lt;h2&gt;
  
  
  The danger of the auto-complete loop
&lt;/h2&gt;

&lt;p&gt;Copilot and Cursor are incredible, but they create a dangerous feedback loop. You start a line, it suggests the next three, and you hit Tab. You do this for ten minutes, and suddenly you have a working function. &lt;/p&gt;

&lt;p&gt;Then you realize you don't actually know how it works. &lt;/p&gt;

&lt;p&gt;I found that my ability to debug dropped because I was no longer the primary author of my code. I was an editor. The problem is that editing is a lower-cognitive effort than writing, and it makes you lazy. &lt;/p&gt;

&lt;p&gt;To fight this, I started a rule: if the AI generates a block of code longer than five lines, I must be able to explain exactly what every line does before I commit it. If I can't, I ask the AI to explain that specific part, or I rewrite it manually.&lt;/p&gt;

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

&lt;p&gt;Stop using your prompt box as a search bar. Shift your workflow to this three step process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define the environment and constraints first (versions, existing utilities, architectural rules).&lt;/li&gt;
&lt;li&gt;Request a logical outline or pseudocode before asking for actual implementation.&lt;/li&gt;
&lt;li&gt;Review the logic, refine the steps, and only then generate the code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This reduces the amount of "hallucinated" boilerplate and ensures the code actually fits into your existing codebase without a total rewrite.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop Over-Engineering Your Indie Project</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sun, 26 Jul 2026 11:01:06 +0000</pubDate>
      <link>https://dev.to/ntty/stop-over-engineering-your-indie-project-1eim</link>
      <guid>https://dev.to/ntty/stop-over-engineering-your-indie-project-1eim</guid>
      <description>&lt;p&gt;I spent three weeks setting up a Kubernetes cluster, a CI/CD pipeline with automated canary deployments, and a strictly typed hexagonal architecture for a tool that had zero users. I told myself I was building for scale. In reality, I was procrastinating on the hard part: finding out if anyone actually wanted the product.&lt;/p&gt;

&lt;p&gt;When you work on a company project, over-engineering is often a safety net. You have a team to review your code and a company that pays for the infrastructure. When you are an indie developer, over-engineering is a trap. It feels like progress because you are writing code, but it is actually a form of resistance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scaling Myth
&lt;/h2&gt;

&lt;p&gt;Many of us suffer from the fear of the 'success disaster'. We imagine that the moment we launch, a million users will flood in and crash our single-instance Postgres database. Because of this, we spend days implementing Redis caching or microservices before we have a single signup.&lt;/p&gt;

&lt;p&gt;Here is the truth: crashing because you have too many users is a high quality problem. It is a problem you want to have. If you spend a month building a system that can handle 100k requests per second, but you only get 10 users, you have wasted 99 percent of your effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Minimal Viable Tech Stack
&lt;/h2&gt;

&lt;p&gt;To move fast, you need to reduce the number of decisions you make. Every new tool in your stack is another point of failure and another thing to maintain. &lt;/p&gt;

&lt;p&gt;For most indie projects, a boring stack is the best stack. Use a framework you know inside and out. If you know Rails, use Rails. If you know Laravel, use Laravel. If you prefer Next.js, stick with it. Do not use an indie project as a playground to learn a new language or a niche database unless the learning process is the primary goal of the project.&lt;/p&gt;

&lt;p&gt;Stick to these rules for your first version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a monolithic architecture. Splitting things into services too early adds network latency and deployment complexity.&lt;/li&gt;
&lt;li&gt;Use a relational database. Postgres can handle way more than you think. Do not add NoSQL just because it sounds modern.&lt;/li&gt;
&lt;li&gt;Avoid complex state management. Use simple props or basic contexts. You do not need a massive Redux store for a landing page and a CRUD dashboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Technical Debt is a Tool
&lt;/h2&gt;

&lt;p&gt;Developers are taught that technical debt is bad. In a corporate setting, that is mostly true. In an indie setting, technical debt is a strategic tool. &lt;/p&gt;

&lt;p&gt;Taking on debt means you are choosing to write a quick, suboptimal solution now so you can validate a feature faster. If the feature fails, you delete the code and the debt vanishes. If the feature succeeds, you now have the data and the motivation to refactor it properly.&lt;/p&gt;

&lt;p&gt;When I say 'quick solution', I do not mean broken code. I mean code that is easy to understand but not perfectly abstract. Avoid the temptation to create a generic 'BaseService' or a 'PluginSystem' for a feature that might only ever have one implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shipping Metric
&lt;/h2&gt;

&lt;p&gt;Your goal is not to write beautiful code. Your goal is to close the loop between an idea and user feedback. &lt;/p&gt;

&lt;p&gt;Every hour spent tweaking a CSS animation or optimizing a database query that takes 10ms instead of 50ms is an hour not spent talking to users. If the app works and the UI is clean, ship it. &lt;/p&gt;

&lt;p&gt;If you find yourself spending more than a day on a 'foundation' task that does not directly result in a user-facing feature, stop. Ask yourself: 'Will the app break if I do this the simple way?' If the answer is no, do it the simple way.&lt;/p&gt;

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

&lt;p&gt;Next time you feel the urge to add a new library or refactor a working module for 'better architecture', do this instead: write a list of the three most important features your users need. If your current work does not directly contribute to those three things, stop and move back to the feature list. Ship the 'ugly' version first. You can't optimize a product that nobody uses.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>devops</category>
      <category>startup</category>
    </item>
    <item>
      <title>Stop Over-Engineering Your Indie Project</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Sat, 25 Jul 2026 11:00:05 +0000</pubDate>
      <link>https://dev.to/ntty/stop-over-engineering-your-indie-project-27ca</link>
      <guid>https://dev.to/ntty/stop-over-engineering-your-indie-project-27ca</guid>
      <description>&lt;p&gt;I spent three weeks setting up a Kubernetes cluster and a complex CI/CD pipeline for a project that had 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 on an indie project, your biggest enemy is not technical debt. It is the lack of momentum. Every hour you spend configuring a fancy orchestration tool or debating between three different state management libraries is an hour you are not talking to users.&lt;/p&gt;

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

&lt;p&gt;Developers love to talk about scale. We worry about what happens when 100,000 people hit our API at the same second. But for 99 percent of indie projects, that is a high class problem that you will likely never have. &lt;/p&gt;

&lt;p&gt;If your app crashes because you hit 1,000 concurrent users, it means you have a successful product. At that point, you will have the data and the motivation to optimize. Scaling a product that nobody uses is a waste of time. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Boring Tech Stack Advantage
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes I made early on was using every single project as a learning playground for new frameworks. I would pick a brand new database or a beta language just because it was trending on Twitter. &lt;/p&gt;

&lt;p&gt;Then, when I hit a bug, I had to spend four hours reading outdated documentation or searching through a tiny community forum. &lt;/p&gt;

&lt;p&gt;Now, I follow the Boring Tech Rule. Use the tools you know best. If you have used Postgres for five years, use Postgres. If you are fast with plain CSS, do not spend two days fighting a new utility framework. The goal is to ship, not to update your resume. &lt;/p&gt;

&lt;h2&gt;
  
  
  MVP vs. MLP
&lt;/h2&gt;

&lt;p&gt;We always hear about the Minimum Viable Product (MVP). But I prefer the Minimum Lovable Product (MLP). &lt;/p&gt;

&lt;p&gt;An MVP is often just a skeleton that barely works. An MLP focuses on one core feature and makes it feel polished. Instead of building ten mediocre features, build one feature that feels great to use. &lt;/p&gt;

&lt;p&gt;For example, if you are building a note taking app, do not build folders, tags, sharing, and a calendar. Just make the text editor feel fast and the saving process invisible. That is what users actually care about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Actually Spend Your Effort
&lt;/h2&gt;

&lt;p&gt;If you are not spending time on infrastructure, where should you be focusing? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Error Logging: You cannot fix what you cannot see. Set up a simple error tracker. Knowing exactly where a user hit a 500 error is more valuable than a fancy deployment pipeline.&lt;/li&gt;
&lt;li&gt;User Onboarding: The first 30 seconds of your app are the most important. If a user has to read a manual to figure out how to start, they will leave.&lt;/li&gt;
&lt;li&gt;Simple Analytics: Use basic tools to see which pages are visited. You might find that the feature you spent a month on is the one nobody clicks.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Next time you feel the urge to refactor your entire backend or migrate to a new database for "better performance," ask yourself: "Will this change make a user's life better tomorrow?"&lt;/p&gt;

&lt;p&gt;If the answer is no, stop. Close that tab. Go back to your core feature and ship it. The most successful indie projects are not the ones with the cleanest code. They are the ones that solved a problem before the developer ran out of energy.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>softwareengineering</category>
      <category>startup</category>
    </item>
    <item>
      <title>Stop Writing Prompts, Start Building Agentic Workflows</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Fri, 24 Jul 2026 11:00:05 +0000</pubDate>
      <link>https://dev.to/ntty/stop-writing-prompts-start-building-agentic-workflows-3mcl</link>
      <guid>https://dev.to/ntty/stop-writing-prompts-start-building-agentic-workflows-3mcl</guid>
      <description>&lt;h2&gt;
  
  
  The Prompt Engineering Trap
&lt;/h2&gt;

&lt;p&gt;Most developers start their AI journey by trying to write the perfect prompt. You spend hours tweaking the wording, adding "you are an expert" and "think step by step", only to find that the LLM still hallucinates or misses a key requirement 20% of the time. &lt;/p&gt;

&lt;p&gt;This happens because you are treating the LLM as a magic box. You send one massive request and hope for a perfect response. In production, this is a fragile strategy. When the input grows or the model updates, your "perfect" prompt breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to Agentic Workflows
&lt;/h2&gt;

&lt;p&gt;Instead of one giant prompt, think in terms of an agentic workflow. An agentic approach is not about giving the AI a personality. It is about breaking a complex task into a series of small, verifiable steps where the AI can loop back and correct its own mistakes.&lt;/p&gt;

&lt;p&gt;Think of it as a state machine. Instead of:&lt;br&gt;
&lt;code&gt;Input&lt;/code&gt; -&amp;gt; &lt;code&gt;Giant Prompt&lt;/code&gt; -&amp;gt; &lt;code&gt;Final Output&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Try this:&lt;br&gt;
&lt;code&gt;Input&lt;/code&gt; -&amp;gt; &lt;code&gt;Plan Step&lt;/code&gt; -&amp;gt; &lt;code&gt;Execute Step&lt;/code&gt; -&amp;gt; &lt;code&gt;Review Step&lt;/code&gt; -&amp;gt; &lt;code&gt;Correct Step&lt;/code&gt; -&amp;gt; &lt;code&gt;Final Output&lt;/code&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  A Concrete Example: Content Generation
&lt;/h2&gt;

&lt;p&gt;If you are building a tool to generate technical documentation from code, a single prompt like "Write a guide for this repo" will produce generic fluff. &lt;/p&gt;

&lt;p&gt;Here is how to build an agentic pipeline for it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Analyst Agent&lt;/strong&gt;: This first step does not write content. It only lists the key functions, API endpoints, and dependencies. It outputs a structured JSON list of "facts".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Drafter Agent&lt;/strong&gt;: This step takes the JSON list and writes a rough draft. It is told to be verbose and ugly, focusing only on technical accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Critic Agent&lt;/strong&gt;: This is the most important part. This agent is given the original code and the draft. Its only job is to find contradictions. "The code says the timeout is 30s, but the draft says 60s."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Refiner Agent&lt;/strong&gt;: This agent takes the draft and the critic's notes to produce the final version.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By decoupling the "writing" from the "fact checking", you dramatically reduce hallucinations. You can also insert a human-in-the-loop check after the Analyst step to ensure the AI didn't miss a critical module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the Loop
&lt;/h2&gt;

&lt;p&gt;To make this work in code, you need to handle state. Do not just chain API calls. Use a framework or a simple database to track the state of the document. &lt;/p&gt;

&lt;p&gt;If the Critic Agent finds more than three errors, the workflow should automatically trigger a loop back to the Drafter. This is what makes it "agentic". The system is making a decision based on the quality of the output, rather than just following a linear script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling GEO and SEO in Agentic Flows
&lt;/h2&gt;

&lt;p&gt;If you are building for Generative Engine Optimization (GEO), the goal is to provide clear, cited, and authoritative data that AI models can easily parse. &lt;/p&gt;

&lt;p&gt;An agentic workflow helps here by allowing you to create a "Citation Agent". This agent's sole purpose is to ensure every claim in your content is mapped to a source URL or a piece of documentation. If a claim lacks a source, the agent flags it for deletion or research. This ensures your content is not just readable for humans, but authoritative for the LLMs that will eventually summarize it.&lt;/p&gt;

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

&lt;p&gt;Stop trying to find the "golden prompt". It does not exist. &lt;/p&gt;

&lt;p&gt;Instead, map out your process as a flowchart. Identify where the AI is likely to fail. Create a separate agent whose only job is to catch those specific failures. &lt;/p&gt;

&lt;p&gt;Build small, specialized loops. Verify the output of each step before passing it to the next. This is the only way to move from a "cool demo" to a production-ready system.&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 citations and source verification in my own content pipelines.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>Today we’re launching WaitSpin for macOS.</title>
      <dc:creator>Ntty</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:04:35 +0000</pubDate>
      <link>https://dev.to/ntty/today-were-launching-waitspin-for-macos-41hp</link>
      <guid>https://dev.to/ntty/today-were-launching-waitspin-for-macos-41hp</guid>
      <description>&lt;p&gt;WaitSpin is a native Mac companion for developers who want to &lt;strong&gt;explore&lt;/strong&gt; &lt;strong&gt;earning&lt;/strong&gt; through supported integrations in the tools (all from VS Code to Claude Code) they already use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal was simple:&lt;/strong&gt; make setup and management feel like part of the workflow, not another dashboard to babysit. -&amp;gt; &lt;a href="https://youtu.be/4lMejgox7BU" rel="noopener noreferrer"&gt;Watch Video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign in with email/OTP.&lt;/li&gt;
&lt;li&gt;Choose and explicitly approve integrations in supported developer tools.&lt;/li&gt;
&lt;li&gt;Manage integration status and targeted recovery actions from one native window.&lt;/li&gt;
&lt;li&gt;Keep an eye on wallet details from the menu bar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The app is built for Apple silicon on macOS 14+, delivered as a signed and notarized DMG, and supports automatic updates.&lt;/p&gt;

&lt;p&gt;Download WaitSpin for macOS:&lt;br&gt;
&lt;a href="https://waitspin.com/" rel="noopener noreferrer"&gt;https://waitspin.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d especially value feedback on the integration-management experience: what would make this genuinely useful in your daily development workflow?&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>ai</category>
      <category>buildinpublic</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
