<?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: Yarden Porat</title>
    <description>The latest articles on DEV Community by Yarden Porat (@yardenporat).</description>
    <link>https://dev.to/yardenporat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F902833%2F41a73da9-d91e-4ddf-8cca-961642bff318.jpeg</url>
      <title>DEV Community: Yarden Porat</title>
      <link>https://dev.to/yardenporat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yardenporat"/>
    <language>en</language>
    <item>
      <title>Stop Waiting: How to Batch-Generate AI Images with Nano Banana</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Fri, 28 Nov 2025 08:58:19 +0000</pubDate>
      <link>https://dev.to/yardenporat/stop-waiting-how-to-batch-generate-ai-images-with-nano-banana-1800</link>
      <guid>https://dev.to/yardenporat/stop-waiting-how-to-batch-generate-ai-images-with-nano-banana-1800</guid>
      <description>&lt;p&gt;Tired of waiting for the AI to finish one image before you can ask for the next?&lt;/p&gt;

&lt;p&gt;Use this prompt structure to force a "production loop." It tells the AI to generate a specific list sequentially without stopping or merging them.&lt;/p&gt;

&lt;p&gt;Copy and paste this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call the image generation function with the following frequency.
After each image generation, always check the number.
You may finish when the last number is matched. 
Here are the images you must create:
1. [prompt_1]
2. [prompt_2]
3. [prompt_3]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nanobanana</category>
      <category>genai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Figma to IDE MCP integration in 2 minutes</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Sat, 08 Nov 2025 07:02:48 +0000</pubDate>
      <link>https://dev.to/yardenporat/figma-to-ide-integration-in-2-minutes-533i</link>
      <guid>https://dev.to/yardenporat/figma-to-ide-integration-in-2-minutes-533i</guid>
      <description>&lt;h2&gt;
  
  
  Stop Pasting Screenshots: A Developer's Guide to Semantic Figma Integration
&lt;/h2&gt;

&lt;p&gt;As full-stack developers, we are constantly looking for ways to bridge the gap between design and implementation. Recently, AI has promised to close this gap, but the prevalent workflow—pasting screenshots into an LLM—is fundamentally flawed.&lt;/p&gt;

&lt;p&gt;When an AI looks at a screenshot, it is guessing. It sees pixels, not intent. It doesn't know your design tokens, it doesn't recognize your existing component library, and it often outputs hard-coded hex values instead of the semantic variables your team uses.&lt;/p&gt;

&lt;p&gt;There is a better way: The Model Context Protocol (MCP).&lt;/p&gt;

&lt;p&gt;By integrating the figma-developer-mcp server into your IDE, you can give your AI agent direct, secure access to the structured data behind your Figma designs. This allows for "one-shot" code generation that actually respects your codebase's architecture.&lt;/p&gt;

&lt;p&gt;Here is how to set it up in minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxigv99a4b8o6v66rwka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxigv99a4b8o6v66rwka.png" alt="illustration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You will need an IDE that supports MCP (like Cursor) and access to your Figma account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Generate a Figma API Token
&lt;/h3&gt;

&lt;p&gt;To allow your local environment to read Figma files securely, you need a personal access token.&lt;/p&gt;

&lt;p&gt;Open Figma and navigate to Settings &amp;gt; Account.&lt;/p&gt;

&lt;p&gt;Find the Personal Access Tokens section.&lt;/p&gt;

&lt;p&gt;Generate a new token. For security, ensure it only has Read-Only scopes.&lt;/p&gt;

&lt;p&gt;Important: Copy this token immediately and store it securely. You will not be able to see it again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkfzjr20l50wq5a220hv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkfzjr20l50wq5a220hv.png" alt="Generate Figma access token" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Your IDE
&lt;/h3&gt;

&lt;p&gt;Next, we need to register the Figma MCP server with your IDE. This is typically done via a standard mcp.json configuration file.&lt;/p&gt;

&lt;p&gt;In standard AI-native IDEs, you can usually find this by navigating to Settings &amp;gt; MCP Tools, which will open the configuration file.&lt;/p&gt;

