<?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: Viram Choksi</title>
    <description>The latest articles on DEV Community by Viram Choksi (@viramchoksi).</description>
    <link>https://dev.to/viramchoksi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3849761%2Fa6669f11-accd-4b97-8eac-77dd8f166043.png</url>
      <title>DEV Community: Viram Choksi</title>
      <link>https://dev.to/viramchoksi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/viramchoksi"/>
    <language>en</language>
    <item>
      <title>The 7 Sneakiest Bugs That Slip Past 100% Test Coverage (And How to Spot Them)</title>
      <dc:creator>Viram Choksi</dc:creator>
      <pubDate>Fri, 30 Oct 2026 17:36:41 +0000</pubDate>
      <link>https://dev.to/viramchoksi/the-7-sneakiest-bugs-that-slip-past-100-test-coverage-and-how-to-spot-them-1h5g</link>
      <guid>https://dev.to/viramchoksi/the-7-sneakiest-bugs-that-slip-past-100-test-coverage-and-how-to-spot-them-1h5g</guid>
      <description>&lt;p&gt;We’ve all heard the myth: &lt;em&gt;"If the tests are green, the code is ready for production."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then at 11:30 PM on a Friday, an unhandled exception brings down the API. &lt;/p&gt;

&lt;p&gt;The truth is, automated tests test the code paths &lt;strong&gt;you remembered to write tests for&lt;/strong&gt;. But real-world code has sneaky language quirks, silent memory mutations, and edge cases that look 100% syntactically innocent until they meet real user data.&lt;/p&gt;

