<?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: Sourabh  Gawande</title>
    <description>The latest articles on DEV Community by Sourabh  Gawande (@gaw).</description>
    <link>https://dev.to/gaw</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%2F1160437%2Ff0b63fe6-a8cd-4081-aee5-bcc1b7acd1e4.png</url>
      <title>DEV Community: Sourabh  Gawande</title>
      <link>https://dev.to/gaw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaw"/>
    <language>en</language>
    <item>
      <title>I Replaced Redis Locks with Database Atomicity and You Should Too</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 03 Sep 2025 18:03:30 +0000</pubDate>
      <link>https://dev.to/gaw/i-replaced-redis-locks-with-database-atomicity-and-you-should-too-3i0m</link>
      <guid>https://dev.to/gaw/i-replaced-redis-locks-with-database-atomicity-and-you-should-too-3i0m</guid>
      <description>&lt;p&gt;Picture this: You are a dev in a payment services company. The thing with payment transactions is that you are supposed to process each transaction (e.g. send money from John's account to Jane) exactly once. It's 3 AM, your PagerDuty is blowing up with alerts about transactions being processed multiple times by cron jobs, and you're staring at Redis locks that &lt;em&gt;should&lt;/em&gt; prevent this exact problem. Sound familiar?&lt;/p&gt;

&lt;p&gt;We didn't end up sending money to someone 20 times, but our problem was similar. This is the story of how we went from a complex Redis-based locking nightmare to a beautifully simple database-centric solution, and why you should probably ditch those distributed locks too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Redis Lock Disaster of 2025
&lt;/h2&gt;

&lt;p&gt;Let me set the scene. We have this automated testing platform where developers would push their OpenAPI specs, and our job workers would generate tests in the background. Think Postman, but the test generation is automated. Simple enough, right? Wrong.&lt;/p&gt;

&lt;p&gt;The system worked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer pushes an OpenAPI spec with 50 endpoints to our platform&lt;/li&gt;
&lt;li&gt;We create 50 "pending" test generation tasks in the database
&lt;/li&gt;
&lt;li&gt;Multiple job instances fight over who gets to process what&lt;/li&gt;
&lt;li&gt;Chaos ensues, developers get duplicate test suites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our "brilliant" solution was Redis user-level locking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;redis_client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Get users with pending tasks
&lt;/span&gt;    &lt;span class="n"&gt;users_with_pending_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_users_with_pending_tasks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Try to acquire lock for a user  
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users_with_pending_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;lock_acquired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setnx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;process_lock_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lock_acquired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Acquired lock for user &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;process_user_tasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;process_lock_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Release lock
&lt;/span&gt;            &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looked solid on paper. One job per user, clean separation, what could go wrong?&lt;/p&gt;

&lt;p&gt;Turns out, a lot. Here's what we discovered after days of debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ghost Lock Problem
&lt;/h3&gt;

&lt;p&gt;Jobs would crash (because who writes perfect code?), leaving behind zombie locks in Redis. Developer #12345's tasks would be forever locked, waiting for a job that no longer exists. We'd have to manually clean these up, which is about as fun as debugging CSS alignment issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Race Condition Ballet
&lt;/h3&gt;

&lt;p&gt;Even worse, we had this beautiful race condition where two jobs would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Both check if a developer has pending tasks ✓&lt;/li&gt;
&lt;li&gt;Both try to acquire the same user's lock &lt;/li&gt;
&lt;li&gt;One succeeds, one fails, but... &lt;/li&gt;
&lt;li&gt;The winner sometimes processed tasks that were already being handled&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It was like watching two developers simultaneously fix the same bug in different branches.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "It Should Work" Syndrome
&lt;/h3&gt;

&lt;p&gt;The most frustrating part? The logic was sound. User-level locking &lt;em&gt;should&lt;/em&gt; prevent duplicate processing. But we were still getting duplicate test suites generated, and developers were opening GitHub issues faster than we could close them.&lt;/p&gt;

&lt;p&gt;After staring at this code for the hundredth time, my teammate dropped this gem: "Why are we even using Redis for this? Isn't our database already designed to handle concurrency?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The Database Epiphany
&lt;/h2&gt;

&lt;p&gt;They were right. Here we were, adding this complex external dependency when PostgreSQL has been solving concurrency problems since before Redis was even a twinkle in antirez's eye.&lt;/p&gt;

&lt;p&gt;The solution was embarrassingly simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;claim_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UPDATE tasks SET status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; WHERE id = %s AND status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rowcount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="c1"&gt;# True if we successfully claimed it
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Twelve lines of Redis complexity replaced by three lines of SQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Actually Works
&lt;/h3&gt;

&lt;p&gt;When two jobs try to claim the same task simultaneously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Job A&lt;/strong&gt; executes the UPDATE first (we're talking microseconds here)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job B&lt;/strong&gt; executes the UPDATE immediately after&lt;/li&gt;
&lt;li&gt;Job A finds &lt;code&gt;status = 'pending'&lt;/code&gt;, updates it to 'processing', returns &lt;code&gt;rowcount = 1&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Job B finds &lt;code&gt;status = 'processing'&lt;/code&gt; (not 'pending'), updates nothing, returns &lt;code&gt;rowcount = 0&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The database engine handles all the locking, isolation, and consistency for us. It's literally what ACID properties were designed for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Approach: Beautifully Boring
&lt;/h2&gt;

&lt;p&gt;Here's what our main processing loop became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Get all pending tasks - dead simple
&lt;/span&gt;    &lt;span class="n"&gt;pending_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_tasks_by_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pending_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Try to atomically claim this task
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;claim_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Got task &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, let&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s go!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;process_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Task &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; stolen by another worker, moving on...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;claim_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UPDATE tasks SET status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; WHERE id = %s AND status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rowcount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Redis calls. No lock cleanup. No timeouts. No complex error handling. Just pure, boring database operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the Resource Hog Problem
&lt;/h2&gt;

&lt;p&gt;But wait, there's more! (There's always more, isn't there?)&lt;/p&gt;

&lt;p&gt;Our celebration was short-lived. Within a week, we discovered a new problem: one startup uploaded their monolithic API spec with 1,000 endpoints (yes, we've all been there). Guess what happened? All our job instances started fighting over that user's tasks, completely ignoring everyone else.&lt;/p&gt;

&lt;p&gt;Meanwhile, Sarah uploaded her simple microservice spec with 3 endpoints and watched it sit in the queue for hours while MegaCorp's monolith hogged all the workers. Classic tragedy of the commons.&lt;/p&gt;

&lt;p&gt;This is where the simplicity of our solution became both a blessing and a curse. It was too fair - treating all tasks equally regardless of user impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fairness Fix: Not All Users Are Created Equal
&lt;/h2&gt;

&lt;p&gt;We went with the simplest solution first: limit each user to 2 concurrent test generation tasks max.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;pending_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_tasks_by_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pending_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Check if this user is already hogging resources
&lt;/span&gt;        &lt;span class="n"&gt;user_task_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_user_task_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_task_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Max 2 concurrent tasks per user
&lt;/span&gt;            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; hit their limit, skipping...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="c1"&gt;# Try to claim the task
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;claim_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing task for user &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;process_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_task_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT COUNT(*) as count FROM tasks WHERE user_id = %s AND status = %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, effective, and Sarah is happy again.&lt;/p&gt;

&lt;h2&gt;
  
  
  There Are A Few Other Ways To Solve This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Single-Query Approach: For the SQL Wizards
&lt;/h3&gt;

&lt;p&gt;If you want to be fancy (and reduce database calls), you can do the fairness check and task claiming in one atomic operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;claim_task_with_fairness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_concurrent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        UPDATE tasks t1 
        SET status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; 
        WHERE t1.id = %s AND t1.status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
        AND (
            SELECT COUNT(*) 
            FROM tasks t2 
            WHERE t2.user_id = t1.user_id 
            AND t2.status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
        ) &amp;lt; %s
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_concurrent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rowcount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is beautiful from a database perspective - one query does it all. But it's harder to debug when things go wrong, and trust me, things will go wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Round-Robin Approach: Maximum Fairness
&lt;/h3&gt;

&lt;p&gt;For maximum fairness, you can prioritize users who have fewer tasks running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_fair_pending_tasks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get tasks ordered by user fairness - users with fewer running tasks go first&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        SELECT t1.* FROM tasks t1
        LEFT JOIN (
            SELECT user_id, COUNT(*) as running_count
            FROM tasks 
            WHERE status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
            GROUP BY user_id
        ) t2 ON t1.user_id = t2.user_id
        WHERE t1.status = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
        ORDER BY COALESCE(t2.running_count, 0) ASC, t1.created_at ASC
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query is doing some heavy lifting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get all pending tasks&lt;/li&gt;
&lt;li&gt;Count how many tasks each user has running&lt;/li&gt;
&lt;li&gt;Order by fewest running tasks first, then by creation time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's more complex but gives you true round-robin fairness. MegaCorp's monolith still gets processed, but not at Sarah's microservice's  expense.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Time-Based Approach: "When Did I Last Process This User?"
&lt;/h3&gt;

&lt;p&gt;You could also add a &lt;code&gt;last_processed_at&lt;/code&gt; timestamp to users and prioritize those who haven't been processed recently. But honestly, that's probably overkill unless you're running something like GitHub Actions at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lessons I Wish I'd Learned Sooner
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Your Database Is Smarter Than You Think
&lt;/h3&gt;

&lt;p&gt;I spent weeks building a distributed locking system when PostgreSQL was sitting there like "I've literally been doing this since 1996, but okay..."&lt;/p&gt;

&lt;p&gt;Databases are &lt;em&gt;designed&lt;/em&gt; for concurrency. ACID properties exist for exactly these scenarios. Use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Complexity Is a Bug, Not a Feature
&lt;/h3&gt;

&lt;p&gt;Every line of Redis locking code was a potential failure point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network timeouts&lt;/li&gt;
&lt;li&gt;Lock cleanup failures
&lt;/li&gt;
&lt;li&gt;Race conditions between services&lt;/li&gt;
&lt;li&gt;Memory management in Redis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The database solution eliminated all of this. Sometimes the best code is the code you don't write.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Fairness Isn't Optional in Multi-Tenant Systems
&lt;/h3&gt;

&lt;p&gt;We learned this the hard way when MegaCorp's monolith starved all the microservice users. If you're building anything where multiple users compete for resources, think about fairness from day one, not when your users start filing angry GitHub issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Start Simple, Then Optimize
&lt;/h3&gt;

&lt;p&gt;We went with the two-query approach (check user count, then claim task) rather than the fancy single-query version. Why? Because when something breaks at 3 AM, you want to be able to debug it quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Reality Check
&lt;/h2&gt;

&lt;p&gt;Let's be honest about the trade-offs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No Redis memory usage&lt;/li&gt;
&lt;li&gt;✅ Leverages existing database infrastructure
&lt;/li&gt;
&lt;li&gt;✅ ACID guarantees&lt;/li&gt;
&lt;li&gt;❌ Extra SELECT query for fairness checks&lt;/li&gt;
&lt;li&gt;❌ Slightly higher database load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Redis Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Fast in-memory operations&lt;/li&gt;
&lt;li&gt;✅ Dedicated locking primitives&lt;/li&gt;
&lt;li&gt;❌ Additional infrastructure to maintain&lt;/li&gt;
&lt;li&gt;❌ Network calls can fail&lt;/li&gt;
&lt;li&gt;❌ Lock cleanup complexity&lt;/li&gt;
&lt;li&gt;❌ Memory management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our use case, the database approach was clearly better. Your mileage may vary.&lt;/p&gt;

&lt;h2&gt;
  
  
  When To Use Each Approach
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Go with database atomicity when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your tasks live in the database anyway&lt;/li&gt;
&lt;li&gt;You want strong consistency guarantees&lt;/li&gt;
&lt;li&gt;You're trying to reduce infrastructure complexity&lt;/li&gt;
&lt;li&gt;You trust your database more than your distributed systems skills (smart choice)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stick with Redis/distributed locks when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need locks across multiple databases&lt;/li&gt;
&lt;li&gt;Tasks involve complex multi-step operations&lt;/li&gt;
&lt;li&gt;You already have Redis infrastructure you're comfortable with&lt;/li&gt;
&lt;li&gt;You're building something like a workflow engine with complex state&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;We replaced 50 lines of complex Redis locking logic with 5 lines of SQL and immediately solved our duplicate processing problem. Sometimes the best engineering solution is the boring one.&lt;/p&gt;

&lt;p&gt;Your database has been solving concurrency problems longer than most of us have been writing code. Maybe it's time to trust it.&lt;/p&gt;




</description>
      <category>redis</category>
      <category>taskqueue</category>
      <category>python</category>
      <category>java</category>
    </item>
    <item>
      <title>When Docker Almost Died: Exploring Container Alternatives</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 03 Sep 2025 06:26:07 +0000</pubDate>
      <link>https://dev.to/gaw/when-docker-almost-died-exploring-container-alternatives-4jnn</link>
      <guid>https://dev.to/gaw/when-docker-almost-died-exploring-container-alternatives-4jnn</guid>
      <description>&lt;p&gt;During one of my mindless internet browsing sessions, I stumbled upon (Side note: I really miss &lt;a href="https://en.wikipedia.org/wiki/StumbleUpon" rel="noopener noreferrer"&gt;StumbleUpon&lt;/a&gt; for finding random sites - they shut it down in 2018 🪦) an article about Docker almost going under back in 2019. Anyway, reading about how Docker nearly died got me thinking: what would we do if Docker disappeared tomorrow?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Elegant Solution That Almost Wasn't
&lt;/h2&gt;

&lt;p&gt;Before diving into alternatives, let's appreciate what Docker achieved. It's one of the most elegant pieces of tech built in the last 10 years, solving the notorious "works on my machine" problem by literally shipping the whole machine. It has become an indispensable part of the tech stack for most tech companies.&lt;/p&gt;

&lt;p&gt;But there was a time when Docker was in serious financial trouble.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 2019 Crisis That Almost Killed Docker
&lt;/h3&gt;

&lt;p&gt;In September 2019, leaked memos revealed that Docker CEO Rob Bearden acknowledged "uncertainty [which] brings with it significant challenges" as the company desperately sought funding. While companies like Elastic and MongoDB had managed to build big businesses around their open-source software, Docker was looking to private investors just to keep going.&lt;/p&gt;

&lt;p&gt;The situation was dire:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Despite having raised $272.9 million previously, Docker wasn't profitable&lt;/li&gt;
&lt;li&gt;The company went through three CEOs in 2019 alone - Steve Singh stepped down in May, was replaced by Rob Bearden, who was then replaced by Scott Johnston in November&lt;/li&gt;
&lt;li&gt;Docker was forced to sell its enterprise business to Mirantis for an undisclosed amount&lt;/li&gt;
&lt;li&gt;The company managed to secure a $35M investment in November 2019, but only after selling off major parts of its business&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There was a real chance of Docker shutting down and possibly not being maintained—which is the case with any software. There's always a possibility of it shutting down for whatever reasons. This made me wonder: if Docker shuts down and is no longer maintained, what are our alternatives?&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives: Your Options If Docker Disappears
&lt;/h2&gt;

&lt;p&gt;Here's a comprehensive breakdown of the main alternatives to Docker:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Podman&lt;/strong&gt; - The Drop-in Replacement
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A daemonless, rootless container engine that's designed to be a direct Docker replacement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs each container as a standard user process, making it inherently more secure and lightweight&lt;/li&gt;
&lt;li&gt;Drop-in replacement for Docker CLI commands&lt;/li&gt;
&lt;li&gt;Typically offers the best cost-efficiency for enterprises, eliminating licensing fees while providing enterprise-grade features&lt;/li&gt;
&lt;li&gt;Rootless containers by default&lt;/li&gt;
&lt;li&gt;No daemon required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller ecosystem compared to Docker&lt;/li&gt;
&lt;li&gt;Some Docker Compose features may not work identically&lt;/li&gt;
&lt;li&gt;Learning curve for Docker-specific workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Migration effort:&lt;/strong&gt; Minimal - literally just replace &lt;code&gt;docker&lt;/code&gt; with &lt;code&gt;podman&lt;/code&gt; in your commands. Your existing Dockerfiles work as-is. You might need to adjust some networking configs for rootless mode, but most workflows transfer directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pricing:&lt;/strong&gt; Free and open source&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Maintenance:&lt;/strong&gt; Actively maintained by Red Hat&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Security-conscious environments, enterprise deployments&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Getting started:&lt;/strong&gt; &lt;a href="https://podman.io/getting-started/" rel="noopener noreferrer"&gt;Podman Official Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;containerd&lt;/strong&gt; - The Kubernetes Native Choice
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A runtime that focuses purely on runtime operations and serves as the container runtime for Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tests show containerd consumes fewer CPU resources compared to Docker&lt;/li&gt;
&lt;li&gt;Industry standard for Kubernetes&lt;/li&gt;
&lt;li&gt;Lightweight and focused&lt;/li&gt;
&lt;li&gt;Cloud native&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has fewer high-level features than a full-featured tool like Docker or Podman&lt;/li&gt;
&lt;li&gt;Migration complexity is moderate - requires installing and learning a separate client tool like nerdctl&lt;/li&gt;
&lt;li&gt;Less user-friendly for development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Migration effort:&lt;/strong&gt; Medium - you'll need to install containerd and either learn ctr commands or install nerdctl for familiar syntax. Your CI/CD pipelines will need updates since you can't build images directly. Plan for some config file changes and team training.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pricing:&lt;/strong&gt; Free and open source&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Maintenance:&lt;/strong&gt; Actively maintained by CNCF&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Kubernetes deployments, cloud-native applications&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Getting started:&lt;/strong&gt; &lt;a href="https://containerd.io/docs/" rel="noopener noreferrer"&gt;containerd Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;LXC/LXD&lt;/strong&gt; - System-Level Containers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Linux container technology that provides OS-level virtualization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excels for system containers&lt;/li&gt;
&lt;li&gt;Better isolation than application containers&lt;/li&gt;
&lt;li&gt;Can run multiple processes and services&lt;/li&gt;
&lt;li&gt;Near-native performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;May use more memory due to its system-level operations&lt;/li&gt;
&lt;li&gt;Different use case from Docker and Podman which target application containers&lt;/li&gt;
&lt;li&gt;Steeper learning curve&lt;/li&gt;
&lt;li&gt;Less portable than Docker containers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Migration effort:&lt;/strong&gt; High - this isn't really a migration, it's a complete rethink. You'd redesign your architecture to use system containers instead of app containers. Think moving from microservices back to more traditional server setups, but containerized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pricing:&lt;/strong&gt; Free and open source&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Maintenance:&lt;/strong&gt; Actively maintained by Canonical&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Long-running workloads, system containers&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Getting started:&lt;/strong&gt; &lt;a href="https://linuxcontainers.org/lxd/getting-started-cli/" rel="noopener noreferrer"&gt;LXD Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Buildah&lt;/strong&gt; - Container Image Builder
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A tool that enables you to add content back to a container image, where the buildah run command imitates the RUN command in a Dockerfile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excellent for building container images&lt;/li&gt;
&lt;li&gt;Works well with Podman&lt;/li&gt;
&lt;li&gt;No daemon required&lt;/li&gt;
&lt;li&gt;Fine-grained control over image layers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Migration effort:&lt;/strong&gt; Medium - mainly impacts your CI/CD image building. You'd replace docker build with Buildah scripts and pair it with Podman for running containers. Your development workflow stays mostly the same, but build pipelines need rewriting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focused primarily on building, not running containers&lt;/li&gt;
&lt;li&gt;Requires additional tools for full container lifecycle&lt;/li&gt;
&lt;li&gt;Learning curve for Docker users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pricing:&lt;/strong&gt; Free and open source&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Maintenance:&lt;/strong&gt; Actively maintained by Red Hat&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Container image building pipelines&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Getting started:&lt;/strong&gt; &lt;a href="https://buildah.io/getting-started.html" rel="noopener noreferrer"&gt;Buildah Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;nerdctl&lt;/strong&gt; - containerd CLI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; containerd with a Docker-like command-line interface - making containerd user-friendly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Familiar Docker commands&lt;/li&gt;
&lt;li&gt;Works directly with containerd&lt;/li&gt;
&lt;li&gt;Supports Docker Compose syntax&lt;/li&gt;
&lt;li&gt;Additional features like image encryption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Still relatively new and less battle-tested&lt;/li&gt;
&lt;li&gt;Some Docker features still missing&lt;/li&gt;
&lt;li&gt;Requires containerd knowledge for troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Migration effort:&lt;/strong&gt; Low - commands are nearly identical (&lt;code&gt;docker run&lt;/code&gt; becomes &lt;code&gt;nerdctl run&lt;/code&gt;), and it supports docker-compose.yml files. Main effort is installing containerd + nerdctl and updating your scripts to use the new binary name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pricing:&lt;/strong&gt; Free and open source&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Maintenance:&lt;/strong&gt; Actively maintained&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Teams transitioning from Docker to containerd, local development&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Getting started:&lt;/strong&gt; &lt;a href="https://github.com/containerd/nerdctl" rel="noopener noreferrer"&gt;nerdctl GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;p&gt;When considering alternatives, think about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Team expertise:&lt;/strong&gt; Docker has the lowest learning curve for beginners&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use case specificity:&lt;/strong&gt; LXC excels for system containers, while Docker and Podman target application containers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance needs:&lt;/strong&gt; All perform well, but choose based on your specific requirements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security requirements:&lt;/strong&gt; Podman's rootless approach may be preferred in security-conscious environments&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Docker's Recovery
&lt;/h2&gt;

&lt;p&gt;It's good to know there are some decent alternatives even if Docker goes belly up. Although it seems like Docker has recovered from their troubles and is doing pretty well now. The company reached $207M in annual recurring revenue (ARR) by 2024, up 25% year-over-year from $165M in 2023. They successfully pivoted to a per-seat subscription model for Docker Desktop, which has proven sustainable.&lt;/p&gt;

&lt;p&gt;The 2019 crisis was a wake-up call that even essential technologies can face existential threats. While Docker has successfully turned things around, exploring alternatives taught me a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For drop-in replacement:&lt;/strong&gt; Podman is your best bet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Kubernetes environments:&lt;/strong&gt; containerd is the natural choice
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For system-level containers:&lt;/strong&gt; LXC/LXD provides better isolation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For CI/CD pipelines:&lt;/strong&gt; Buildah excels at image building&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either way, it's always good to have options. The container ecosystem is robust enough that if Docker disappeared tomorrow, we'd have viable alternatives to keep our applications running. Though let's hope it doesn't come to that!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Chrome DevTools: The Complete Use Case Guide for Developers</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Mon, 01 Sep 2025 20:48:22 +0000</pubDate>
      <link>https://dev.to/gaw/chrome-devtools-the-complete-use-case-guide-for-developers-20la</link>
      <guid>https://dev.to/gaw/chrome-devtools-the-complete-use-case-guide-for-developers-20la</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical, scenario-based breakdown of Chrome DevTools features that every developer should know&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Chrome DevTools is arguably the most powerful debugging toolkit available to web developers, yet most of us only scratch the surface. This guide breaks down DevTools by real-world use cases you encounter daily, showing you exactly which tools to use and how to use them effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Performance &amp;amp; Speed Analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "My page loads slowly - where's the bottleneck?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use the Performance Tab:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools → &lt;strong&gt;Performance&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click the record button (circle icon)&lt;/li&gt;
&lt;li&gt;Reload your page or interact with it&lt;/li&gt;
&lt;li&gt;Stop recording and analyze the flame chart&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Red triangles&lt;/strong&gt;: Performance warnings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long yellow bars&lt;/strong&gt;: JavaScript execution blocking the main thread&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purple bars&lt;/strong&gt;: Layout/reflow operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Green bars&lt;/strong&gt;: Painting operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Use the "Screenshots" checkbox to see exactly when visual changes occur.&lt;/p&gt;

&lt;h3&gt;
  
  
  "My API calls are taking forever - how long exactly?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use the Network Tab:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools → &lt;strong&gt;Network&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Reload the page or trigger your API calls&lt;/li&gt;
&lt;li&gt;Look at the &lt;strong&gt;Time&lt;/strong&gt; column for total request duration&lt;/li&gt;
&lt;li&gt;Click on any request to see the detailed timing breakdown:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queueing&lt;/strong&gt;: Time waiting to be processed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stalled&lt;/strong&gt;: Time spent waiting for available connection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS Lookup&lt;/strong&gt;: Domain resolution time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initial Connection&lt;/strong&gt;: Time to establish connection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL&lt;/strong&gt;: Time for SSL handshake&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Sent&lt;/strong&gt;: Time to send request data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waiting (TTFB)&lt;/strong&gt;: Time to first byte from server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Download&lt;/strong&gt;: Time to download response&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Filtering tricks:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type &lt;code&gt;XHR&lt;/code&gt; to see only API calls&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;fetch&lt;/code&gt; to see fetch requests&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;larger-than:1M&lt;/code&gt; to find large files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "JavaScript is blocking my UI - what's causing it?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use the Performance Tab + Call Tree:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Record a performance profile during the slow interaction&lt;/li&gt;
&lt;li&gt;Look for long yellow bars in the flame chart&lt;/li&gt;
&lt;li&gt;Click on them to see the &lt;strong&gt;Call Tree&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Sort by &lt;strong&gt;Self Time&lt;/strong&gt; to find the heaviest functions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Coverage Tab for unused code:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Coverage&lt;/strong&gt; tab (in drawer)&lt;/li&gt;
&lt;li&gt;Click record and interact with your page&lt;/li&gt;
&lt;li&gt;Red bars show unused JavaScript/CSS&lt;/li&gt;
&lt;li&gt;Click on files to see exactly which lines aren't executed&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  📱 Responsive Design &amp;amp; Mobile Testing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "How does my site look on different screen sizes?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Device Simulation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Device Toggle&lt;/strong&gt; (phone/tablet icon) or press &lt;code&gt;Ctrl+Shift+M&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select from preset devices or click &lt;strong&gt;Edit&lt;/strong&gt; to add custom dimensions&lt;/li&gt;
&lt;li&gt;Test common breakpoints: 320px (mobile), 768px (tablet), 1024px (desktop)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Custom responsive testing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag the viewport edges to test any size&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Responsive&lt;/strong&gt; dropdown to quickly switch between sizes&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;Zoom&lt;/strong&gt; dropdown to test different pixel densities&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Is my mobile experience actually usable?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Touch Simulation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable Device Mode&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;three dots menu&lt;/strong&gt; → &lt;strong&gt;More tools&lt;/strong&gt; → &lt;strong&gt;Sensors&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Touch&lt;/strong&gt; to "Force enabled"&lt;/li&gt;
&lt;li&gt;Test your touch interactions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Network throttling for mobile:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Network tab, click &lt;strong&gt;No throttling&lt;/strong&gt; dropdown&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Slow 3G&lt;/strong&gt; or &lt;strong&gt;Fast 3G&lt;/strong&gt; to simulate mobile networks&lt;/li&gt;
&lt;li&gt;Test how your app performs on slower connections&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  "What's causing horizontal scroll on mobile?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Element inspection trick:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Switch to mobile view&lt;/li&gt;
&lt;li&gt;Right-click and &lt;strong&gt;Inspect Element&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In Console, run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollWidth&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientWidth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wide element:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🐛 JavaScript Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "My code is throwing errors - where exactly?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Console Tab mastery:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Red errors&lt;/strong&gt; show exactly where code failed&lt;/li&gt;
&lt;li&gt;Click the link on the right to jump to the exact line&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;console.trace()&lt;/code&gt; in your code to see the full call stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sources Tab debugging:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Sources&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Find your file in the file tree&lt;/li&gt;
&lt;li&gt;Click line numbers to set &lt;strong&gt;breakpoints&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Reload/trigger the code to pause execution&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;Scope&lt;/strong&gt; panel to inspect variable values&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  "Variables aren't what I expect - how do I inspect them?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Live expression watching:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Console, click the &lt;strong&gt;eye icon&lt;/strong&gt; (Create live expression)&lt;/li&gt;
&lt;li&gt;Enter variable names or expressions to watch in real-time&lt;/li&gt;
&lt;li&gt;They update automatically as you step through code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Breakpoint debugging:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;F10&lt;/strong&gt;: Step over (next line)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;F11&lt;/strong&gt;: Step into (enter functions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shift+F11&lt;/strong&gt;: Step out (exit current function)&lt;/li&gt;
&lt;li&gt;Hover over any variable to see its current value&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Event listeners aren't firing - what's attached where?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Elements Tab event inspection:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select any element in the &lt;strong&gt;Elements&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;In the right panel, scroll to &lt;strong&gt;Event Listeners&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;See all events attached to that element&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Framework listeners&lt;/strong&gt; to see through library abstractions&lt;/li&gt;
&lt;li&gt;Click the function name to jump to the code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Console event monitoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Monitor all click events&lt;/span&gt;
&lt;span class="nf"&gt;monitorEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Monitor specific element&lt;/span&gt;
&lt;span class="nf"&gt;monitorEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// $0 is currently selected element&lt;/span&gt;

&lt;span class="c1"&gt;// Stop monitoring&lt;/span&gt;
&lt;span class="nf"&gt;unmonitorEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🌐 Network &amp;amp; API Analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Which requests are failing and why?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Network Tab filtering:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Red entries&lt;/strong&gt;: Failed requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yellow entries&lt;/strong&gt;: Redirects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter by status&lt;/strong&gt;: Type &lt;code&gt;status-code:404&lt;/code&gt; or &lt;code&gt;status-code:500&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter by domain&lt;/strong&gt;: Type &lt;code&gt;domain:api.yoursite.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Response inspection:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on any failed request&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Headers&lt;/strong&gt; tab for request/response details&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Response&lt;/strong&gt; tab for error messages&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Preview&lt;/strong&gt; tab for formatted JSON&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  "What headers are being sent/received?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Headers analysis:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on any request in Network tab&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt; tab shows:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Headers&lt;/strong&gt;: What your browser sent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Headers&lt;/strong&gt;: What the server returned&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query String Parameters&lt;/strong&gt;: URL parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Data&lt;/strong&gt;: POST body content&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Copy as cURL:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Right-click any request → &lt;strong&gt;Copy&lt;/strong&gt; → &lt;strong&gt;Copy as cURL&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Test the exact same request in terminal or Postman&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How do I simulate slow network conditions?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Network throttling:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Network tab → &lt;strong&gt;No throttling&lt;/strong&gt; dropdown&lt;/li&gt;
&lt;li&gt;Choose preset (Slow 3G, Fast 3G) or &lt;strong&gt;Add&lt;/strong&gt; custom profiles&lt;/li&gt;
&lt;li&gt;Watch how your app handles slow loading&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Offline testing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Offline&lt;/strong&gt; to test your app's offline behavior&lt;/li&gt;
&lt;li&gt;Great for testing service worker functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔒 Security &amp;amp; Privacy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "What cookies/storage does my site use?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Application Tab overview:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Application&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Left sidebar shows all storage:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Storage&lt;/strong&gt;: Persistent key-value data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Storage&lt;/strong&gt;: Session-only data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookies&lt;/strong&gt;: All cookies with expiration dates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB&lt;/strong&gt;: Structured database storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Storage&lt;/strong&gt;: Service worker caches&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cookie inspection:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Cookies&lt;/strong&gt; → your domain&lt;/li&gt;
&lt;li&gt;See all cookies with values, expiration, and security flags&lt;/li&gt;
&lt;li&gt;Double-click any value to edit for testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Are there any security warnings?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Security Tab:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Security&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;See certificate details and security state&lt;/li&gt;
&lt;li&gt;Check for mixed content warnings (HTTP resources on HTTPS page)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Console security warnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red security warnings appear in Console&lt;/li&gt;
&lt;li&gt;Common issues: mixed content, unsafe inline scripts, CSP violations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ♿ SEO &amp;amp; Accessibility
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "What accessibility issues exist?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lighthouse audit:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Lighthouse&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Accessibility&lt;/strong&gt; category&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate report&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Get specific recommendations with line numbers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Elements Tab accessibility:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select any element&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt; panel (right side) shows:

&lt;ul&gt;
&lt;li&gt;ARIA attributes&lt;/li&gt;
&lt;li&gt;Computed accessibility name&lt;/li&gt;
&lt;li&gt;Role and properties&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Accessibility tree:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Console → Settings (gear icon) → &lt;strong&gt;Experiments&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable "Full accessibility tree in Elements panel"&lt;/li&gt;
&lt;li&gt;See how screen readers interpret your page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How does my site appear to screen readers?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Screen reader simulation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Elements tab → select element&lt;/li&gt;
&lt;li&gt;Right panel → &lt;strong&gt;Accessibility&lt;/strong&gt; section&lt;/li&gt;
&lt;li&gt;See &lt;strong&gt;Name&lt;/strong&gt;, &lt;strong&gt;Role&lt;/strong&gt;, and &lt;strong&gt;Properties&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Computed Properties&lt;/strong&gt; to see final accessibility values&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  💾 Application State &amp;amp; Storage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "What data is stored locally?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Storage inspection:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt; tab → &lt;strong&gt;Storage&lt;/strong&gt; section&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Storage&lt;/strong&gt;: Persistent data that survives browser restarts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Storage&lt;/strong&gt;: Data cleared when tab closes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB&lt;/strong&gt;: Complex structured data storage&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Quick storage clearing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Right-click on any storage type → &lt;strong&gt;Clear&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Or use Console: &lt;code&gt;localStorage.clear()&lt;/code&gt;, &lt;code&gt;sessionStorage.clear()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How do I modify storage for testing?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Direct editing:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Application tab → Local/Session Storage&lt;/li&gt;
&lt;li&gt;Double-click any key or value to edit&lt;/li&gt;
&lt;li&gt;Right-click to add new entries&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Console manipulation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Set values&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&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="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Get values&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Remove specific items&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎨 CSS &amp;amp; Visual Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Why doesn't my CSS look right?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Elements Tab CSS debugging:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Right-click element → &lt;strong&gt;Inspect&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styles&lt;/strong&gt; panel shows all applied CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crossed-out styles&lt;/strong&gt;: Overridden rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orange warning icons&lt;/strong&gt;: Invalid CSS values&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Computed&lt;/strong&gt; tab: Final calculated values&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Box model visualization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select element → &lt;strong&gt;Styles&lt;/strong&gt; panel&lt;/li&gt;
&lt;li&gt;Hover over the box model diagram&lt;/li&gt;
&lt;li&gt;See margin (orange), border (yellow), padding (green), content (blue)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CSS changes testing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click any CSS property to edit&lt;/li&gt;
&lt;li&gt;Add new properties by clicking in empty space&lt;/li&gt;
&lt;li&gt;Changes are temporary - refresh to revert&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How do I find which CSS rule is affecting my element?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CSS cascade inspection:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select element in Elements tab&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styles&lt;/strong&gt; panel shows rules in cascade order (most specific first)&lt;/li&gt;
&lt;li&gt;Look for &lt;strong&gt;Inherited from&lt;/strong&gt; sections&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;filter box&lt;/strong&gt; to search for specific properties&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;CSS specificity calculator:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hover over any CSS selector to see specificity value&lt;/li&gt;
&lt;li&gt;Higher numbers win the cascade battle&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔧 Advanced Debugging Techniques
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Memory leaks are suspected - how do I find them?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Memory Tab analysis:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt; tab → &lt;strong&gt;Heap snapshot&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Take snapshot, interact with your app, take another snapshot&lt;/li&gt;
&lt;li&gt;Compare snapshots to see memory growth&lt;/li&gt;
&lt;li&gt;Look for &lt;strong&gt;Detached DOM nodes&lt;/strong&gt; and &lt;strong&gt;Event listeners&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Performance memory tracking:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Memory&lt;/strong&gt; checkbox before recording&lt;/li&gt;
&lt;li&gt;See memory usage over time in the timeline&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  "How do I debug Web Workers or Service Workers?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Application Tab Workers:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt; tab → &lt;strong&gt;Service Workers&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;See registration status and update cycles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sources&lt;/strong&gt; tab to debug worker code with breakpoints&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Worker console:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worker console messages appear in main DevTools Console&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;console.log()&lt;/code&gt; in worker code to debug&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠️ Console Power User Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Advanced Console commands I should know?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Element selection shortcuts:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$0&lt;/span&gt; &lt;span class="c1"&gt;// Currently selected element&lt;/span&gt;
&lt;span class="nx"&gt;$1&lt;/span&gt; &lt;span class="c1"&gt;// Previously selected element&lt;/span&gt;
&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Same as document.querySelector()&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Same as document.querySelectorAll()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Network monitoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Monitor all XHR requests&lt;/span&gt;
&lt;span class="nf"&gt;monitorEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Log all function calls to an object&lt;/span&gt;
&lt;span class="nf"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;unmonitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Performance helpers:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Time any operation&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myOperation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ... your code ...&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myOperation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Performance mark for detailed timing&lt;/span&gt;
&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ... code ...&lt;/span&gt;
&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myMeasure&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="s1"&gt;start&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="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📊 Real-World Debugging Workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workflow 1: "My React app is slow"
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance tab&lt;/strong&gt; → Record during slow interaction&lt;/li&gt;
&lt;li&gt;Look for long &lt;strong&gt;yellow bars&lt;/strong&gt; (JavaScript execution)&lt;/li&gt;
&lt;li&gt;Click into them to see which React components are slow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sources tab&lt;/strong&gt; → Add breakpoints in suspicious components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React DevTools&lt;/strong&gt; (if installed) → &lt;strong&gt;Profiler&lt;/strong&gt; for component render times&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Workflow 2: "API integration isn't working"
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Network tab&lt;/strong&gt; → Find the failing request&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Status code&lt;/strong&gt; and &lt;strong&gt;Response&lt;/strong&gt; tabs&lt;/li&gt;
&lt;li&gt;Copy as &lt;strong&gt;cURL&lt;/strong&gt; to test outside browser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Console&lt;/strong&gt; → Check for CORS errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security tab&lt;/strong&gt; → Verify HTTPS issues&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Workflow 3: "Mobile site looks broken"
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Device toggle&lt;/strong&gt; → Select target device&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elements tab&lt;/strong&gt; → Inspect problematic elements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Computed styles&lt;/strong&gt; → Check actual CSS values&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Console&lt;/strong&gt; → Run viewport debugging:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Viewport:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Device pixel ratio:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;devicePixelRatio&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎯 Pro Tips for Each Tab
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Elements Tab
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;H key&lt;/strong&gt;: Hide/show selected element&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Z&lt;/strong&gt;: Undo DOM changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right-click&lt;/strong&gt; → &lt;strong&gt;Scroll into view&lt;/strong&gt;: Find elements in viewport&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Break on&lt;/strong&gt; → &lt;strong&gt;Subtree modifications&lt;/strong&gt;: Pause when DOM changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Console Tab
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+L&lt;/strong&gt;: Clear console&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter levels&lt;/strong&gt;: Click Error, Warning, Info to filter messages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserve log&lt;/strong&gt;: Keep console messages across page reloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$_&lt;/strong&gt;: Reference to last evaluated expression&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Network Tab
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+E&lt;/strong&gt;: Export HAR file for external analysis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Headers&lt;/strong&gt; → &lt;strong&gt;view source&lt;/strong&gt;: See raw headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timing tab&lt;/strong&gt;: Detailed breakdown of request phases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable cache&lt;/strong&gt;: Checkbox to force fresh requests&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sources Tab
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+P&lt;/strong&gt;: Quick file finder&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Shift+F&lt;/strong&gt;: Search across all files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional breakpoints&lt;/strong&gt;: Right-click line number&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logpoints&lt;/strong&gt;: Console.log without modifying code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Application Tab
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear storage&lt;/strong&gt;: Remove all data for clean testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manifest&lt;/strong&gt;: Check PWA configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Workers&lt;/strong&gt;: Debug offline functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔍 Common Debugging Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario: "Button click isn't working"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In Console, check if element exists&lt;/span&gt;
&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;

&lt;span class="c1"&gt;// Check event listeners&lt;/span&gt;
&lt;span class="nf"&gt;getEventListeners&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// Test click programmatically&lt;/span&gt;
&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Check if element is actually clickable&lt;/span&gt;
&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario: "CSS not applying"
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Inspect element → &lt;strong&gt;Computed&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for your CSS property&lt;/li&gt;
&lt;li&gt;If missing: Check &lt;strong&gt;Styles&lt;/strong&gt; for syntax errors (orange warnings)&lt;/li&gt;
&lt;li&gt;If overridden: Look at specificity values&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scenario: "Form data not submitting"
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Network tab&lt;/strong&gt; → Submit form&lt;/li&gt;
&lt;li&gt;Check if POST request appears&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt; → &lt;strong&gt;Request Headers&lt;/strong&gt; → verify &lt;code&gt;Content-Type&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request&lt;/strong&gt; tab → verify form data is included&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🚨 Quick Debugging Checklist
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Page Load Issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Network tab: Any failed requests (red)?&lt;/li&gt;
&lt;li&gt;[ ] Console: Any JavaScript errors (red)?&lt;/li&gt;
&lt;li&gt;[ ] Performance: Any long-running scripts (yellow bars)?&lt;/li&gt;
&lt;li&gt;[ ] Lighthouse: Performance score below 90?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mobile Issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Device mode: Tested on actual target devices?&lt;/li&gt;
&lt;li&gt;[ ] Console: Any viewport meta tag warnings?&lt;/li&gt;
&lt;li&gt;[ ] Network: Tested on slow connections?&lt;/li&gt;
&lt;li&gt;[ ] Touch: All interactive elements large enough (44px minimum)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;API Issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Network: Request/response headers correct?&lt;/li&gt;
&lt;li&gt;[ ] Console: Any CORS errors?&lt;/li&gt;
&lt;li&gt;[ ] Security: Mixed content warnings?&lt;/li&gt;
&lt;li&gt;[ ] Network: Response time acceptable under throttling?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎓 Advanced Features You Should Know
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Local Overrides
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Test changes without deploying:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sources&lt;/strong&gt; tab → &lt;strong&gt;Overrides&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select folder to save changes&lt;/li&gt;
&lt;li&gt;Edit any file and changes persist across reloads&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Workspaces
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Edit files directly:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sources&lt;/strong&gt; → &lt;strong&gt;Filesystem&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add your project folder&lt;/li&gt;
&lt;li&gt;Edit files directly in DevTools&lt;/li&gt;
&lt;li&gt;Changes save to your actual files&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Device Mode Advanced
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Custom device profiles:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Device mode → &lt;strong&gt;Edit&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;Add custom devices with specific:

&lt;ul&gt;
&lt;li&gt;Screen resolution&lt;/li&gt;
&lt;li&gt;Device pixel ratio&lt;/li&gt;
&lt;li&gt;User agent string&lt;/li&gt;
&lt;li&gt;Touch capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Performance Insights (New!)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Automated performance analysis:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance Insights&lt;/strong&gt; tab (newer Chrome versions)&lt;/li&gt;
&lt;li&gt;Automatically identifies performance opportunities&lt;/li&gt;
&lt;li&gt;Provides specific recommendations with code examples&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔥 Console Commands Every Developer Should Know
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Clear console&lt;/span&gt;
&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Copy any value to clipboard&lt;/span&gt;
&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anyObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Get all images on page&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Find elements with specific text&lt;/span&gt;
&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search term&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// Monitor function calls&lt;/span&gt;
&lt;span class="nf"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Debug function calls&lt;/span&gt;
&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Adds automatic breakpoint&lt;/span&gt;

&lt;span class="c1"&gt;// Check performance&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;operation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ... code ...&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;operation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Table format for objects&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayOfObjects&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Group related logs&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API Calls&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupEnd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎯 Productivity Shortcuts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Essential keyboard shortcuts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;F12&lt;/strong&gt;: Open/close DevTools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Shift+C&lt;/strong&gt;: Inspect element mode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Shift+J&lt;/strong&gt;: Jump to Console&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Shift+I&lt;/strong&gt;: Open DevTools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+R&lt;/strong&gt;: Reload page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Shift+R&lt;/strong&gt;: Hard reload (ignore cache)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+Shift+Delete&lt;/strong&gt;: Clear browsing data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Panel shortcuts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+[&lt;/strong&gt;: Previous panel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+]&lt;/strong&gt;: Next panel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escape&lt;/strong&gt;: Toggle drawer (Console while in other tabs)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏆 Pro Tips from the Trenches
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use the Command Menu&lt;/strong&gt;: Press &lt;code&gt;Ctrl+Shift+P&lt;/code&gt; to access any DevTools feature quickly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Screenshot any element&lt;/strong&gt;: Right-click element → &lt;strong&gt;Capture node screenshot&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copy element selectors&lt;/strong&gt;: Right-click element → &lt;strong&gt;Copy&lt;/strong&gt; → &lt;strong&gt;Copy selector&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dock DevTools smartly&lt;/strong&gt;: Click the three dots → choose docking position based on your task&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-line Console editing&lt;/strong&gt;: Press &lt;code&gt;Shift+Enter&lt;/code&gt; for new lines in Console&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preserve console across navigations&lt;/strong&gt;: Settings → &lt;strong&gt;Preserve log&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dark mode&lt;/strong&gt;: Settings → &lt;strong&gt;Preferences&lt;/strong&gt; → &lt;strong&gt;Theme: Dark&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🎬 Conclusion
&lt;/h2&gt;

&lt;p&gt;Chrome DevTools is incredibly powerful when you know which tool to reach for in each situation. The key is thinking in terms of problems you need to solve rather than features you want to explore.&lt;/p&gt;

&lt;p&gt;Bookmark this guide and refer back to it when you encounter these common debugging scenarios. The more you use these workflows, the faster you'll become at diagnosing and fixing issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next time you're debugging, ask yourself:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What exactly am I trying to figure out?&lt;/li&gt;
&lt;li&gt;Which DevTools tab would give me that information?&lt;/li&gt;
&lt;li&gt;What specific metric or value am I looking for?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Master these use cases, and you'll debug faster and build better web applications.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want to level up your debugging skills further? Practice these workflows on your current projects and you'll be amazed at how much faster you can identify and fix issues.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Tracking outbound API calls from your application: why, what worked (and what didn’t)</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Mon, 01 Sep 2025 20:46:56 +0000</pubDate>
      <link>https://dev.to/gaw/tracking-outbound-api-calls-from-your-application-why-what-worked-and-what-didnt-13ii</link>
      <guid>https://dev.to/gaw/tracking-outbound-api-calls-from-your-application-why-what-worked-and-what-didnt-13ii</guid>
      <description>&lt;p&gt;We recently had to do an &lt;strong&gt;on-prem deployment&lt;/strong&gt; (i.e. our SaaS is installed and run on the customer's own physical hardware, servers, and data centers, rather than on our cloud) for a customer—a particularly paranoid one (read: fintech 🏦).&lt;br&gt;&lt;br&gt;
Our application is containerized, and we already had scripts and artifacts for different deployment scenarios (Helm charts for Kubernetes, CloudFormation for AWS ECS, etc.). But there was one thing we didn’t have ready:  &lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;A list of all outbound API calls our application makes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This customer had a strict outbound firewall policy, and they needed an exhaustive whitelist of API endpoints.  &lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Until this point, we hadn’t really thought about outbound calls. Our own infra had no outbound restrictions, so we happily used libraries, SDKs, and third-party services without tracking what domains they pinged. But for on-prem deployments with locked-down firewalls, &lt;strong&gt;this becomes a critical requirement.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Our first instinct was: &lt;em&gt;“How hard can it be?”&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just go through &lt;code&gt;requirements.txt&lt;/code&gt;,
&lt;/li&gt;
&lt;li&gt;Look at the SDKs we use,
&lt;/li&gt;
&lt;li&gt;Identify direct API calls in our code (e.g., &lt;code&gt;requests&lt;/code&gt;),
&lt;/li&gt;
&lt;li&gt;Then compile the list of domains.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds reasonable, right?  &lt;/p&gt;

&lt;p&gt;Except… it didn’t work.  &lt;/p&gt;

&lt;p&gt;Why? Because &lt;strong&gt;SDKs don’t always map cleanly to a single domain.&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many SDKs call multiple endpoints.
&lt;/li&gt;
&lt;li&gt;Some use alternative domains for redundancy.
&lt;/li&gt;
&lt;li&gt;Others make &lt;em&gt;hidden calls&lt;/em&gt; to services you never expected.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: One LLM library suddenly made a call to Azure Blob Storage to fetch a file used for token calculation. Not exactly obvious from the docs.  &lt;/p&gt;

&lt;p&gt;So the manual approach = incomplete.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Exploring Approaches
&lt;/h2&gt;

&lt;p&gt;We turned to ChatGPT (of course) to ask how to track &lt;em&gt;all&lt;/em&gt; API calls made by a Python backend. We got a bunch of suggestions that sounded good in theory, but didn’t fully solve the problem in practice.  &lt;/p&gt;

&lt;p&gt;Here’s a summary:  &lt;/p&gt;
&lt;h3&gt;
  
  
  ❌ Approach 1: Monkey Patch &lt;code&gt;requests&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Idea: Patch the &lt;code&gt;requests&lt;/code&gt; module to log every call.
&lt;/li&gt;
&lt;li&gt;Issue: Not all SDKs use &lt;code&gt;requests&lt;/code&gt;. Some use &lt;code&gt;httpx&lt;/code&gt;, &lt;code&gt;urllib3&lt;/code&gt;, or even custom HTTP clients.
&lt;/li&gt;
&lt;li&gt;Result: We only saw a subset of calls.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ❌ Approach 2: Use &lt;code&gt;httpretty&lt;/code&gt; or &lt;code&gt;wrapt&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Idea: Intercept calls by decorating functions dynamically.
&lt;/li&gt;
&lt;li&gt;Issue: Same limitation—only works if the library is using something we patched. Anything else bypassed this.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ❌ Approach 3: Logging Middleware
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Idea: Wrap the app with middleware that logs outbound traffic.
&lt;/li&gt;
&lt;li&gt;Issue: Works if we control the code making requests, but useless for opaque SDKs that bypass middleware.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ❌ Other Attempts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Packet capture tools like &lt;code&gt;tcpdump&lt;/code&gt; or &lt;code&gt;wireshark&lt;/code&gt;: noisy, low-level, and painful to parse.
&lt;/li&gt;
&lt;li&gt;Debugging proxies tied only to &lt;code&gt;requests&lt;/code&gt;: again, incomplete.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these gave us &lt;strong&gt;the full picture.&lt;/strong&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution: A Proxy for Everything
&lt;/h2&gt;

&lt;p&gt;The only reliable approach turned out to be:  &lt;/p&gt;

&lt;p&gt;➡️ &lt;strong&gt;Force all outbound calls to go through a proxy, and log everything at the proxy.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;We used &lt;a href="https://mitmproxy.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;mitmproxy&lt;/strong&gt;&lt;/a&gt;. It’s lightweight, easy to run, and gives a clean log of every outbound request.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Making Sure &lt;em&gt;All&lt;/em&gt; Calls Go Through the Proxy
&lt;/h3&gt;

&lt;p&gt;Specifying a proxy in just the &lt;code&gt;requests&lt;/code&gt; client wasn’t enough, because many SDKs bypass it. The trick was to use &lt;strong&gt;environment variables&lt;/strong&gt; that most HTTP clients respect by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://your-proxy:port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTPS_PROXY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://your-proxy:port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, &lt;code&gt;requests&lt;/code&gt;, &lt;code&gt;httpx&lt;/code&gt;, and many other libraries automatically route traffic through the proxy—without touching our code.&lt;/p&gt;

&lt;p&gt;Once we had mitmproxy logging everything, we finally got a &lt;strong&gt;complete list of domains&lt;/strong&gt; our backend was calling. ✅&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Frontend Calls?
&lt;/h2&gt;

&lt;p&gt;Backend calls are only half the story. The frontend may also directly hit third-party services—for example:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intercom (support chat)
&lt;/li&gt;
&lt;li&gt;Posthog / Clarity (analytics)
&lt;/li&gt;
&lt;li&gt;Sentry (error tracking)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do we capture these?  &lt;/p&gt;

&lt;p&gt;Super simple:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Chrome DevTools → Network tab.
&lt;/li&gt;
&lt;li&gt;Start recording.
&lt;/li&gt;
&lt;li&gt;Walk through all major pages and flows in the app.
&lt;/li&gt;
&lt;li&gt;Export the HAR file at the end.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That HAR file contains every outbound request the frontend made. We then parse it (with a quick script) to extract unique domains.  &lt;/p&gt;

&lt;p&gt;⚠️ The tricky part: making sure we triggered &lt;strong&gt;all&lt;/strong&gt; flows. One approach is to leave the recording on while using the app normally for a day, then export the file. That way we’re more likely to catch edge cases.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don’t assume you know what domains your app calls. SDKs are sneaky.
&lt;/li&gt;
&lt;li&gt;Manual inspection isn’t enough.
&lt;/li&gt;
&lt;li&gt;A proxy-based approach (e.g., mitmproxy + environment variables) gives you a complete picture for backend.
&lt;/li&gt;
&lt;li&gt;For frontend, HAR files from DevTools are the simplest solution.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re doing on-prem deployments with strict firewall rules, it’s worth setting this up early—before the customer is blocked and waiting on you for a whitelist.  &lt;/p&gt;

</description>
      <category>backend</category>
      <category>python</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>Mastering the Model Context Protocol (MCP): A Comprehensive Guide</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Mon, 01 Sep 2025 20:45:17 +0000</pubDate>
      <link>https://dev.to/gaw/mastering-the-model-context-protocol-mcp-a-comprehensive-guide-4m20</link>
      <guid>https://dev.to/gaw/mastering-the-model-context-protocol-mcp-a-comprehensive-guide-4m20</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This guide presents Model Context Protocol as a proposed standard for LLM-tool integration. While the concepts and architecture described are based on emerging patterns in AI tooling, specific implementations may vary across different platforms.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Large Language Models excel at understanding and generating text, but when it comes to executing real-world tasks—running tests, fetching data, or interacting with your systems—they need a bridge to your tools. The &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; provides exactly that bridge, offering a standardized way for LLMs to discover, understand, and safely interact with external resources and tools.&lt;/p&gt;

&lt;p&gt;This guide explores MCP's architecture, demonstrates practical implementations, and shows how to integrate MCP servers with modern development tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; is an open standard that enables secure, structured communication between LLMs and external systems. Rather than relying on ad-hoc integrations or hoping the LLM can parse documentation correctly, MCP provides machine-readable definitions of available capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   MCP Host  │────│ MCP Client  │────│ MCP Server  │
│    (LLM)    │    │ (Protocol)  │    │(Your Tools) │
└─────────────┘    └─────────────┘    └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The protocol defines three core components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP Host&lt;/strong&gt;: The application containing the LLM (like Claude Desktop)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Client&lt;/strong&gt;: Maintains connections to MCP servers and translates between the LLM and the protocol&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server&lt;/strong&gt;: Runs in your environment and exposes capabilities to the LLM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  MCP Capabilities
&lt;/h3&gt;

&lt;p&gt;MCP supports three types of capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Functions the LLM can call to perform actions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt;: Data sources the LLM can read from (files, APIs, databases)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt;: Pre-defined prompt templates with parameters&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How MCP Works
&lt;/h2&gt;

&lt;p&gt;Here's the typical interaction flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Discovery&lt;/strong&gt;: The MCP client connects to your MCP server via configuration and requests available capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema Exchange&lt;/strong&gt;: The server responds with JSON Schema definitions for tools, resources, and prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Request&lt;/strong&gt;: A user asks the LLM to perform a task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Selection&lt;/strong&gt;: The LLM analyzes available tools and selects the appropriate one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt;: The LLM calls the tool via the MCP client with structured parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response&lt;/strong&gt;: The MCP server executes the logic and returns structured results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt;: The LLM interprets the results and presents them to the user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach ensures tool invocation is &lt;strong&gt;predictable, secure, and maintainable&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Questions About MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Where does the actual tool logic reside?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The implementation lives entirely within your MCP server. The LLM simply makes standardized calls through the protocol—it never directly accesses your infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the MCP server run on my infrastructure?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. The server operates in your environment, maintaining full control over your data and systems. The LLM communicates only through the standardized MCP protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use schemas instead of documentation?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
While well-structured documentation can work for human developers, machine-readable schemas provide greater reliability and eliminate ambiguity. The LLM receives precise parameter types, constraints, and expected outputs, reducing errors and hallucinations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does this compare to providing examples and letting the LLM adapt?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example-based approaches can work but are fragile and inconsistent. MCP's schema-driven approach provides deterministic behavior, better error handling, and clearer boundaries for what the LLM can and cannot do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about security?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
MCP servers run in your controlled environment and you define exactly which capabilities to expose. The protocol supports authentication mechanisms like API keys and OAuth2, with role-based access control for fine-grained permissions.&lt;/p&gt;


&lt;h2&gt;
  
  
  Implementation Example: Building an MCP Server
&lt;/h2&gt;

&lt;p&gt;Here's a practical example using the Python SDK pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NotificationOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;InitializationOptions&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mcp.server.stdio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mcp.types&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize the MCP server
&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;development-tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@server.list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;List available tools&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run_test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Execute a test case against the system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inputSchema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unique identifier for the test to run&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;environment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;staging&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Target environment for the test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fetch_logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieve application logs for analysis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inputSchema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date-time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;debug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nd"&gt;@server.call_tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle tool execution with proper error handling&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# Validate arguments exist
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: No arguments provided for tool &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run_test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Validate required fields
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: Missing required field &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_id&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="n"&gt;test_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;environment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Execute test logic
&lt;/span&gt;            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;execute_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;test_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;test_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; completed in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; environment.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                         &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                         &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Duration: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                         &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Details: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fetch_logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Validate required fields
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: Missing required field &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Fetch logs logic
&lt;/span&gt;            &lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch_service_logs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; log entries for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
                         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# Show first 10 entries
&lt;/span&gt;                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: Unknown tool &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error executing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Implementation functions (replace with your actual logic)
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Placeholder test execution function.
    Replace with your actual test runner integration.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Mock implementation - replace with real test execution
&lt;/span&gt;    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
    &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All assertions successful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;850&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Assertion failed on line 42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_service_logs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Placeholder log fetching function.
    Replace with your actual logging system integration.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Mock implementation - replace with real log fetching
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Sample log entry 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Sample log entry 2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Sample log entry 3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Run the MCP server using stdio transport&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stdio_server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;InitializationOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;server_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;development-tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;server_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_capabilities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;notification_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;NotificationOptions&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="n"&gt;experimental_capabilities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step-By-Step Implementation Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Choose Your Technology Stack
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;: Use the MCP Python SDK for robust server development with async/await support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js&lt;/strong&gt;: The MCP TypeScript SDK provides comprehensive type safety and modern JavaScript features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;: Microsoft's official SDK enables .NET integration with MCP protocols.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Design Your Capabilities
&lt;/h3&gt;

&lt;p&gt;Define what your MCP server will expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt; for actions (running tests, deploying code, sending emails)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt; for data access (configuration files, database queries, API endpoints)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt; for reusable templates (code review prompts, documentation generators)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Implement Server Logic with Validation
&lt;/h3&gt;

&lt;p&gt;Each capability requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear name and description&lt;/li&gt;
&lt;li&gt;JSON Schema definitions for inputs and outputs&lt;/li&gt;
&lt;li&gt;The actual implementation logic&lt;/li&gt;
&lt;li&gt;Comprehensive error handling and input validation&lt;/li&gt;
&lt;li&gt;Appropriate security controls&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Configure Transport Mechanisms
&lt;/h3&gt;

&lt;p&gt;MCP supports multiple transport options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;stdio&lt;/strong&gt;: For local development and direct integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP&lt;/strong&gt;: For remote servers and web-based tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket&lt;/strong&gt;: For real-time, bidirectional communication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Register with MCP Clients
&lt;/h3&gt;

&lt;p&gt;Configure your MCP server in client tools using their specific configuration format. For example, in Claude Desktop's configuration file:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&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;"development-tools"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"path/to/your/mcp_server.py"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Test and Validate
&lt;/h3&gt;

&lt;p&gt;Before deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify schema validation works correctly&lt;/li&gt;
&lt;li&gt;Test error handling for edge cases&lt;/li&gt;
&lt;li&gt;Ensure security boundaries are properly enforced&lt;/li&gt;
&lt;li&gt;Validate performance under expected load&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Current MCP Ecosystem
&lt;/h2&gt;

&lt;p&gt;MCP adoption has grown across development tools, with several platforms providing native integration:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;MCP Support&lt;/th&gt;
&lt;th&gt;Configuration Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Desktop&lt;/td&gt;
&lt;td&gt;Full integration&lt;/td&gt;
&lt;td&gt;JSON config file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor AI&lt;/td&gt;
&lt;td&gt;Development workflows&lt;/td&gt;
&lt;td&gt;Extension settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VS Code Extensions&lt;/td&gt;
&lt;td&gt;Various implementations&lt;/td&gt;
&lt;td&gt;Extension-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom Implementations&lt;/td&gt;
&lt;td&gt;DIY integration&lt;/td&gt;
&lt;td&gt;Manual setup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Server Discovery&lt;/strong&gt;: MCP clients typically discover servers through configuration files that specify connection details, authentication, and transport methods. Some enterprise implementations use centralized registries for automatic server discovery across teams.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP Server Marketplace and Discovery
&lt;/h2&gt;

&lt;p&gt;The MCP ecosystem includes several discovery mechanisms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Official Directories:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Community-maintained registries of open-source MCP servers&lt;/li&gt;
&lt;li&gt;GitHub repositories tagged with &lt;code&gt;mcp-server&lt;/code&gt; for easy discovery&lt;/li&gt;
&lt;li&gt;Package registries (PyPI, npm) with MCP-specific categories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Enterprise Solutions:&lt;/strong&gt;&lt;br&gt;
Organizations build internal MCP server registries for sharing tools across teams while maintaining security and compliance requirements. These often integrate with existing service discovery infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Community Contributions:&lt;/strong&gt;&lt;br&gt;
The open-source community develops MCP servers for popular tools like Git, Docker, Kubernetes, AWS, and database systems, making them available through standard package managers.&lt;/p&gt;


&lt;h2&gt;
  
  
  MCP Vs. Alternative Approaches
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Traditional Documentation Approach:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Server provides: API documentation + examples
LLM parses: Unstructured text and examples
Result: Variable reliability depending on documentation quality
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MCP Protocol Approach:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Server provides: Machine-readable schemas + implementations
LLM receives: Structured definitions with clear contracts
Result: Reliable, predictable tool usage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While modern LLMs can effectively parse well-structured documentation, MCP's schemas provide greater reliability and consistency, especially for complex tool chains and enterprise environments where predictability is crucial.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices and Considerations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: Always run MCP servers in controlled environments with appropriate access controls. Use API keys or OAuth2 for authentication and implement role-based access control for fine-grained permissions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: Design tools to be responsive and provide progress feedback for long-running operations. Consider implementing timeouts and cancellation support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Provide clear, actionable error messages that help the LLM understand what went wrong and how to correct it. Always validate required inputs and handle edge cases gracefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: While MCP reduces the need for extensive documentation, clear descriptions in your schemas help LLMs make better tool selection decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production Considerations&lt;/strong&gt;: For production systems, implement proper logging, monitoring, and circuit breakers. Consider using a registry-based approach for tool discovery rather than hardcoded tool names.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started Today
&lt;/h2&gt;

&lt;p&gt;The concepts underlying MCP reflect emerging patterns in AI-tool integration. Here's how to begin exploring these approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose an SDK&lt;/strong&gt; that aligns with your preferred language and existing infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with a simple tool&lt;/strong&gt; that solves a specific problem in your workflow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with compatible platforms&lt;/strong&gt; to validate your implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement proper error handling&lt;/strong&gt; and security controls from the beginning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate and expand&lt;/strong&gt; based on what works well for your use cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document and share&lt;/strong&gt; your learnings with your team or the community&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;MCP-style protocols represent a significant step toward more reliable AI-tool integration. By providing standardized interfaces, they enable LLMs to work more effectively with existing systems while maintaining security and predictability.&lt;/p&gt;

&lt;p&gt;Whether you're building internal development tools or creating solutions for the broader community, structured protocols like MCP offer a robust foundation for AI-powered automation that scales with your needs. The key is starting with clear schemas, robust error handling, and a security-first mindset.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>llm</category>
      <category>ai</category>
    </item>
    <item>
      <title>What does the future of coding interviews look like in the age of LLMs?</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Mon, 01 Sep 2025 20:42:44 +0000</pubDate>
      <link>https://dev.to/gaw/what-does-the-future-of-coding-interviews-look-like-in-the-age-of-llms-4aji</link>
      <guid>https://dev.to/gaw/what-does-the-future-of-coding-interviews-look-like-in-the-age-of-llms-4aji</guid>
      <description>&lt;p&gt;Since I started working in the software industry over 11 years ago, there's been one constant in technical hiring: the coding interview. Every company might tweak their process—some add system design rounds, others throw in culture fit sessions—but the coding interview has been universal.&lt;/p&gt;

&lt;p&gt;That's changing fast.&lt;/p&gt;

&lt;p&gt;Now that you can generate nearly correct code in seconds using an LLM, the traditional coding interview has become both obsolete and trivial. This is especially obvious in remote settings where candidates can—and let's be honest, do—just ChatGPT their way through problems.&lt;/p&gt;

&lt;p&gt;But the problem runs deeper than just cheating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fundamental flaw that LLMs exposed
&lt;/h2&gt;

&lt;p&gt;Coding interviews were always broken. We just didn't want to admit it.&lt;/p&gt;

&lt;p&gt;They weren't testing problem-solving skills. They were testing how well someone had memorized LeetCode problems. After all, interviewers weren't creating original algorithmic challenges—they were pulling from the same pool of problems everyone else uses.&lt;/p&gt;

&lt;p&gt;At best, these interviews showed whether someone could convert thoughts into executable logic. But here's the thing: with LLMs handling that exact same task, what skill are we actually measuring?&lt;/p&gt;

&lt;p&gt;The bigger issue is that coding interviews were never good predictors of job performance. Real software engineering requires skills that a 45-minute algorithm session doesn't touch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding complex existing codebases&lt;/li&gt;
&lt;li&gt;Learning new technologies quickly
&lt;/li&gt;
&lt;li&gt;Actually finishing projects (not just starting them or fucking around halfway through)&lt;/li&gt;
&lt;li&gt;Making architectural decisions that won't bite you later&lt;/li&gt;
&lt;li&gt;Working effectively with other humans&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why LLMs killed coding interviews completely
&lt;/h2&gt;

&lt;p&gt;LLMs have exposed two fatal flaws in traditional coding interviews:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remote interviews are pointless.&lt;/strong&gt; There's no reliable way to prevent AI usage, and frankly, why would you want to? You can be almost 100% sure candidates are just going to ChatGPT it anyway—can't really blame them. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In-person interviews test the wrong skills.&lt;/strong&gt; Even if you force candidates into a conference room, you're asking them to manually code solutions they'd use AI for on the actual job.&lt;/p&gt;

&lt;p&gt;You could insist on whiteboarding, but then you're testing penmanship and memorization in an era where the job requires AI collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious solution nobody wants to admit
&lt;/h2&gt;

&lt;p&gt;Instead of viewing LLMs as the death of technical assessment, they're actually the best thing that happened to hiring.&lt;/p&gt;

&lt;p&gt;Here's why: a software engineer's job is to engineer software. We only settled for coding interviews because you couldn't build real projects in interview timeframes. Coding interviews were a proxy for the actual work—building complete systems.&lt;/p&gt;

&lt;p&gt;With LLMs, that constraint is gone. You can now build a working project in hours.&lt;/p&gt;

&lt;p&gt;So why use a proxy when you can test the real thing?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My proposal: Scrap coding interviews entirely. Give candidates a full project to complete, with the explicit expectation that they'll use AI tools.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What this actually looks like
&lt;/h2&gt;

&lt;p&gt;I'm not talking about take-home assignments that sit in someone's backlog for weeks. I'm talking about time-boxed project builds that mirror real work.&lt;/p&gt;

&lt;p&gt;And when I say "full project," I don't mean building the next Google Maps. I mean something focused but complete—like a simple blogging platform that takes markdown files and hosts them with switchable themes. Or better yet, let the candidate choose.&lt;/p&gt;

&lt;p&gt;There's a common product interview question: "What's your favorite product and how would you improve it?" You could adapt this for engineering: "Pick your favorite product and build a barebones version—a proof of concept."&lt;/p&gt;

&lt;p&gt;This approach is especially valuable for startups. Most early-stage work is rapid POC development. You need people who can build fast without overthinking and overengineering. This format reveals whether a candidate can make progress in ambiguous situations or if they'll get stuck internally debating which fucking datatype to use for a database column.&lt;/p&gt;

&lt;p&gt;Here's what changes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You see real engineering skills.&lt;/strong&gt; How do they set up their development environment? How do they structure code for maintainability? How do they handle dependencies, build systems, maybe even basic deployment? These are the messy realities of actual software work that coding interviews completely ignore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You evaluate AI collaboration.&lt;/strong&gt; Like it or not, we're not going back. Even if AI only improves productivity by 50%, that's a massive competitive advantage. You want to hire people who are exceptionally good at human-AI collaboration, not people who can solve tree traversal problems from memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You get system design for free.&lt;/strong&gt; A complete project forces architectural decisions. Which database? Why? How do you structure the code for extensibility? How do you handle error cases? These decisions reveal thinking that's impossible to assess in isolated coding problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this wasn't practical before (and why it is now)
&lt;/h2&gt;

&lt;p&gt;The old constraints were real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt;: Non-trivial projects needed weeks, not hours&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Candidate dropout&lt;/strong&gt;: Working professionals couldn't spend weekends building speculative projects
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interview throughput&lt;/strong&gt;: You could do multiple coding interviews per day, but not multiple project builds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LLMs changed the math. What used to take a week now takes hours.&lt;/p&gt;

&lt;p&gt;Plus, the time investment isn't actually worse than the current system. Most companies already put candidates through 4-5 coding rounds, and since remote interviews aren't practical anymore (thanks to AI cheating), these end up being in-person. &lt;/p&gt;

&lt;p&gt;Do the math: 5 hours of interviews plus 1-2 hours of travel time each way. If you're in Bangalore, make that 3+ hours in traffic. You're already looking at a full day commitment for the traditional process.&lt;/p&gt;

&lt;p&gt;A single project-based assessment that takes 4-6 hours? That's actually more efficient than the current marathon of multiple coding rounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm seeing in practice
&lt;/h2&gt;

&lt;p&gt;Some companies are already moving this direction, though most won't admit it publicly. The ones I've talked to report better hiring outcomes—fewer mismatches, better performance correlation, and candidates who actually understand what they're signing up for.&lt;/p&gt;

&lt;p&gt;The resistance isn't technical; it's cultural. We've been doing coding interviews for so long that they feel "rigorous" even when they're not predictive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The companies that adapt first win
&lt;/h2&gt;

&lt;p&gt;Traditional coding interviews are ending whether we acknowledge it or not. Candidates are already using AI in remote interviews. The choice isn't whether to allow AI—it's whether to design assessments that account for it.&lt;/p&gt;

&lt;p&gt;Companies that switch to project-based assessments will attract better candidates and make more accurate hiring decisions. Those clinging to LeetCode-style problems will find themselves testing memorization skills while missing the qualities that actually predict engineering success.&lt;/p&gt;

&lt;p&gt;The future of technical interviews isn't about fighting AI. It's about embracing it to create better, more realistic assessments of what engineering actually involves.&lt;/p&gt;

&lt;p&gt;This isn't just a trend—it's the new reality. The question is whether your hiring process will adapt or become irrelevant.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>interview</category>
      <category>llm</category>
      <category>coding</category>
    </item>
    <item>
      <title>How CAPTCHAs work - The Internet's Annoying but Essential Gatekeepers</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 19 Jun 2024 20:23:18 +0000</pubDate>
      <link>https://dev.to/gaw/how-captchas-work-the-internets-annoying-but-essential-gatekeepers-p4j</link>
      <guid>https://dev.to/gaw/how-captchas-work-the-internets-annoying-but-essential-gatekeepers-p4j</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9s55mqdb1xh6v5zej349.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9s55mqdb1xh6v5zej349.png" alt="Image description" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you live on the internet (which is practically everyone these days), you likely come across a CAPTCHA often - those somewhat irritating puzzles asking you to pick traffic lights to prove you’re not a robot. Have you ever wondered how these things work and why they’re needed? Let’s take a deep dive into it. (P.S. There's a bonus section containing bad CAPTCHA examples at the end).&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a CAPTCHA
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/CAPTCHA?ref=blog.kusho.ai"&gt;CAPTCHA&lt;/a&gt; (which stands for “Completely Automated Public Turing test to tell Computers and Humans Apart”) is a tool used by sites to identify whether an internet user is a human or a bot. &lt;/p&gt;

&lt;p&gt;Around 1997, AltaVista (a primitive search engine of that decade) was having a tough time fixing the high number of auto URL assets that were hampering its website ranking process severely. To solve this issue, the then-chief scientist of AltaVista, Andrei Broder, created an algorithm that later became famous as CAPTCHA.&lt;/p&gt;

&lt;p&gt;Because the test is administered by a computer, in contrast to the standard Turing test that is administered by a human, CAPTCHAs are sometimes described as &lt;a href="https://en.wikipedia.org/wiki/Reverse_Turing_test?ref=blog.kusho.ai"&gt;reverse Turing tests&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is CAPTCHA needed?
&lt;/h2&gt;

&lt;p&gt;Tl;dr - To make sure some sensitive resource is not exploited using bots&lt;/p&gt;

&lt;p&gt;CAPTCHAs are used by any website that wishes to restrict usage by bots. For instance, if you’re running a hotel reservation site, there’s a chance that someone might try to take all the bookings using a bot and legit customers will not be left with any slots. Or you might be running an online poll and want to make sure that votes are not manipulated using bots. CAPTCHA comes in handy in these scenarios making sure only human users can perform some actions blocking access to bot users. &lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;There are different types of CAPTCHAs available in the market these days, each a little different in its workings than the last one. But all of them work on the same principle - ask users to perform some actions that are trivial for a human to do but almost impossible to automate.&lt;/p&gt;

&lt;p&gt;Here are some common CAPTCHA flavours and how they work - &lt;/p&gt;

&lt;h2&gt;
  
  
  Classic CAPTCHA (Text-based CAPTCHA)
&lt;/h2&gt;

&lt;p&gt;These are the oldest variants of CAPTCHAs, as the name suggests. Classic CAPTCHAs work by asking a user to identify words. These words are shown in a distorted blurry manner with different fonts and handwriting which makes it very difficult for bots to identify them using OCR but it’s still trivial for human users to decipher.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06jy46cg0nw0a1vxz038.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06jy46cg0nw0a1vxz038.png" alt="Image description" width="620" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ReCAPTCHA
&lt;/h2&gt;

&lt;p&gt;Google came up with a new way to identify human users which doesn’t require users to enter anything. It just asks you to click on a checkbox.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zn6zs46vkv8ihs0cqgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zn6zs46vkv8ihs0cqgg.png" alt="Image description" width="620" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How can you figure out if a user is a human or a bot by just looking at a checkbox click, you may wonder. The answer is not in the click but in what happens before you click the checkbox. Google has a &lt;a href="https://security.googleblog.com/2014/12/are-you-robot-introducing-no-captcha.html?ref=blog.kusho.ai"&gt;risk analysis engine&lt;/a&gt; that looks at things like how the cursor moved on its way to the checkbox (organic random path/acceleration vs cursor moving in a straight line), which part of the checkbox was clicked (random places, or dead on center every time), browser fingerprint, Google cookies &amp;amp; contents, click location history tied to your fingerprint or account if it detects one, etc. to differentiate between organic and automated clicks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Image-recognition CAPTCHA
&lt;/h2&gt;

&lt;p&gt;For an image-recognition CAPTCHA, users are presented with square images of common objects like bikes, buses, traffic lights, etc. The images may all be from the same large image, or they may each be different. A user has to identify the images that contain certain objects. If their response matches the responses from most other users who have submitted the same test, the answer is considered "correct" and the user passes the test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90me0o3xnhoeveb85mbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90me0o3xnhoeveb85mbk.png" alt="Image description" width="618" height="1058"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: 5 examples of terrible CAPTCHAs that will make you pull out your hair
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             _You need a physics degree to solve CAPTCHAs now?_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcohzh5ddmykbuxf0k62e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcohzh5ddmykbuxf0k62e.png" alt="Image description" width="365" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         _Good luck deciphering this_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3v68cteo12pj38zzhd3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3v68cteo12pj38zzhd3q.png" alt="Image description" width="452" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    _If "you shall not pass" was an image_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F488fjb9v8kvkuovim1ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F488fjb9v8kvkuovim1ra.png" alt="Image description" width="738" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                 _Speechless_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                      _Maybe the robots should take over_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Simplify LLM Cost Tracking with Tokencost</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 19 Jun 2024 20:12:39 +0000</pubDate>
      <link>https://dev.to/gaw/simplify-llm-cost-tracking-with-tokencost-2cj6</link>
      <guid>https://dev.to/gaw/simplify-llm-cost-tracking-with-tokencost-2cj6</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg7p9nhjmemikuigg4ao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg7p9nhjmemikuigg4ao.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the popularity of Large Language Models (LLMs) grows, so does the need to accurately track and estimate the costs associated with using these powerful APIs. This is where &lt;a href="https://github.com/AgentOps-AI/tokencost?ref=blog.kusho.ai"&gt;Tokencost&lt;/a&gt; comes in - a Python library that simplifies the process of calculating the USD cost of prompts and completions for major LLM providers.&lt;/p&gt;

&lt;p&gt;today, and start shipping bug-free code faster!&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;LLM Price Tracking: Tokencost stays up-to-date with the latest pricing changes from major LLM providers, ensuring you always have accurate cost estimates.&lt;/li&gt;
&lt;li&gt;Token Counting: Accurately count the number of tokens in your prompts before sending requests to OpenAI, helping you optimize your usage and costs.&lt;/li&gt;
&lt;li&gt;Easy Integration: With just a single function call, you can get the cost of a prompt or completion, making it simple to incorporate Tokencost into your existing projects.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Install Tokencost via PyPI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install tokencost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cost Estimation
&lt;/h2&gt;

&lt;p&gt;Tokencost makes it easy to calculate the cost of prompts and completions from OpenAI requests. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from openai import OpenAI
from tokencost import calculate_prompt_cost, calculate_completion_cost

client = OpenAI()
model = "gpt-3.5-turbo"
prompt = [{ "role": "user", "content": "Say this is a test"}]

chat_completion = client.chat.completions.create(
    messages=prompt, model=model
)

completion = chat_completion.choices[0].message.content
prompt_cost = calculate_prompt_cost(prompt, model)
completion_cost = calculate_completion_cost(completion, model)
print(f"{prompt_cost} + {completion_cost} = {prompt_cost + completion_cost}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also calculate costs using string prompts instead of messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from tokencost import calculate_prompt_cost

prompt_string = "Hello world"
response = "How may I assist you today?"
model= "gpt-3.5-turbo"

prompt_cost = calculate_prompt_cost(prompt_string, model)
print(f"Cost: ${prompt_cost}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Token Counting
&lt;/h2&gt;

&lt;p&gt;In addition to cost estimation, Tokencost provides functions for counting tokens in both message lists and string prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from tokencost import count_message_tokens, count_string_tokens

message_prompt = [{ "role": "user", "content": "Hello world"}]
print(count_message_tokens(message_prompt, model="gpt-3.5-turbo"))

print(count_string_tokens(prompt="Hello world", model="gpt-3.5-turbo"))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to optimize your prompts and stay within the token limits of your chosen LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As LLMs continue to advance and find new applications, managing the costs associated with these powerful APIs becomes increasingly important. Tokencost simplifies this process, providing accurate cost estimates and token counting for major LLM providers.&lt;/p&gt;

&lt;p&gt;By integrating Tokencost into your projects, you can ensure that you're using LLMs efficiently and cost-effectively, helping you build better AI-powered applications without breaking the bank.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Generate assertions using AI</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 19 Jun 2024 19:58:45 +0000</pubDate>
      <link>https://dev.to/gaw/generate-assertions-using-ai-2bim</link>
      <guid>https://dev.to/gaw/generate-assertions-using-ai-2bim</guid>
      <description>&lt;p&gt;Assertions are like the rear-view mirrors of your testing process. They check whether specific conditions within the code are running as expected.&lt;/p&gt;

&lt;p&gt;Assertions testing is based on the use of assertion functions that we have productized for you. In a single click: you can check for accuracy, reliability, and performance!&lt;/p&gt;

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

&lt;p&gt;After you check the response to your request, directly generate assertions using AI! The best part? Absolutely no prompting is required from your end.&lt;/p&gt;

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

&lt;p&gt;If the assertions match, the test passes. You can be rest assured your code is ready for prod.&lt;/p&gt;

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

&lt;p&gt;If the assertions do not match, and the test fails, you get insight into the exact point and reason for failure. From here on, you can fix the code promptly.&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>Test more efficiently with GenAI</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 19 Jun 2024 19:56:17 +0000</pubDate>
      <link>https://dev.to/gaw/test-more-efficiently-with-genai-2g3k</link>
      <guid>https://dev.to/gaw/test-more-efficiently-with-genai-2g3k</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r92hegk96zbfvu1bwvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r92hegk96zbfvu1bwvf.png" alt="Image description" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run GenAI written tests for your entire codebase while you’re on a coffee break!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The era of shift left-testing arrived but our products did not change… At KushoAI, we’re bringing you a testing tool that will match pace with the dynamic shipping cycles of your team. &lt;/p&gt;

&lt;p&gt;You have to catch issues before they reach production and impact users but since testing is so time-consuming it’s often a bottleneck.&lt;/p&gt;

&lt;p&gt;Manual testing helps you debug specific problems but it’s painstakingly slow. AI-driven testing ensures you get consistent in-depth coverage and reduces human error. &lt;/p&gt;

&lt;p&gt;The best part? It’s lightning fast. Kusho looks at every scenario, writes your tests, and executes them instantly.&lt;/p&gt;

&lt;p&gt;In fact, KushoAI can auto-run relevant test suites at any stage of your CI/CD pipeline. A release that affects millions of customers? We’ve got you.&lt;/p&gt;

&lt;p&gt;You can run tests for a single API, group some APIs together, or run tens of APIs with a single click! Writing and executing tests usually take hours. Now you can do it in a matter of minutes.&lt;/p&gt;

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

&lt;p&gt;For every test, you get a request, response, assertions, and assertions results tab. You can generate assertions with GenAI and say goodbye to your testing woes forever.&lt;/p&gt;

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

&lt;p&gt;With assertion testing, detecting small and subtle errors that lead to notorious bugs is possible. When an assertion returns as false, it’s a warning system like in cars when the petrol must be re-fuelled, and your test fails.&lt;/p&gt;

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

&lt;p&gt;Now you know exactly where to intervene to ship pristine code in a &lt;br&gt;
matter of minutes.&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>Add API inputs in many easy ways</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 19 Jun 2024 19:52:40 +0000</pubDate>
      <link>https://dev.to/gaw/add-api-inputs-in-many-easy-ways-154</link>
      <guid>https://dev.to/gaw/add-api-inputs-in-many-easy-ways-154</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm01yfok1z2337q1gnre4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm01yfok1z2337q1gnre4.png" alt="Image description" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As developers, you deserve robust tools. We understand the laundry list of items you must get to and let’s not even get into the time spent in meetings.&lt;/p&gt;

&lt;p&gt;At Kusho, we’ve built a GenAI test automation product that adapts to the needs of your job, and can save you a couple of hours daily.&lt;/p&gt;

&lt;p&gt;Kusho solves your testing bottleneck by simulating test scenarios, running tests, validating them, and helping you discover bugs. The best part is that you can enter API details from your existing workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose whatever way suits you best:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Just enter API Details: you can manually enter your API details and provide basic details like HTTP method, the endpoint URL, headers, path params , query params etc. and let Kusho do the rest! &lt;/li&gt;
&lt;li&gt;Import OpenAPI specs: if you prefer breezy documentation and swear by OpenAPI specs, you can also easily import your collection.&lt;/li&gt;
&lt;li&gt;Import your existing Postman Collections: since you already spend so much time maintaining your Postman Collections, we ensure you can directly import them, and Kusho can generate on top of it. &lt;/li&gt;
&lt;li&gt;Copy/paste your cURL command: If you don’t want to switch out of your environment, you can create test suites by entering a cURL command.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the middle of a crazy workday and wish there was someone to help you test quickly and reliably? Test with Kusho and let us know if you have any feedback!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>On HumaneAI: should completely new tech products be judged by their promise or on their delivery?</title>
      <dc:creator>Sourabh  Gawande</dc:creator>
      <pubDate>Wed, 19 Jun 2024 19:46:43 +0000</pubDate>
      <link>https://dev.to/gaw/on-humaneai-should-completely-new-tech-products-be-judged-by-their-promise-or-on-their-delivery-4eng</link>
      <guid>https://dev.to/gaw/on-humaneai-should-completely-new-tech-products-be-judged-by-their-promise-or-on-their-delivery-4eng</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67en5imb424afgluqqhe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67en5imb424afgluqqhe.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m sure you’re following today’s main character on tech Twitter: HumaneAI.&lt;br&gt;
The TLDR is that there’s a new AI voice assistant device on the market. It’s multi-modal, wearable, and built with some pretty cool engineering. Think of it like computing on the go.&lt;/p&gt;

&lt;p&gt;It acts as a live voice search, shadows you on calls, can capture basic photos and video, etc. Plus, it can display a screen on your hand, in case you don’t want to talk out loud. &lt;/p&gt;

&lt;p&gt;The kicker: it costs $700 plus an additional subscription free. &lt;/p&gt;

&lt;p&gt;Many journalists, YouTubers, and tech enthusiasts have released their honest reviews of HumaneAI. The reviews are brutal and rely on comparing this new AI pin to our smartphones — that we all wished we used less of but only truly put away when we’re asleep.&lt;/p&gt;

&lt;p&gt;We can’t forget we have smartphones because we use them all the time. In fact, do you even remember all the big and small things you do on your phone daily? Furthermore, the computing power and affordability of smartphones make them the poster child of the global and digital economy.&lt;/p&gt;

&lt;p&gt;For any AI native hardware device to play in the same league, it needs access to rich data, it needs to be fast, and it needs to synthesize information in a way that feels like a step forward.&lt;/p&gt;

&lt;p&gt;And it somehow needs to do all of this on a different interface, OS, and on a device other than the one we carry around all the time.  &lt;/p&gt;

&lt;p&gt;It’s an admittedly hard problem to solve.&lt;/p&gt;

&lt;p&gt;You can’t limit the power of your software by trying to build it on top of older hardware, but at the same time, your newer hardware can’t be a container only for your AI native software. &lt;/p&gt;

&lt;p&gt;HumaneAI is attempting to build in uncharted territory. It’s a novel attempt. However, there is a clear gap between the current product and its ideal/ future self — the execution lags far behind the idea. &lt;/p&gt;

&lt;p&gt;As tech enthusiasts, should we support HumaneAI for bringing a new idea to the public, or should we be pragmatic consumers?  Is it our responsibility to offer an honest critique or are we killing an audacious idea before it has found its footing? &lt;/p&gt;

&lt;p&gt;What do you all think?&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