&lt;p&gt;Add the following entry to your mcpServers object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "mcpServers": {
    "figma-developer-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "figma-developer-mcp",
        "--figma-api-key",
        "YOUR_TOKEN_HERE",
        "--stdio"
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace YOUR_TOKEN_HERE with the actual token you generated in Step 1.&lt;/p&gt;

&lt;p&gt;Once saved, completely restart your IDE to ensure the new server registry loads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: The New Workflow
&lt;/h3&gt;

&lt;p&gt;Once integrated, you no longer need to take screenshots.&lt;/p&gt;

&lt;p&gt;In Figma: Right-click the frame or component you want to implement and select Copy link to selection.&lt;/p&gt;

&lt;p&gt;In your IDE: Open your AI chat interface and paste the link directly.&lt;/p&gt;

&lt;p&gt;Prompt: Instruct the AI on how you want it implemented (e.g., "Implement this using our existing React UI components and CSS modules").&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0j8zylpg7vrswst0bf8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0j8zylpg7vrswst0bf8k.png" alt="copy link of selected frame" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;The difference between pixel-guessing and semantic understanding is significant for professional codebases:&lt;/p&gt;

&lt;p&gt;Design Tokens: The AI can read your Figma variables, meaning it will use --color-surface-primary instead of #FFFFFF.&lt;/p&gt;

&lt;p&gt;Component Recognition: It can identify that a design element is an instance of your standardized Button component, rather than re-inventing it with raw divs.&lt;/p&gt;

&lt;p&gt;Reduced Technical Debt: By generating code that aligns with your existing patterns from day one, you spend less time refactoring "AI slop."&lt;/p&gt;

&lt;p&gt;Integrating Figma via MCP transforms it from a visual reference into a queryable data source for your development environment.&lt;/p&gt;

</description>
      <category>figma</category>
      <category>mcp</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to Create a Custom LinkedIn Frame to Stand Out in 2025</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Sun, 03 Aug 2025 05:19:03 +0000</pubDate>
      <link>https://dev.to/yardenporat/how-to-create-a-custom-linkedin-frame-to-stand-out-in-2025-2l2m</link>
      <guid>https://dev.to/yardenporat/how-to-create-a-custom-linkedin-frame-to-stand-out-in-2025-2l2m</guid>
      <description>&lt;p&gt;Open your LinkedIn feed. You'll see a sea of professional headshots, all blending into a uniform blue and white landscape. But every so often, a profile picture catches your eye. It has a subtle ring of color, a word, or a simple design.&lt;/p&gt;

&lt;p&gt;That small detail is a LinkedIn Frame, and it’s one of the most underutilized tools for personal branding on the platform.&lt;/p&gt;

&lt;p&gt;While LinkedIn offers default frames like #OpenToWork or #Hiring, they are generic. Imagine, instead, a frame that uses your brand's colors, promotes your latest project, or announces your role as an event speaker.&lt;/p&gt;

&lt;p&gt;This is more than just decoration; it's a strategic way to communicate your value before anyone even clicks on your profile. This guide shows you why it matters and how you can create your own in less than a minute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1msjncrkb5qa9z3ldr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1msjncrkb5qa9z3ldr3.png" alt="video editor linkedin profile frame" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Strategic Advantage of a Custom LinkedIn Frame
&lt;/h2&gt;

&lt;p&gt;In the digital world, attention is currency. You have mere seconds to make an impression on a recruiter, a potential client, or a future collaborator. Your profile picture is your digital handshake, and a custom frame makes that handshake firmer.&lt;/p&gt;

&lt;p&gt;Here’s what a custom frame can do for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Instantly Grab Attention&lt;/strong&gt;: A pop of color or a clean design makes your profile stand out in crowded feeds, search results, and comment sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Communicate Your Purpose&lt;/strong&gt;: Instantly signal what you’re about. Are you "Speaking at #SaaStr," "Launching a Podcast," or "Open to Board Roles"? Your frame can say it all.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reinforce Your Brand Identity&lt;/strong&gt;: Using your brand colors creates a consistent and memorable visual identity across all your digital platforms.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A bland profile is a missed opportunity. A framed profile is a conversation starter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fk7lwur6lia5ymoh2l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fk7lwur6lia5ymoh2l3.png" alt="ai linkedin custom profile frame" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Create Your Custom LinkedIn Frame in Under 60 Seconds
&lt;/h2&gt;

&lt;p&gt;You don't need design skills or expensive software. The LinkedIn Frame Generator is a free, simple tool designed to do one thing perfectly.&lt;/p&gt;

&lt;p&gt;There are no accounts to create, no watermarks, and no freemium tricks. It's built for speed and privacy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Visit Frame-Generator.com&lt;br&gt;
The tool works directly in your browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Upload Your Profile Picture&lt;br&gt;
For the best results, use the high-resolution photo you already have on LinkedIn.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssa1ukaxs5g3ntbpi1vf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssa1ukaxs5g3ntbpi1vf.png" alt="linkedin profile frame upload button" width="512" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Customize Your Frame&lt;/p&gt;

&lt;p&gt;Add Text: Write a short, impactful message (e.g., your tagline or status).&lt;/p&gt;

&lt;p&gt;Choose Your Color: Use a hex code to match your brand colors perfectly, or pick one you like.&lt;/p&gt;

&lt;p&gt;Adjust and Position: Use the image offset controls to ensure your face remains perfectly centered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Download and Upload to LinkedIn&lt;br&gt;
Download your new, framed photo and upload it directly to your LinkedIn profile. The entire process takes less than a minute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk7s7jqil0xugurkoooe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk7s7jqil0xugurkoooe.png" alt=" " width="800" height="1362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for a Professional Look
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Less is More&lt;/strong&gt;: A simple, clean ring of color is often more professional and impactful than a frame overloaded with text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stay On-Brand&lt;/strong&gt;: Consistency is key. Use your established brand colors to build recognition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep it Fresh&lt;/strong&gt;: Update your frame for special campaigns, events, or job-seeking cycles. A dynamic profile signals that you are active and engaged.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4ygah37nm39fpb83efp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4ygah37nm39fpb83efp.png" alt="digital custom linkedin profile frame" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;Q: Is the LinkedIn Frame Generator free to use?&lt;br&gt;
A: Yes, it is 100% free. There are no hidden costs, subscriptions, or watermarks.&lt;/p&gt;

&lt;p&gt;Q: Are my images stored on your server?&lt;br&gt;
A: No. Your privacy is paramount. All image processing happens in your browser. Your pictures are never uploaded to or stored on our servers.&lt;/p&gt;

&lt;p&gt;Q: Can I use this for other social media platforms?&lt;br&gt;
A: Yes! While it's optimized for LinkedIn's circular format, the downloaded image works perfectly for other platforms like X (Twitter), Instagram, or as a Discord avatar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41imx9pgwwjky31mykyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41imx9pgwwjky31mykyc.png" alt="recruiter linkedin custom profile frame" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Upgrade Your Digital First Impression?
&lt;/h2&gt;

&lt;p&gt;Your LinkedIn profile is your most important digital career asset. Don't let it blend in.&lt;/p&gt;

&lt;p&gt;A custom frame is a powerful signal. It shows you are intentional, brand-savvy, and care about how you present yourself professionally. It’s a simple change that makes a significant impact.&lt;/p&gt;

&lt;p&gt;Take 60 seconds and create your free frame now: Visit Frame-Generator.com&lt;/p&gt;

&lt;p&gt;We’ve been featured on &lt;a href="https://geekytools.com/article/linkedin-profile-frame-generator-transform-your-first-impression" rel="noopener noreferrer"&gt;GeekyTools.com&lt;/a&gt;, a platform for digital tools that enhance productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ms7v59nzhxw8oz9lsbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ms7v59nzhxw8oz9lsbp.png" alt="tech custom profile frame for linkedin" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;My name is Yarden Porat. By day, I’m a Senior Software Engineer at Vimeo, and I'm the creator of the LinkedIn Frame Generator.&lt;/p&gt;

&lt;p&gt;I built this tool with a simple mission: to make powerful, professional branding accessible to everyone. I believe you shouldn't need complex software to make your profile stand out. I'm thrilled the tool has been recognized for its simplicity and effectiveness. &lt;br&gt;
I hope it helps you make your best first impression.&lt;/p&gt;

</description>
      <category>linkedin</category>
      <category>profileframe</category>
      <category>linkedintips</category>
      <category>linkedinframe</category>
    </item>
    <item>
      <title>Arguing with LLMs</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Mon, 14 Jul 2025 06:59:27 +0000</pubDate>
      <link>https://dev.to/yardenporat/arguing-with-llms-gh4</link>
      <guid>https://dev.to/yardenporat/arguing-with-llms-gh4</guid>
      <description>&lt;p&gt;Ever been in a debate with a colleague from a different role, and suddenly they drop a ChatGPT response on you to counter your point? 🤨&lt;/p&gt;

&lt;p&gt;If so, you're not alone. It seems there's a new weapon in the arsenal of technical arguments.&lt;/p&gt;

&lt;p&gt;We all love AI tools. They're amazing and help us with a variety of daily tasks with an efficiency that sometimes feels like magic.&lt;/p&gt;

&lt;p&gt;But turning them into the ultimate authority in a professional argument? That’s where I think we’re missing the point.&lt;/p&gt;

&lt;p&gt;Why do I find this so problematic?&lt;/p&gt;

&lt;p&gt;An LLM is not documentation 📚&lt;br&gt;
It hasn't read your internal design docs, it doesn't understand the project's constraints, and it can invent an entire API that doesn't exist.&lt;/p&gt;

&lt;p&gt;An LLM is a confirmation bias machine 🧠&lt;br&gt;
With the right prompt, you can make it say anything. "Write five arguments why X is better than Y" – and it will. That doesn't make it right or smart. Basically, it just wants to please you.&lt;/p&gt;

&lt;p&gt;An LLM is no substitute for a real discussion 🎯&lt;br&gt;
The whole point of a professional discussion is to weigh the pros and cons, to understand the trade-offs. When you pull out a generic bot answer, you're essentially saying: "I can't be bothered to think, let's just take the first answer from Google on steroids." You're just shooting yourself in the foot and missing an opportunity to learn.&lt;/p&gt;

&lt;p&gt;I'm not against these tools, quite the opposite. But there's a huge difference between 'fake it till you make it' and 'let the AI fake it for me.' Using them to "win" an argument, without scrutiny and real references, is an abuse of the tool and cheapens the professional discourse.&lt;/p&gt;

&lt;p&gt;So, have you encountered this phenomenon?&lt;br&gt;
How do you think we should handle an argument that's based on a generic AI response?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahcvfbrhsizx701wonco.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahcvfbrhsizx701wonco.jpeg" alt="ai puppeteer" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Codeium Windsurf IDE rules file</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Thu, 03 Apr 2025 05:45:26 +0000</pubDate>
      <link>https://dev.to/yardenporat/codium-windsurf-ide-rules-file-1hn9</link>
      <guid>https://dev.to/yardenporat/codium-windsurf-ide-rules-file-1hn9</guid>
      <description>&lt;p&gt;Due to lacking documentation:&lt;/p&gt;

&lt;h1&gt;
  
  
  Wave 8 and beyond
&lt;/h1&gt;

&lt;p&gt;Now, Rules are defined in markdown (.md) files within the repository’s root folder of .windsurf/rules. After creating a Rules file with a descriptive name (just like with Workflows), the user will be greeted with a GUI wrapper around the Markdown file.&lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;p&gt;for more information &lt;a href="https://windsurf.com/blog/windsurf-wave-8-cascade-customization-features?_sc=ODEwMDk4MiM5OTQ1MTQ%3D&amp;amp;utm_campaign=wave-8&amp;amp;utm_source=email#:~:text=with%20Custom%20Workflows!-,File%2DBased%20Rules,-Ok%2C%20now%20raise" rel="noopener noreferrer"&gt;check the official blog post&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Before Wave 8
&lt;/h1&gt;

&lt;p&gt;At the root of your project, create a file &lt;code&gt;.windsurfrules&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Add appropriate rules for you project in the following format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. My build system is Bazel
2. My testing framework is pytest
3. Don't modify any files in ...
4. Don't use these APIs ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more rule files examples, check out the official docs: &lt;a href="https://codeium.com/windsurf/directory" rel="noopener noreferrer"&gt;https://codeium.com/windsurf/directory&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>testing</category>
      <category>development</category>
    </item>
    <item>
      <title>How to hide Next.js 14 server logs</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Thu, 20 Feb 2025 09:31:26 +0000</pubDate>
      <link>https://dev.to/yardenporat/how-to-hide-nextjs-14-server-logs-38e9</link>
      <guid>https://dev.to/yardenporat/how-to-hide-nextjs-14-server-logs-38e9</guid>
      <description>&lt;p&gt;Example for hiding logs such as:&lt;br&gt;
&lt;code&gt;GET /_next/static/chunks/app/route/react-toastify.esm.mjs.map 404 in 1623ms&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ./src/utils/customLogger.mjs

if (process.env.NODE_ENV === "development") {
  // Omit NextJS writing it's log https://github.com/vercel/next.js/discussions/65992
  const __write = process.stdout.write;
  process.stdout.write = (...args) =&amp;gt; {
    if (typeof args[0] === "string" &amp;amp;&amp;amp; args[0].startsWith(" GET /")) {
      if (args[0].includes("react-toastify.esm.mjs.map")) {
        return;
      }
    }
    __write.apply(process.stdout, args);
  };
}

export {};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// next.config.mjs
import "./src/utils/customLogger.mjs";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>How to Disable Removal of Formatting When Pasting Text in Microsoft Word for Mac</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Sun, 15 Sep 2024 06:09:44 +0000</pubDate>
      <link>https://dev.to/yardenporat/how-to-disable-removal-of-formatting-when-pasting-text-in-microsoft-word-for-mac-3k32</link>
      <guid>https://dev.to/yardenporat/how-to-disable-removal-of-formatting-when-pasting-text-in-microsoft-word-for-mac-3k32</guid>
      <description>&lt;p&gt;Recently, Microsoft Word for Mac has started stripping away formatting when you paste text using &lt;strong&gt;Command (⌘) + V&lt;/strong&gt;, leaving you with plain text. To restore the original formatting, follow these simple steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Microsoft Word&lt;/strong&gt; on your Mac.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Preferences&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;Click on Word in the top menu bar next to the Apple logo.&lt;/li&gt;
&lt;li&gt;Select Preferences from the drop-down menu.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modify Edit Settings&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;In the Word Preferences window, click on Edit.&lt;/li&gt;
&lt;li&gt;If you don't see an Edit option, choose Advanced instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust Cut and Paste Options&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Find the section labeled "&lt;strong&gt;Cut and paste options&lt;/strong&gt;" or "&lt;strong&gt;Cut, copy, and paste&lt;/strong&gt;".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uncheck&lt;/strong&gt; the box next to "&lt;strong&gt;Show Paste Options button when content is pasted&lt;/strong&gt;".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Close the Preferences Window&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Your changes will be saved automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After completing these steps, pasting text with &lt;strong&gt;Command + V&lt;/strong&gt; will retain the original formatting.&lt;/p&gt;

</description>
      <category>word</category>
      <category>microsoftword</category>
      <category>vscode</category>
      <category>msword</category>
    </item>
    <item>
      <title>Chrome extension that allows font-weight control</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Sun, 04 Aug 2024 05:55:57 +0000</pubDate>
      <link>https://dev.to/yardenporat/chrome-extension-that-allows-font-weight-control-1gic</link>
      <guid>https://dev.to/yardenporat/chrome-extension-that-allows-font-weight-control-1gic</guid>
      <description>&lt;p&gt;Recently, I assisted a relative in setting up a new computer. This relative has vision problems that make it difficult to read fine text with low contrast. While I knew that browsers allow you to control the base font size, I was searching for a way to control the font weight (font-weight) and couldn't find an easy solution. Even the Chrome Web Store didn’t have an extension that fit the bill.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PkWMMiUn29A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;After some research and development, I created a Chrome extension called Bold it that allows users to control the font weight on any website. This extension can help not only my family member but also others who struggle with reading online due to vision issues.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{% embed https://youtu.be/PkWMMiUn29A %}&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Extension Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description:
&lt;/h3&gt;

&lt;p&gt;Easily adjust font-weight on any webpage.&lt;br&gt;
User-friendly interface with simple controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Real-time font-weight adjustment.&lt;/li&gt;
&lt;li&gt;Save preferred settings.&lt;/li&gt;
&lt;li&gt;Enhance readability.&lt;/li&gt;
&lt;li&gt;Compatible with all websites.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to Use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install from the &lt;a href="https://chromewebstore.google.com/detail/bold-it/dccjfkknapjcbjalaknijpoocjilpjfa" rel="noopener noreferrer"&gt;Chrome Web Store&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click the extension icon.&lt;/li&gt;
&lt;li&gt;Adjust the font-weight slider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I invite you to try the extension and share it with anyone who might benefit from it.&lt;/p&gt;

&lt;p&gt;Bold it: &lt;a href="https://chromewebstore.google.com/detail/bold-it/dccjfkknapjcbjalaknijpoocjilpjfa" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/bold-it/dccjfkknapjcbjalaknijpoocjilpjfa&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fontweight</category>
      <category>chromeextension</category>
    </item>
    <item>
      <title>Why Do I Love Code Formatters?</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Tue, 11 Jun 2024 05:39:21 +0000</pubDate>
      <link>https://dev.to/yardenporat/why-do-i-love-code-formatters-a87</link>
      <guid>https://dev.to/yardenporat/why-do-i-love-code-formatters-a87</guid>
      <description>&lt;p&gt;Is it because standardizing the code makes it more readable? Also, but no.&lt;br&gt;
Is it because it saves unnecessary discussions about style in reviews? Also, but no.&lt;br&gt;
Is it because it saves us the need to think about formatting at all? Also, but no.&lt;br&gt;
I love Code Formatters because they provide instant validation—immediate feedback on whether the syntax is correct. In large projects, nothing gives you validation on the code in the file you are editing as quickly. Linting can take a few seconds. Unit tests running with watch take more time. A development server with HMR is usually slower.&lt;/p&gt;

&lt;p&gt;Even if you are an expert in a certain domain, one day you might find yourself in a codebase you're unfamiliar with, in a language that isn't your forte, and you'll be grateful that a formatter was enforced in the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F568o2uhex6a3vbt0edfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F568o2uhex6a3vbt0edfn.png" alt="code formatters" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>prettier</category>
      <category>codeformatters</category>
      <category>formatting</category>
      <category>codestyle</category>
    </item>
    <item>
      <title>TypeScript's noUncheckedIndexedAccess</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Sat, 17 Feb 2024 18:27:45 +0000</pubDate>
      <link>https://dev.to/yardenporat/typescripts-nouncheckedindexedaccess-strictnullchecks-4l1j</link>
      <guid>https://dev.to/yardenporat/typescripts-nouncheckedindexedaccess-strictnullchecks-4l1j</guid>
      <description>&lt;p&gt;Recently, a friend shared a TypeScript project with me, and as I delved into it, I noticed something crucial missing: the basic configuration of noUncheckedIndexedAccess&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ Why is this configurations important?
&lt;/h2&gt;

&lt;p&gt;noUncheckedIndexedAccess feature ensures that accessing elements in arrays or objects doesn't result in undefined or null, reducing runtime errors. Without it, developers might overlook potential null or undefined values, leading to unexpected crashes or behaviors.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 Examples Speak Louder Than Words:
&lt;/h2&gt;

&lt;p&gt;Consider this snippet without noUncheckedIndexedAccess:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Potential runtime error if arr[4] is undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Conclusion:
&lt;/h2&gt;

&lt;p&gt;Integrating noUncheckedIndexedAccess into your TypeScript projects might seem like a minor tweak, but it can prevent major headaches down the line. By catching potential issues early and enforcing stricter typing, these features contribute to more robust and reliable codebases.&lt;/p&gt;

&lt;p&gt;Let's prioritize these configurations in our TypeScript projects to ensure smoother development experiences and fewer surprises in production. Keep coding confidently! 💻✨&lt;/p&gt;

</description>
      <category>typesafety</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>tsconfig</category>
    </item>
    <item>
      <title>Introducing `useThrottledCallback`: Enhance Performance with Throttled Callbacks in React</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Fri, 25 Aug 2023 10:39:42 +0000</pubDate>
      <link>https://dev.to/yardenporat/introducing-usethrottledcallback-enhance-performance-with-throttled-callbacks-in-react-l1c</link>
      <guid>https://dev.to/yardenporat/introducing-usethrottledcallback-enhance-performance-with-throttled-callbacks-in-react-l1c</guid>
      <description>&lt;p&gt;In the world of web development, creating smooth and performant user experiences is paramount.&lt;/p&gt;

&lt;p&gt;One common challenge developers face is dealing with event handlers that can fire rapidly, potentially causing unnecessary re-renders and performance bottlenecks.&lt;/p&gt;

&lt;p&gt;This is where throttling comes into play. &lt;strong&gt;Throttling limits the rate at which a function is executed, ensuring that it's called at a controlled pace, thus optimizing performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is why I created a new React hook that simplifies the implementation of throttled callbacks - &lt;code&gt;useThrottledCallback&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This hook streamlines the process of creating throttled callbacks and also aligns perfectly with best practices in React development, including seamless integration with React linting tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;useThrottledCallback&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let's take a closer look at how the &lt;code&gt;useThrottledCallback&lt;/code&gt; hook works:&lt;/p&gt;

&lt;h4&gt;
  
  
  TypeScript
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DependencyList&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;throttle&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash.throttle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useThrottledCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TCallback&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;(
    fn: TCallback,
    dependencies?: DependencyList,
    wait: number = 250
) =&amp;gt; &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// eslint-disable-next-line react-hooks/exhaustive-deps&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])]);&lt;/span&gt;
&lt;span class="si"&gt;}&lt;/span&gt;;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  JavaScript
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;throttle&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash.throttle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useThrottledCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// eslint-disable-next-line react-hooks/exhaustive-deps&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hook accepts three parameters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;fn&lt;/code&gt;: The callback function you want to throttle.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dependencies&lt;/code&gt; (optional): An array of dependencies that, when changed, trigger the creation of a new throttled callback. This aligns with React's dependency tracking system.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wait&lt;/code&gt;: The time interval in milliseconds that specifies how often the throttled function can be executed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Enhancing Code Quality with Linting
&lt;/h3&gt;