&lt;p&gt;Here are 7 of the sneakiest bugs in modern software development—and how to spot the pattern before your users do.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Reference Trap: &lt;code&gt;[[]] * 3&lt;/code&gt; in Python
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&lt;/strong&gt;&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="c1"&gt;# Create a 3x3 grid
&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[]]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bug&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="n"&gt;grid&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;What you expect:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[['bug'], [], []]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happens:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[['bug'], ['bug'], ['bug']]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
In Python, the &lt;code&gt;*&lt;/code&gt; operator on a list does not make deep copies. It creates three copies of the &lt;strong&gt;pointer to the exact same list in memory&lt;/strong&gt;. When you mutate &lt;code&gt;grid[0]&lt;/code&gt;, all three positions reflect the change because they are all referencing the exact same object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Use a list comprehension to create independent inner lists:&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="n"&gt;grid&lt;/span&gt; &lt;span class="o"&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;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. The Iterator Shift: Mutating an Array While Looping
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&lt;/strong&gt;&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="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&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;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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="n"&gt;nums&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;What you expect:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[]&lt;/code&gt; (An empty list)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happens:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[4, 8]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
Python’s loop maintains an internal index pointer. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On iteration 0, it removes &lt;code&gt;2&lt;/code&gt;. The list becomes &lt;code&gt;[4, 6, 8]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Now, index 0 is &lt;code&gt;4&lt;/code&gt;, and index 1 is &lt;code&gt;6&lt;/code&gt;!&lt;/li&gt;
&lt;li&gt;The loop advances to iteration 1, which reads index 1 (&lt;code&gt;6&lt;/code&gt;), skipping &lt;code&gt;4&lt;/code&gt; completely!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Iterate over a shallow copy (&lt;code&gt;nums[:]&lt;/code&gt;) or use a list comprehension:&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="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;should_remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. The &lt;code&gt;parseInt&lt;/code&gt; in &lt;code&gt;Array.prototype.map&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&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="nb"&gt;parseInt&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="nx"&gt;numbers&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;What you expect:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[10, 10, 10, 10]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happens:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[10, NaN, 2, 3]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Array.prototype.map&lt;/code&gt; passes three arguments to its callback: &lt;code&gt;(element, index, array)&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;code&gt;parseInt&lt;/code&gt; takes two arguments: &lt;code&gt;(string, radix)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So JavaScript actually executes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;parseInt("10", 0)&lt;/code&gt; -&amp;gt; Radix 0 defaults to decimal -&amp;gt; &lt;code&gt;10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parseInt("10", 1)&lt;/code&gt; -&amp;gt; Radix 1 is invalid -&amp;gt; &lt;code&gt;NaN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parseInt("10", 2)&lt;/code&gt; -&amp;gt; Radix 2 (binary &lt;code&gt;10&lt;/code&gt;) -&amp;gt; &lt;code&gt;2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parseInt("10", 3)&lt;/code&gt; -&amp;gt; Radix 3 (ternary &lt;code&gt;10&lt;/code&gt;) -&amp;gt; &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Pass an explicit arrow function:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&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;str&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&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;// Or simply:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&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="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. The Mutable Default Argument
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&lt;/strong&gt;&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;add_user_to_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;cache&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add_user_to_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&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="nf"&gt;add_user_to_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bob&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;&lt;strong&gt;What you expect:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;['Alice']&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;['Bob']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happens:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;['Alice']&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;['Alice', 'Bob']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
Python evaluates default function arguments &lt;strong&gt;once when the function is defined&lt;/strong&gt;, not every time it is called. That default &lt;code&gt;[]&lt;/code&gt; is stored in the function's &lt;code&gt;__defaults__&lt;/code&gt; tuple for the lifetime of the process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Use &lt;code&gt;None&lt;/code&gt; as a sentinel value:&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;add_user_to_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;=&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;if&lt;/span&gt; &lt;span class="n"&gt;cache&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="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;cache&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. JavaScript's Alphabetical &lt;code&gt;.sort()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&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="nx"&gt;scores&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;What you expect:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[1, 5, 12, 25, 100]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happens:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[1, 100, 12, 25, 5]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
By default, &lt;code&gt;.sort()&lt;/code&gt; converts all elements to strings and compares their UTF-16 code units. Because &lt;code&gt;"100"&lt;/code&gt; starts with &lt;code&gt;"1"&lt;/code&gt;, it comes before &lt;code&gt;"2"&lt;/code&gt;. Because &lt;code&gt;"25"&lt;/code&gt; starts with &lt;code&gt;"2"&lt;/code&gt;, it comes before &lt;code&gt;"5"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Always supply a comparator function for numeric sorting:&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;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. The &lt;code&gt;max()&lt;/code&gt; on an Empty Sequence
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&lt;/strong&gt;&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_highest_bid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bids&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;What happens in testing:&lt;/strong&gt;&lt;br&gt;
You test with &lt;code&gt;[100, 250, 40]&lt;/code&gt; -&amp;gt; Returns &lt;code&gt;250&lt;/code&gt;. Tests pass!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens in production:&lt;/strong&gt;&lt;br&gt;
A new auction opens with 0 bids. A user views the page.&lt;br&gt;&lt;br&gt;
Boom: &lt;code&gt;ValueError: max() arg is an empty sequence&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Provide the &lt;code&gt;default&lt;/code&gt; keyword argument:&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_highest_bid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. The Float Precision Trap
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Innocent Code:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;applyDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balance&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mf"&gt;0.3&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Special promo applied!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Regular rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2&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="nf"&gt;applyDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balance&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;What you expect:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;"Special promo applied!"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happens:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;"Regular rate"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
In IEEE 754 floating-point arithmetic (used by JS, Python, and most languages), &lt;code&gt;0.1 + 0.2&lt;/code&gt; equals &lt;code&gt;0.30000000000000004&lt;/code&gt;. Exact equality comparisons on calculated floats will silently fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
Compare within an epsilon:&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EPSILON&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Special promo applied!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  The Real Skill: Reading Broken Code
&lt;/h3&gt;

&lt;p&gt;Every coding platform and university course teaches you how to write code starting from line 1 of an empty file. &lt;/p&gt;

&lt;p&gt;Nobody teaches you how to read 300 lines of legacy code at midnight, spot the silent mutation, and fix it without breaking five other things.&lt;/p&gt;