&lt;p&gt;Linting helps Maintaining clean and organized code is essential for collaboration and long-term project health. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;useThrottledCallback&lt;/code&gt; dependency array can be validated by linting, specifically the by popular &lt;code&gt;react-hooks/exhaustive-deps&lt;/code&gt; rule.&lt;/p&gt;

&lt;p&gt;In your linting configuration file (usually &lt;code&gt;.eslintrc&lt;/code&gt;), add the following configuration to the rules section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"react-hooks/exhaustive-deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="s2"&gt;"warn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"additionalHooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(useThrottledCallback)"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rules&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, linting tools will recognize your usage of the &lt;code&gt;useThrottledCallback&lt;/code&gt; hook and ensure that you provide appropriate dependencies to the hook to avoid unnecessary re-renders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useThrottledCallback&lt;/code&gt; hook brings simplicity and performance optimization to your React applications. By incorporating throttled callbacks, you can effortlessly manage event handlers that could otherwise cause performance hiccups. With linting integration, maintaining code quality becomes a breeze, ensuring your projects stay organized and efficient.&lt;/p&gt;

&lt;p&gt;Give the &lt;code&gt;useThrottledCallback&lt;/code&gt; hook a try in your next React project, and experience the benefits of smooth user interactions and enhanced code maintainability. Happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Flaky Tests, and How to Deal with Them</title>
      <dc:creator>Yarden Porat</dc:creator>
      <pubDate>Thu, 26 Jan 2023 15:45:35 +0000</pubDate>
      <link>https://dev.to/codux/flaky-tests-and-how-to-deal-with-them-2id2</link>
      <guid>https://dev.to/codux/flaky-tests-and-how-to-deal-with-them-2id2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf69kaxw58c98p40udb1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf69kaxw58c98p40udb1.jpg" alt="Battling Flakiness" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Hey! My name is Yarden Porat, and in this article, I will explain what flaky tests are, their costs, their causes, and how they harm your work and organization. Once we have that figured out, I will share our strategy and tools we have developed in-house for dealing with test flakiness at Wix and how we avoid their costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a flaky test?