&lt;p&gt;If you want to train your eye to spot these bugs in real time, check out &lt;strong&gt;&lt;a href="https://trybughunt.com" rel="noopener noreferrer"&gt;TryBugHunt&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;150+ interactive, real-world debugging challenges.&lt;/li&gt;
&lt;li&gt;You get the symptom and broken code—never the answer.&lt;/li&gt;
&lt;li&gt;Runs 100% client-side in your browser (powered by WebAssembly and Pyodide).&lt;/li&gt;
&lt;li&gt;Includes escalating hints and mental model explanations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's completely free and requires zero login to start solving: &lt;strong&gt;&lt;a href="https://trybughunt.com" rel="noopener noreferrer"&gt;trybughunt.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What’s the most innocent-looking bug that has ever taken down your production system? Share your war stories in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Nobody teaches you to debug</title>
      <dc:creator>Viram Choksi</dc:creator>
      <pubDate>Tue, 04 Aug 2026 18:42:49 +0000</pubDate>
      <link>https://dev.to/viramchoksi/nobody-teaches-you-to-debug-39om</link>
      <guid>https://dev.to/viramchoksi/nobody-teaches-you-to-debug-39om</guid>
      <description>&lt;p&gt;You've been here.&lt;/p&gt;

&lt;p&gt;The code looks right. It runs. The output is wrong.&lt;/p&gt;

&lt;p&gt;No error. No stack trace. Nothing to paste into Google. Just a number that should&lt;br&gt;
be 10 and is 4, and no idea where it went.&lt;/p&gt;


&lt;h2&gt;
  
  
  Three years of writing code, zero of fixing it
&lt;/h2&gt;

&lt;p&gt;Every assignment I was given was graded on writing something from scratch.&lt;/p&gt;

&lt;p&gt;Not one was graded on fixing something broken.&lt;/p&gt;

&lt;p&gt;Then you get to real work and it inverts completely. You spend far more time&lt;br&gt;
reading code you didn't write and finding out why it misbehaves than you ever&lt;br&gt;
spend on a blank file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We're trained for the rare case and left to improvise the common one.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Bugs aren't infinite. They're a handful of shapes
&lt;/h2&gt;

&lt;p&gt;This is the thing that changed how I think about it.&lt;/p&gt;

&lt;p&gt;Almost every bug is one of a small number of patterns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;the shape&lt;/th&gt;
&lt;th&gt;what you see&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🔁 Loop runs one time too many&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;IndexError&lt;/code&gt; on the last item&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0️⃣ A valid &lt;code&gt;0&lt;/code&gt; treated as missing&lt;/td&gt;
&lt;td&gt;Setting it to zero has no effect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔒 Closure captures the variable, not the value&lt;/td&gt;
&lt;td&gt;Every callback reports the last one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📋 A "copy" that's the same object&lt;/td&gt;
&lt;td&gt;Editing the copy changes the original&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once you can recognise the shape, you stop debugging line by line and start&lt;br&gt;
recognising. &lt;strong&gt;The next one takes minutes instead of an afternoon.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can't get that from reading. You get it from finding bugs, repeatedly, and&lt;br&gt;
being told what you just found.&lt;/p&gt;


&lt;h2&gt;
  
  
  So I built the practice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://trybughunt.vercel.app" rel="noopener noreferrer"&gt;BugHunt&lt;/a&gt; gives you working code with exactly one&lt;br&gt;
bug in it.&lt;/p&gt;

&lt;p&gt;You get the &lt;strong&gt;symptom&lt;/strong&gt;, not the cause:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;last_char("hello")&lt;/code&gt; raises &lt;code&gt;IndexError: string index out of range&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&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;last_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&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;text&lt;/span&gt;&lt;span class="p"&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;text&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;     &lt;span class="c1"&gt;# ← one character too far
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You find it. Fix it in the browser. Run it against the test cases.&lt;/p&gt;