&lt;/h2&gt;

&lt;p&gt;A flaky test is an automated test with a non-deterministic result. This is a way of saying that a test sometimes passes and sometimes doesn’t, inconsistently, without any code changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famfvyjc1e5qrqzxa9yxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famfvyjc1e5qrqzxa9yxi.png" alt="failing test" width="479" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How often does it fail?
&lt;/h2&gt;

&lt;p&gt;Beautifully depicted in this &lt;a href="https://shopify.engineering/unreasonable-effectiveness-test-retries-android-monorepo-case-study" rel="noopener noreferrer"&gt;article&lt;/a&gt;, if a single test has a failure rate of 0.05% (0.0005), and you have 100 of these tests in your test suite, it would have a success rate of 95.12%= 0.9995&lt;sup&gt;100&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;But what happens when you have thousands of these tests?  A 60.64% success rate (0.9995&lt;sup&gt;1,000&lt;/sup&gt;). It’s easy to calculate the significant impact of even a low failure rate on large scale tested applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But… What’s the problem? Just rerun the tests!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are some really bad implications of ignoring flaky tests. Let's go over some of the most common ones, from least important to most.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Wasted CI minutes (Hours? Days? Weeks?)
&lt;/h3&gt;

&lt;p&gt;Consider the following scenario: &lt;/p&gt;