&lt;p&gt;When it passes, you get an explanation of the &lt;strong&gt;pattern&lt;/strong&gt; — not just the diff.&lt;br&gt;
Knowing this loop needed &lt;code&gt;i + 1&lt;/code&gt; is nearly worthless. Recognising an off-by-one&lt;br&gt;
on sight is worth a lot.&lt;/p&gt;




&lt;h2&gt;
  
  
  A few things that matter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Nothing to install.&lt;/strong&gt; Python runs through WebAssembly right in the tab. Works on&lt;br&gt;
a locked-down college lab machine with no admin rights.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No account needed.&lt;/strong&gt; Solve a bug, read the explanation, close the tab. An account&lt;br&gt;
only saves your progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch it run.&lt;/strong&gt; Step through line by line and see every variable at every step.&lt;br&gt;
Seeing the exact moment a value goes wrong is very different from being told&lt;br&gt;
where the bug was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free.&lt;/strong&gt; No ads, no paywall. It runs on free hosting tiers on purpose — there's&lt;br&gt;
nothing to recoup, so there's no reason to start charging.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try one
&lt;/h2&gt;

&lt;p&gt;Pick a bug and see how long it takes you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://trybughunt.com" rel="noopener noreferrer"&gt;trybughunt.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an explanation is confusing, there's a report button on every challenge. I&lt;br&gt;
read them.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Four things that surprised me running Python in the browser</title>
      <dc:creator>Viram Choksi</dc:creator>
      <pubDate>Tue, 04 Aug 2026 18:31:20 +0000</pubDate>
      <link>https://dev.to/viramchoksi/four-things-that-surprised-me-running-python-in-the-browser-4lci</link>
      <guid>https://dev.to/viramchoksi/four-things-that-surprised-me-running-python-in-the-browser-4lci</guid>
      <description>&lt;p&gt;I built a debugging-practice site where student code runs &lt;strong&gt;entirely in the&lt;br&gt;
browser&lt;/strong&gt;. Python via &lt;a href="https://pyodide.org" rel="noopener noreferrer"&gt;Pyodide&lt;/a&gt;, JavaScript in a worker. No&lt;br&gt;
server executes anything.&lt;/p&gt;

&lt;p&gt;No execution bill, no queue, no sandbox to maintain. But four things bit me hard.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Your arguments aren't Python objects
&lt;/h2&gt;

&lt;p&gt;Pass a JS object into Python and you get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeError: 'pyodide.ffi.JsProxy' object is not subscriptable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not a &lt;code&gt;dict&lt;/code&gt;. It's a live view of the JS object, and it supports neither&lt;br&gt;
&lt;code&gt;obj[key]&lt;/code&gt; nor &lt;code&gt;.get()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Convert explicitly:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pyArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&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;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pyodide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;pyArgs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. &lt;code&gt;null&lt;/code&gt; is not &lt;code&gt;None&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This one passed my entire test suite while being broken in production.&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;pyodide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;check&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;type(v)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JsNull&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bool(v)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ falsy, as expected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v is None&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ the surprise&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It's falsy, so truthiness checks work fine. But &lt;code&gt;is None&lt;/code&gt; fails — which was&lt;br&gt;
exactly what my code was checking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why my tests missed it:&lt;/strong&gt; the harness used &lt;code&gt;json.loads&lt;/code&gt;. The app used &lt;code&gt;toPy&lt;/code&gt;.&lt;br&gt;
Different conversion paths, different answers.&lt;/p&gt;

&lt;p&gt;If you need a real &lt;code&gt;None&lt;/code&gt;, create it &lt;em&gt;in&lt;/em&gt; Python. Don't pass one across.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. &lt;code&gt;sys.settrace&lt;/code&gt; is a free step debugger
&lt;/h2&gt;