&lt;p&gt;You are a developer working in a team. There’s a new feature you’ve been developing for several days, and you opened a pull request wanting to merge it into the project. &lt;/p&gt;

&lt;p&gt;Now, your company works in a modern development workflow and runs automated tests on your code changes using your CI system. All of the product’s tests ran and failed on a test &lt;strong&gt;entirely unrelated&lt;/strong&gt; to the changes you introduced. &lt;/p&gt;

&lt;p&gt;Since you are &lt;strong&gt;aware&lt;/strong&gt; of the code changes you have made, and you &lt;strong&gt;know&lt;/strong&gt; that this project has issues with non-deterministic tests, you therefore &lt;strong&gt;know&lt;/strong&gt; the failing test is not your fault.&lt;/p&gt;

&lt;p&gt;So, you rerun the test, and it passes.&lt;/p&gt;

&lt;p&gt;If you don’t know your project has an issue with non-deterministic tests, you’ll probably waste even more time investigating.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom320bhbwcin7zkwnsa8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom320bhbwcin7zkwnsa8.png" alt="rerun failed jobs" width="185" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is that this time accumulates. The longer the test workflows take, the more time is wasted—but how much time? This can be measured, assuming you track your CI test results. &lt;/p&gt;

&lt;p&gt;You can easily calculate the CI time wasted due to flakiness by summing up the CI time of a workflow run that had a non-deterministic result. For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;commit&lt;/th&gt;
&lt;th&gt;workflow_name&lt;/th&gt;
&lt;th&gt;os&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;th&gt;duration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;9f3e679&lt;/td&gt;
&lt;td&gt;test-part-1&lt;/td&gt;
&lt;td&gt;linux&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;9f3e679&lt;/td&gt;
&lt;td&gt;test-part-1&lt;/td&gt;
&lt;td&gt;linux&lt;/td&gt;
&lt;td&gt;fail&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Run identifier: commit + workflow_name + os&lt;/p&gt;

&lt;p&gt;That’s 7 minutes of CI time wasted!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Wasted development time
&lt;/h3&gt;

&lt;p&gt;When a developer reruns a test, they are forced to wait (again) for the build and test time. Precious developer time is being lost.&lt;/p&gt;

&lt;p&gt;Even if we assume that a developer utilizes this wait time for other tasks, we still have 2 major drawbacks:&lt;br&gt;
Loss of immediate feedback (long feedback loop).&lt;br&gt;
Context switching—which eats away at focus and productivity.&lt;/p&gt;

&lt;p&gt;Unfortunately, this wasted time is much harder to measure.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Flaky product behavior (or flaky implementation)
&lt;/h3&gt;

&lt;p&gt;Sometimes a flaky test is only a symptom of a non-deterministic implementation.  &lt;/p&gt;

&lt;p&gt;The same race condition that can cause test flakiness can do the same in a feature’s implementation, thus causing flaky product behavior in production. &lt;/p&gt;
&lt;h3&gt;
  
  
  4. Alert fatigue
&lt;/h3&gt;

&lt;p&gt;A common phenomenon in flaky test workflow is the loss of trust in the feedback you are getting. Consider this scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You push your new code&lt;/li&gt;
&lt;li&gt;Workflow tests run and fail&lt;/li&gt;
&lt;li&gt;“Oh it's that annoying flakiness again; we should fix it sometime”&lt;/li&gt;
&lt;li&gt;Rerun workflow, tests run and fail&lt;/li&gt;
&lt;li&gt;“D*%N FLAKINESS”&lt;/li&gt;
&lt;li&gt;Rerun workflow, tests run and fail&lt;/li&gt;
&lt;li&gt;Realizing that it was actually my code changes that had failed the tests&lt;/li&gt;
&lt;li&gt;Go back to step 1&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwfjgm4bcfdk9k5ovy2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwfjgm4bcfdk9k5ovy2j.png" alt="multiple reruns" width="381" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This harms development velocity and the developer’s experience. In an environment where it's not mandatory for tests to pass to merge a pull request, it is not uncommon for changes to merge even though they are breaking some product and tested behavior.&lt;/p&gt;
&lt;h3&gt;
  
  
  What's lost?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Money (Developer time, CI time)&lt;/li&gt;
&lt;li&gt;Development velocity&lt;/li&gt;
&lt;li&gt;Confidence in tests (regressing to manual testing)&lt;/li&gt;
&lt;li&gt;Product quality&lt;/li&gt;
&lt;li&gt;Developer experience&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Causes of test flakiness
&lt;/h2&gt;

&lt;p&gt;So now that we know the price and the pain, here are some of the causes of test flakiness.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Poorly written test code
&lt;/h3&gt;

&lt;p&gt;For example, interacting with DOM elements that are not yet ready, or improper use of &lt;code&gt;waitFor&lt;/code&gt; functions. This is the most common case where testing is done incorrectly. Sometimes, powerful development machines (a.k.a, your local computer) hide race conditions in a test, which ends up failing on CI machines.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Poorly written application code
&lt;/h3&gt;

&lt;p&gt;As mentioned above, sometimes the application code itself introduces a flaky behavior. These cases are much harder to detect and debug. It could be related to communications, asynchronous code, or many other alternatives.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Infrastructural causes
&lt;/h3&gt;