&lt;p&gt;Want to show users their code running line by line? Python basically hands it to you:&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;_tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&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;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;co_name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;                    &lt;span class="c1"&gt;# skip library frames
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;locals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_locals&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;_tracer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things this naive version gets wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add a step cap.&lt;/strong&gt; A tight loop generates steps faster than it burns a 5-second
timeout. You need both guards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle &lt;code&gt;exception&lt;/code&gt;.&lt;/strong&gt; During unwinding, the &lt;code&gt;return&lt;/code&gt; event still fires with
&lt;code&gt;arg=None&lt;/code&gt;. Miss it and your trace says "returned None" for code that crashed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Your snapshots are lying
&lt;/h2&gt;

&lt;p&gt;A user screenshot exposed this one.&lt;/p&gt;

&lt;p&gt;Every step in the trace showed the &lt;strong&gt;final&lt;/strong&gt; state of a list. Step 1 included&lt;br&gt;
mutations that hadn't happened yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  tracing:  nums = []; nums.append(1); nums.append(2)
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;- what the trace showed        + what actually happened
- step 1   nums = [1, 2]       + step 1   nums = []
- step 2   nums = [1, 2]       + step 2   nums = [1]
- step 3   nums = [1, 2]       + step 3   nums = [1, 2]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;frame.f_locals&lt;/code&gt; gives you &lt;strong&gt;references&lt;/strong&gt;. Snapshot a list and you've stored a&lt;br&gt;
pointer to something the program keeps mutating.&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="c1"&gt;# copy at capture time
&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Any time you snapshot mutable state over time, you're one reference away from&lt;br&gt;
a history that rewrites itself.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Worth it?
&lt;/h2&gt;

&lt;p&gt;Yes. Zero execution cost, scales infinitely, works on a locked-down lab machine&lt;br&gt;
with nothing installed.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;test against the real runtime.&lt;/strong&gt; Every bug above was found by running the&lt;br&gt;
actual thing — not by unit tests around it. The &lt;code&gt;JsNull&lt;/code&gt; one passed a fully green&lt;br&gt;
suite.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for &lt;a href="https://trybughunt.com" rel="noopener noreferrer"&gt;BugHunt&lt;/a&gt; — free debugging practice,&lt;br&gt;
runs in your browser, no account needed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webassembly</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why My Portfolio Has a Boot Sequence, Window Manager, and 6 Playable Games</title>
      <dc:creator>Viram Choksi</dc:creator>
      <pubDate>Sun, 29 Mar 2026 17:19:36 +0000</pubDate>
      <link>https://dev.to/viramchoksi/why-my-portfolio-has-a-boot-sequence-window-manager-and-6-playable-games-15j9</link>
      <guid>https://dev.to/viramchoksi/why-my-portfolio-has-a-boot-sequence-window-manager-and-6-playable-games-15j9</guid>
      <description>&lt;h1&gt;
  
  
  I Built a Full Operating System as My Developer Portfolio — Here's How
&lt;/h1&gt;

&lt;p&gt;Most developer portfolios look the same: a hero section, some cards, a contact form. I wanted mine to make recruiters stop scrolling.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;ViramOS&lt;/strong&gt; — a fully functional desktop operating system that runs in the browser. Boot sequence, login screen, draggable windows, taskbar, 13+ interactive apps, 6 playable games, and a working terminal. All built with Next.js, React, and Framer Motion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://viram-choksi.vercel.app" rel="noopener noreferrer"&gt;viram-choksi.vercel.app&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Does It Actually Do?
&lt;/h2&gt;