&lt;p&gt;There are various environmental causes to blame, and they are the immediate culprit for those who write flaky tests. Such causes may be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network issues: loss of connectivity, slow connection, etc.&lt;/li&gt;
&lt;li&gt;Hardware issues: low-performance shared virtual machines, which stress existing race conditions&lt;/li&gt;
&lt;li&gt;External dependencies: package manager (npm\yarn), runtime setup (i.e. Node, and other dependencies, which also suffer from some level of flakiness&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. Test tools that are prone to flakiness
&lt;/h3&gt;

&lt;p&gt;In our experience tests which use a browser are more prone to flakiness. One reason is that the browser itself is a complex piece of software with many dependencies, and it can be affected by a variety of factors - its version, operating system, and other specific configurations of the machine it is running on.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Key takeaways up to this point
&lt;/h2&gt;

&lt;p&gt;Here are some points I think you should keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flaky tests could occur due to many reasons and various causes. Some are test related, some production-code related, others from the infrastructure and development environment.&lt;/li&gt;
&lt;li&gt;They have direct and indirect implications on the development process—both technical and psychological.&lt;/li&gt;
&lt;li&gt;Flaky tests reduce development speed and quality if left untreated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to deal with flaky tests?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Collect data
&lt;/h3&gt;

&lt;p&gt;It is much easier to communicate the costs of flakiness to your team or organization if you have data to back you up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffihwlb63xp7nvhhz59s3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffihwlb63xp7nvhhz59s3.png" alt="Upload test results" width="468" height="192"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Analyze it
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Workflow reruns per day bar graph
&lt;/h3&gt;

&lt;p&gt;A bar graph that represents the overall flakiness and displays the total number of times a workflow has been restarted.&lt;br&gt;
It helps us understand the scale of the flakiness problem and the lack of developer trust in the tests/CI.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.codux.com/" rel="noopener noreferrer"&gt;Codux&lt;/a&gt; we chose to count any case of workflow rerun, but you can also create a subset of this graph that shows reruns that &lt;strong&gt;never succeeded&lt;/strong&gt;, which could better depict the lack of trust in your tests/CI.&lt;/p&gt;

&lt;p&gt;This is a general index that tells if your data correlates with your &lt;strong&gt;general feel&lt;/strong&gt; of flakiness. We don’t derive tasks from it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthmtj66xghc1074nxpw9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthmtj66xghc1074nxpw9.png" alt="Reruns per day bay graph" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We count rerun by identifying the commit, branch, OS, and workflow name. We call it an “entity” and count its total occurrences minus one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Fail rate table
&lt;/h3&gt;

&lt;p&gt;This is a table that calculates a test’s fail rate out of its total runs. We collect data from all branches, including development branches, and present only tests that have failed on 3 branches or more, with a minimum number of total runs.&lt;/p&gt;

&lt;p&gt;This table helps us find the current culprits tests. A Flaky test that fails over an arbitrary percentage of your choice (we chose 5%), is skipped, documented, and assigned to the relevant developer. This process occurs 1-2 times a week.&lt;/p&gt;

&lt;p&gt;This process requires reasoning and shouldn’t, in our opinion, be done automatically — for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some features have a low number of tests, so you probably wouldn’t want to lose coverage, and you might prefer, or should, add a retry on those tests.&lt;/li&gt;
&lt;li&gt;Some tests are more prone to failure (during development), such as end-to-end tests, so it might indicate they have a higher fail rate than they actually do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs27grryy46r8nxl57bj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs27grryy46r8nxl57bj5.png" alt="Fail rate table" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Fail by test scatter plot (Environmental factors)
&lt;/h3&gt;

&lt;p&gt;We’ve created a plot similar to &lt;a href="https://engineering.atspotify.com/2019/11/test-flakiness-methods-for-identifying-and-dealing-with-flaky-tests/#:~:text=I%20discussed%20below%3A-,Odeneye,-Odeneye%20is%20a" rel="noopener noreferrer"&gt;Spotify’s Odeneye&lt;/a&gt;. This plot helps us realize if there are some environmental or infrastructural problems. If you suspect your infrastructure is causing flakiness, try creating this dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkvptyayokx6hi43y7xu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkvptyayokx6hi43y7xu.png" alt="Fail by test scatter plot" width="800" height="299"&gt;&lt;/a&gt;&lt;br&gt;
_&lt;br&gt;
Horizontal lines indicate that a test is flaky. Vertical lines indicate an issue external to the test because it shows multiple test failures in the same timeframe. _&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Run new tests multiple times
&lt;/h3&gt;

&lt;p&gt;After noticing that newly created tests are flaky and require adjustments, we have decided to raise the bar for newly created tests and created “&lt;strong&gt;check-new-flaky&lt;/strong&gt;” — a CLI tool that detects new tests and runs them multiple times.&lt;/p&gt;

&lt;p&gt;It detects new tests by running our test runner (mocha) programmatically, recursively extracting test names on the branch, and comparing them to master.&lt;/p&gt;

&lt;p&gt;Checking newly created tests reduced the new flaky tests added to the application and the need to refactor them significantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tid52e9w23tajv09s2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tid52e9w23tajv09s2e.png" alt="Run new tests multiple times" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Some more benefits that we got:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster feedback loop&lt;/strong&gt;: This test workflow runs your new tests immediately, thus letting you know if it passes without waiting for their turn within the entire test suite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Another OS is running your test&lt;/strong&gt;: All our tests are running on Linux, while tests/features which are considered to be operating system sensitive, also run on Windows. Using the check-new-flaky CLI, we sometimes get an indication that a test we thought wasn’t OS sensitive is actually sensitive or broken for the other operating system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fym92rmitg4yz8vqzn7t1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fym92rmitg4yz8vqzn7t1.jpeg" alt="New flaky test shall not pass" width="770" height="324"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Set a bar for when a test isn’t flaky
&lt;/h3&gt;

&lt;p&gt;At first, it wasn't really clear to a developer when he fixed a flaky test. Developers would usually run a test 2-10 times before it would be labeled as not flaky and get merged to master.&lt;/p&gt;

&lt;p&gt;Once we declared war on test flakiness, the bar would be set to 100 consecutive runs.&lt;/p&gt;

&lt;p&gt;There are many ways to run a test multiple times — we used parts from the above CLI (check-new-flaky) and made it accessible via our GitHub bot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2c308lm427dqanwswma6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2c308lm427dqanwswma6.png" alt="Benchmarking a test" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Does your test only fail when running on CI?
&lt;/h2&gt;

&lt;p&gt;CI machines usually have reduced performance compared to your local development machine, thus most race conditions only show once tests are running on the CI.&lt;/p&gt;
&lt;h3&gt;
  
  
  Helping tests fail on your local machine
&lt;/h3&gt;

&lt;p&gt;One tool that we have found to be helpful is CPU throttling emulation. &lt;br&gt;
We use &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt; for integration and end-to-end browser tests. It emulates slow CPUs using the &lt;a href="https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setCPUThrottlingRate" rel="noopener noreferrer"&gt;Chrome Devtools Protocol&lt;/a&gt; (experimental feature).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChromiumBrowserContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright-core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;...&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ChromiumBrowserContext&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;newCDPSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Emulation.setCPUThrottlingRate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Rate is the slowdown factor (1 is no throttle, 2 is 2x slowdown)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Find out what’s going on with a test on the CI
&lt;/h3&gt;

&lt;p&gt;Many testing tools today allow you to take some recordings of your tests. &lt;br&gt;
Playwright released a &lt;a href="https://playwright.dev/docs/trace-viewer/" rel="noopener noreferrer"&gt;tracing feature&lt;/a&gt; on version 1.12, which records the test flow and provides us with screenshots and DOM snapshots. Since we had a significant issue with flaky tests, we immediately integrated this feature into our testing utils, allowing developers to record runs.&lt;/p&gt;

&lt;p&gt;We send CI tracing to a dedicated Slack channel for ease of use.&lt;/p&gt;

&lt;p&gt;This feature is super helpful when you have no clue why the test is failing on CI. Tracing helped us catch some unimaginable bugs that we wouldn't have caught otherwise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkg4mobvpfzt90v3tcsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkg4mobvpfzt90v3tcsm.png" alt="Send CI trace files to slack" width="415" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop using ElementHandles. Start using Playwright Locators
&lt;/h2&gt;

&lt;p&gt;Following the release of &lt;a href="https://playwright.dev/docs/locators" rel="noopener noreferrer"&gt;Playwright Locators&lt;/a&gt; and &lt;a href="https://playwright.dev/docs/locators#locator-vs-elementhandle" rel="noopener noreferrer"&gt;ElementHandle being discouraged&lt;/a&gt; from use, we decided to migrate our test kits and test drivers to Locators to enjoy the benefits given to us by this new API: &lt;a href="https://playwright.dev/docs/actionability" rel="noopener noreferrer"&gt;actionability check&lt;/a&gt;, more strictness (detailed below), and in our React application - reduced flakiness. &lt;/p&gt;

&lt;p&gt;From our experience, we can say that simply replacing ElementHandles with Locators in a test can resolve flakiness by itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's wrong with ElementHandles?
&lt;/h3&gt;

&lt;p&gt;Each &lt;code&gt;ElementHandle&lt;/code&gt; refers to an actual specific DOM node. React, when trying to reconcile changes, might replace these referred DOM nodes. This is happening due to changes or as a result of components being unmounted and remounted again, making the referenced &lt;code&gt;ElementHandle&lt;/code&gt; irrelevant. Keeping references to specific DOM nodes is not really needed because we usually get those references with selectors — which are agnostic to specific DOM nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Locators help us to get the correct DOM node
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Locators keep the selector itself rather than a reference to a specific DOM node.&lt;/li&gt;
&lt;li&gt;Upon action (e.g .click()) the locator:

&lt;ul&gt;
&lt;li&gt;Uses the selector to query the DOM node relevant for that try&lt;/li&gt;
&lt;li&gt;Verifies it is actionable (attached, clickable, etc.) &lt;/li&gt;
&lt;li&gt;Validates there is no single-multiple mismatch.&lt;/li&gt;
&lt;li&gt;Repeats the process until it succeeds.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The actionability validation is batched along with the action itself as an atomic action. &lt;br&gt;
For example, an atomic action could be: check if the button is available, visible, clickable and only then click it — meaning less communication between node and the browser.&lt;/p&gt;

&lt;p&gt;By doing the query and validation alongside the action, we prevent possible race conditions that could occur between waitFor -&amp;gt; client re-render -&amp;gt; action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some more benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Increased strictness: default locator will throw an exception if the selector matched more than one element.&lt;/li&gt;
&lt;li&gt;More readable errors: depicts the exact issue of why an action cannot be done instead of a failing assertion or some generic timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Battling flakiness isn’t a short-term thing. &lt;/p&gt;

&lt;p&gt;It requires developers' awareness and care, writing tests more carefully, keeping in mind possible race conditions, and a conscience that tells them it isn’t okay to just rerun tests.&lt;/p&gt;

&lt;p&gt;It requires assistive tooling for testing the test itself and monitoring it.&lt;/p&gt;

&lt;p&gt;It requires priority, time, and guidelines — things you should receive from the technical management, thus requiring them to be aware of this issue.&lt;/p&gt;

&lt;p&gt;A single developer cannot change the state of flakiness — a group effort is needed.&lt;/p&gt;

&lt;p&gt;Flakiness is a manageable long-term battle. Empower yourself with the right tools to not only increase your development velocity, but also elevate your overall experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://shopify.engineering/unreasonable-effectiveness-test-retries-android-monorepo-case-study" rel="noopener noreferrer"&gt;Shopify Engineering: The Unreasonable Effectiveness of Test Retries: An Android Monorepo Case Study&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://engineering.atspotify.com/2019/11/test-flakiness-methods-for-identifying-and-dealing-with-flaky-tests/" rel="noopener noreferrer"&gt;Spotify Engineering: Test Flakiness – Methods for identifying and dealing with flaky tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html" rel="noopener noreferrer"&gt;Google Testing Blog: Flaky Tests at Google and How We Mitigate Them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://library.oapen.org/viewer/web/viewer.html?file=/bitstream/handle/20.500.12657/22839/1007322.pdf?sequence=1&amp;amp;isAllowed=y" rel="noopener noreferrer"&gt;Rethinking Productivity in Software Engineering, Edited by Caitlin Sadowski, Thomas Zimmermann - page 139 - The Cost of Context Switching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/docs/api/class-browsercontext#browser-context-new-cdp-session" rel="noopener noreferrer"&gt;Playwright: newCDPSession&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