&lt;p&gt;When you visit my portfolio, you don't see a webpage. You see this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Boot Sequence&lt;/strong&gt; — Matrix rain, ASCII art, fake BIOS logs loading frameworks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login Screen&lt;/strong&gt; — Glassmorphic card with animated gradient ring, press Enter to unlock&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desktop&lt;/strong&gt; — Animated wallpapers, floating particles, draggable app icons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Window Manager&lt;/strong&gt; — Drag, resize, minimize, maximize, snap-to-edge (like Windows 11)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Taskbar&lt;/strong&gt; — Running app indicators, system tray, control center, clock&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And then 13+ apps you can actually use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal&lt;/strong&gt; with 15+ commands (&lt;code&gt;whoami&lt;/code&gt;, &lt;code&gt;neofetch&lt;/code&gt;, &lt;code&gt;benchmark&lt;/code&gt;, &lt;code&gt;architecture&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Projects&lt;/strong&gt; file manager with metrics and impact numbers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; package manager with proficiency bars&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Games&lt;/strong&gt; — Snake, 2048, Tic Tac Toe (with minimax AI), Typing Test, Memory Card, Reaction Time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Monitor&lt;/strong&gt; — Real-time FPS, Core Web Vitals, bundle size breakdown, architecture decision records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings&lt;/strong&gt; — 12 wallpapers, accent colors, font scaling, night shift, high contrast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Palette&lt;/strong&gt; — Press &lt;code&gt;/&lt;/code&gt; to fuzzy-search and launch any app&lt;/li&gt;
&lt;/ul&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Next.js 16 (App Router, SSR, ISR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;React 19, Framer Motion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;Tailwind CSS 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3D&lt;/td&gt;
&lt;td&gt;Three.js + React Three Fiber&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;React Context (no Redux needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Nodemailer via API route&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analytics&lt;/td&gt;
&lt;td&gt;Vercel Analytics + Speed Insights&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deploy&lt;/td&gt;
&lt;td&gt;Vercel (Edge Network)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Architecture Decisions That Matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why React Context over Redux?
&lt;/h3&gt;

&lt;p&gt;The OS state (open windows, settings, theme) is shared across components but updates infrequently — user clicks, not real-time data. Context + &lt;code&gt;useCallback&lt;/code&gt;/&lt;code&gt;useMemo&lt;/code&gt; keeps the bundle smaller and API simpler. Redux would add ~12KB gzipped for state that changes maybe 5 times per session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why DOM Windows, Not Canvas?
&lt;/h3&gt;

&lt;p&gt;I considered building the window manager on Canvas (like Figma does). But DOM-based windows mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native text selection inside windows&lt;/li&gt;
&lt;li&gt;Form inputs work naturally&lt;/li&gt;
&lt;li&gt;Screen readers can access content&lt;/li&gt;
&lt;li&gt;Standard React component composition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Canvas would give better performance at 50+ simultaneous windows, but a portfolio never has more than 5 open.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Framer Motion over CSS Animations?
&lt;/h3&gt;

&lt;p&gt;The boot sequence, window transitions, and desktop effects need &lt;strong&gt;orchestrated animations with exit transitions&lt;/strong&gt;. CSS can't do &lt;code&gt;AnimatePresence&lt;/code&gt; — you can't animate an element leaving the DOM. Framer Motion costs ~45KB gzipped but enables spring physics, gesture-based drag, and coordinated mount/unmount animations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Window Snap Zones
&lt;/h3&gt;

&lt;p&gt;I implemented Windows 11-style snap zones: drag a window to the left edge and it snaps to the left half, right edge for right half, top for maximize. The snap preview shows a translucent overlay while dragging near edges. Dragging a snapped window out restores it to its original size.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getSnapZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vw&lt;/span&gt; &lt;span class="o"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;top&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// maximize&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;clientX&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// left half&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;clientX&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;vw&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// right half&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;h3&gt;
  
  
  Settings Persistence
&lt;/h3&gt;

&lt;p&gt;All user preferences (wallpaper, accent color, font size, night shift) persist to &lt;code&gt;localStorage&lt;/code&gt;. The trick with Next.js SSR: you can't read &lt;code&gt;localStorage&lt;/code&gt; during server render or you get hydration mismatches. So I start with defaults, then restore from &lt;code&gt;localStorage&lt;/code&gt; in a &lt;code&gt;useEffect&lt;/code&gt; after mount.&lt;/p&gt;




&lt;h2&gt;
  
  
  SEO for a JavaScript-Heavy Portfolio
&lt;/h2&gt;

&lt;p&gt;The biggest SEO challenge: the homepage is entirely JS-rendered. Google can crawl dynamic content, but it takes extra time. My approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sr-only&lt;/code&gt; content&lt;/strong&gt; — Full text resume hidden but crawlable (same content as the interactive apps)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; fallback&lt;/strong&gt; — Visible content for JS-disabled users and crawlers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;11 static landing pages&lt;/strong&gt; — &lt;code&gt;/frontend-developer-ahmedabad&lt;/code&gt;, &lt;code&gt;/react-developer-ahmedabad&lt;/code&gt;, etc. with visible content, FAQ schema, and breadcrumbs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON-LD structured data&lt;/strong&gt; — 7 schemas: Person, FAQPage, WebSite, ProfessionalService, ItemList, LocalBusiness, Organization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic sitemap&lt;/strong&gt; with proper priorities and dates&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Accessibility in an OS Simulation
&lt;/h2&gt;

&lt;p&gt;Building an accessible OS simulation sounds contradictory, but I took it seriously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt;&lt;/strong&gt; — All CSS animations respect the user preference&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;role="application"&lt;/code&gt;&lt;/strong&gt; on the desktop, &lt;code&gt;role="dialog"&lt;/code&gt; on windows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skip link&lt;/strong&gt; — Tab-accessible "Skip to desktop" link&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard navigation&lt;/strong&gt; — Tab through desktop icons, Enter/Space to open apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;aria-label&lt;/code&gt;&lt;/strong&gt; on all interactive elements (window controls, taskbar, context menu)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus indicators&lt;/strong&gt; — Visible &lt;code&gt;focus-visible&lt;/code&gt; rings on all buttons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic HTML&lt;/strong&gt; — &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; everywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WCAG compliance in my day job went from 40% to 95%. I applied the same thinking here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Despite the visual complexity, the portfolio loads fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code splitting&lt;/strong&gt; — Each app component only loads when its window opens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutable cache headers&lt;/strong&gt; — 1-year cache for JS/CSS assets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive particles&lt;/strong&gt; — Fewer particles on mobile for 60fps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy window rendering&lt;/strong&gt; — Zero hidden DOM nodes for closed apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel Edge Network&lt;/strong&gt; — CDN distribution + SSR&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The OS metaphor forces you to solve real problems&lt;/strong&gt; — Window z-index management, focus trapping, state persistence, responsive layouts for different "screen sizes" inside windows. These are the same problems production apps face.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Constraints breed creativity&lt;/strong&gt; — A scrollable page is easy. An interactive desktop with overlapping windows, a taskbar, and 13 apps forces you to think about layout, performance, and UX simultaneously.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recruiters spend 15-30 seconds&lt;/strong&gt; — If they don't instantly see something interesting, they leave. The boot sequence animation buys you 5 seconds of attention. The desktop experience keeps them exploring.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://viram-choksi.vercel.app" rel="noopener noreferrer"&gt;viram-choksi.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the Terminal and type &lt;code&gt;help&lt;/code&gt;. Try &lt;code&gt;/&lt;/code&gt; to open the Command Palette. Play Snake. Change the wallpaper in Settings. Drag a window to the edge and watch it snap.&lt;/p&gt;

&lt;p&gt;If you're building your own portfolio, steal the architecture — just don't copy the design. The world needs more creative portfolios and fewer Bootstrap templates.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Viram Choksi, a Frontend Engineer in Ahmedabad, India. I build with React.js, Next.js, Vue.js, and TypeScript. Currently at Motadata, previously at MindInventory. Say hi at &lt;a href="mailto:viramchoksi77166@gmail.com"&gt;viramchoksi77166@gmail.com&lt;/a&gt; or find me on &lt;a href="https://www.linkedin.com/in/viram-choksi" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; #webdev #javascript #react #portfolio #nextjs #frontend #career&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>portfolio</category>
    </item>
  </channel>
</rss>
