<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Async Thinking]]></title><description><![CDATA[Demystifying the world of software engineering—from debugging to design—one post at a time.]]></description><link>https://asyncthinking.com</link><image><url>https://substackcdn.com/image/fetch/$s_!_Wek!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8d036f5-56c2-47cd-84dd-9e2768ba4084_1024x1024.png</url><title>Async Thinking</title><link>https://asyncthinking.com</link></image><generator>Substack</generator><lastBuildDate>Thu, 16 Apr 2026 20:22:17 GMT</lastBuildDate><atom:link href="https://asyncthinking.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Naresh Sharma]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[asyncthinking@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[asyncthinking@substack.com]]></itunes:email><itunes:name><![CDATA[Naresh Sharma]]></itunes:name></itunes:owner><itunes:author><![CDATA[Naresh Sharma]]></itunes:author><googleplay:owner><![CDATA[asyncthinking@substack.com]]></googleplay:owner><googleplay:email><![CDATA[asyncthinking@substack.com]]></googleplay:email><googleplay:author><![CDATA[Naresh Sharma]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[How GPT Reads Your Words (And Why It Can’t Count Letters)]]></title><description><![CDATA[Part of the MiniGPT series: Learn by Building]]></description><link>https://asyncthinking.com/p/how-gpt-reads-your-words-and-why</link><guid isPermaLink="false">https://asyncthinking.com/p/how-gpt-reads-your-words-and-why</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Tue, 25 Nov 2025 05:45:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b8eee9ed-0cf5-4a81-bd95-2a30fa0ea853_2372x1318.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://github.com/naresh-sharma/mini-gpt">GitHub Repo</a> &#8226; <a href="https://colab.research.google.com/github/naresh-sharma/mini-gpt/blob/main/notebooks/part1_tokenization.ipynb">Open in Colab</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AzVD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AzVD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 424w, https://substackcdn.com/image/fetch/$s_!AzVD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 848w, https://substackcdn.com/image/fetch/$s_!AzVD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 1272w, https://substackcdn.com/image/fetch/$s_!AzVD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AzVD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png" width="1456" height="809" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:906103,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/178056647?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AzVD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 424w, https://substackcdn.com/image/fetch/$s_!AzVD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 848w, https://substackcdn.com/image/fetch/$s_!AzVD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 1272w, https://substackcdn.com/image/fetch/$s_!AzVD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa23c3969-138e-437d-aebd-b930e82753f2_2372x1318.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>TL;DR</h2><p>GPT doesn&#8217;t see letters; it sees tokens (subword chunks). &#8220;strawberry&#8221; becomes <code>[&#8221;straw&#8221;, &#8220;berry&#8221;]</code>, which is why counting R&#8217;s is hard. This single design choice explains mysterious behaviours, API costs, and why your prompts sometimes get truncated. Understanding tokens is now as fundamental as understanding databases for anyone building with LLMs.</p><div><hr></div><p>You type:</p><blockquote><p>&#8220;How many R&#8217;s are in strawberry?&#8221;</p></blockquote><p>Early versions of ChatGPT would often reply:</p><blockquote><p>&#8220;There are two R&#8217;s in strawberry.&#8221;</p></blockquote><p><strong>Wrong. There are three.</strong></p><p>Modern models like GPT-5 usually get this right. But they&#8217;re getting it right <em>despite</em> how they read text, not because of it.</p><p>When you type &#8220;strawberry,&#8221; the model does not see <code>s-t-r-a-w-b-e-r-r-y</code>. It sees two tokens, something like:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NSXl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NSXl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 424w, https://substackcdn.com/image/fetch/$s_!NSXl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 848w, https://substackcdn.com/image/fetch/$s_!NSXl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 1272w, https://substackcdn.com/image/fetch/$s_!NSXl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NSXl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png" width="1456" height="835" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:835,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:330659,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/178056647?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NSXl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 424w, https://substackcdn.com/image/fetch/$s_!NSXl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 848w, https://substackcdn.com/image/fetch/$s_!NSXl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 1272w, https://substackcdn.com/image/fetch/$s_!NSXl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214bc6a4-1ed2-411e-bf64-60cff16d1fef_1464x840.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>To count the R&#8217;s, the model has to work around its own representation. It needs to reason about spelling even though the architecture never promised it could see characters at all.</p><p>That single design choice, how text is chopped up into tokens, explains a lot of behaviour that feels mysterious:</p><ul><li><p>Why letter counting, reversing strings, and simple ciphers are surprisingly hard</p></li><li><p>Why API costs spike with certain kinds of content</p></li><li><p>Why does your prompt sometimes get silently truncated, and instructions vanish</p></li></ul><p>If you&#8217;re building production systems on top of LLMs, tokenization is not an academic detail. It&#8217;s the first place bugs and costs start to show up.</p><p>&#128161; <em>All the code you see here (and a lot more) is in the <a href="https://github.com/naresh-sharma/mini-gpt">MiniGPT repo</a> with Colab notebooks you can run yourself.</em></p><div><hr></div><h2>Why Understanding This Matters Right Now</h2><p>Three years ago, knowing how to call an API was enough. Today, understanding how LLMs work is becoming as fundamental as understanding databases or networking.</p><p>Here&#8217;s why this specific topic tokenization is worth your time.</p><h3>1. You&#8217;re Already Building With LLMs</h3><p>If you&#8217;re:</p><ul><li><p>Integrating ChatGPT in your product</p></li><li><p>Using GitHub Copilot</p></li><li><p>Indexing documents with embeddings</p></li></ul><p>...you&#8217;re already making architectural decisions around tokens, context windows, and costs.</p><p>One line of code that ignores token limits can:</p><ul><li><p>Truncate your prompt in production</p></li><li><p>Drop the most important part of a document</p></li><li><p>Double your bill without changing a single word of UI copy</p></li></ul><h3>2. The Abstraction Is Leaking</h3><p>The nice mental model of &#8220;I send text, I get text back&#8221; holds until:</p><ul><li><p>The model hallucinates after a small prompt change</p></li><li><p>A long prompt quietly stops following your last instruction</p></li><li><p>A user pastes some code, and your token counts explode</p></li></ul><p>At that point, &#8220;vibes-based&#8221; prompt engineering stops working. The people who understand tokens, attention, and probabilities are the ones who can actually debug and improve the system.</p><h3>3. The Market Has Moved</h3><p>&#8220;LLM experience&#8221; on a job description rarely means &#8220;can call the OpenAI API.&#8221;</p><p>It usually means:</p><ul><li><p>Can reason about context limits</p></li><li><p>Can estimate and control token costs</p></li><li><p>Can design systems that combine LLMs with traditional components</p></li></ul><p>You don&#8217;t need to become a research scientist. But you do need to know what&#8217;s really happening when you send a text to a model.</p><h3>4. It&#8217;s Much Less Scary Than It Looks</h3><p>You already know the ingredients:</p><ul><li><p>Strings</p></li><li><p>Arrays</p></li><li><p>Integers</p></li><li><p>Some probability</p></li></ul><p>We&#8217;re just going to put those pieces together in a way that explains what GPT is doing behind the scenes.</p><p>By the end of this series, when the next major model ships, you won&#8217;t just read the marketing page. You&#8217;ll look for:</p><ul><li><p>What tokenizer does it use</p></li><li><p>How large is the context window really in practice</p></li><li><p>Where the failure modes are going to show up</p></li></ul><div><hr></div><h2>The Core Insight: Tokens, Not Letters</h2><p>Here&#8217;s what you <em>think</em> happens when you send a text to GPT:</p><pre><code><code>&#8220;strawberry&#8221;
  &#8595;
[&#8217;s&#8217;, &#8216;t&#8217;, &#8216;r&#8217;, &#8216;a&#8217;, &#8216;w&#8217;, &#8216;b&#8217;, &#8216;e&#8217;, &#8216;r&#8217;, &#8216;r&#8217;, &#8216;y&#8217;]
</code></code></pre><p>Here&#8217;s what <em>actually</em> happens:</p><pre><code><code>&#8220;strawberry&#8221;
  &#8595; [Tokenizer]
[&#8221;straw&#8221;, &#8220;berry&#8221;]
  &#8595; [Token IDs]
[496, 15717]
</code></code></pre><p>GPT never sees letters. It only sees integers. Every model call is &#8220;take this sequence of integers and predict the next integer.&#8221;</p><p>That one detail explains a lot:</p><ul><li><p>Letter counting is not &#8220;free&#8221; like it is for humans</p></li><li><p>String reversal is hard without an explicit character-level tool</p></li><li><p>Small whitespace or punctuation changes can alter the meaning the model perceives</p></li></ul><div><hr></div><h2>What Is Tokenization?</h2><p>Tokenization is the step that turns text into something a neural network can work with.</p><p>Conceptually:</p><pre><code><code>Your sentence
    &#8595;
Tokenizer
    &#8595;
[Tokens]
    &#8595;
[Token IDs]
    &#8595;
Embeddings and transformer layers
</code></code></pre><p><strong>Example:</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n-kL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n-kL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 424w, https://substackcdn.com/image/fetch/$s_!n-kL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 848w, https://substackcdn.com/image/fetch/$s_!n-kL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 1272w, https://substackcdn.com/image/fetch/$s_!n-kL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n-kL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png" width="1456" height="873" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:873,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:567765,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/178056647?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!n-kL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 424w, https://substackcdn.com/image/fetch/$s_!n-kL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 848w, https://substackcdn.com/image/fetch/$s_!n-kL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 1272w, https://substackcdn.com/image/fetch/$s_!n-kL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfcf23e0-f08c-46be-943a-d8440dc88ab6_1998x1198.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Everything that looks &#8220;smart&#8221; later is built on top of this representation.</p><div><hr></div><h2>Why Not Just Use Characters?</h2><p>The obvious question is: why not just give the model one token per character and be done with it?</p><h3>Character-Level</h3><pre><code><code>&#8220;Hello world&#8221;
&#8594; [&#8221;H&#8221;, &#8220;e&#8221;, &#8220;l&#8221;, &#8220;l&#8221;, &#8220;o&#8221;, &#8220; &#8220;, &#8220;w&#8221;, &#8220;o&#8221;, &#8220;r&#8221;, &#8220;l&#8221;, &#8220;d&#8221;]
&#8594; 11 tokens
</code></code></pre><p><strong>Pros:</strong></p><ul><li><p>Simple</p></li><li><p>Fixed vocabulary (roughly 256-byte values)</p></li><li><p>Never out-of-vocabulary</p></li></ul><p><strong>Cons:</strong></p><ul><li><p>5-10&#215; more tokens for the same text</p></li><li><p>Smaller effective context window</p></li><li><p>The model has to learn everything from scratch at the character layer</p></li></ul><h3>Word-Level</h3><pre><code><code>&#8220;Hello world&#8221;
&#8594; [&#8221;Hello&#8221;, &#8220;world&#8221;]
&#8594; 2 tokens
</code></code></pre><p><strong>Pros:</strong></p><ul><li><p>Intuitive</p></li><li><p>Each token has a clear meaning</p></li></ul><p><strong>Cons:</strong></p><ul><li><p>Vocabulary explodes into the millions</p></li><li><p>Fails on new words, typos, usernames, weird formatting</p></li></ul><h3>Subword-Level (What GPT Uses)</h3><p>Subword tokenization aims for a balance:</p><ul><li><p>Common words become single tokens</p></li><li><p>Rare words are split into smaller pieces</p></li><li><p>Everything can still be represented</p></li></ul><pre><code><code>&#8220;ChatGPT&#8221;          &#8594; [&#8221;Chat&#8221;, &#8220;GPT&#8221;]
&#8220;unbelievableness&#8221; &#8594; [&#8221;un&#8221;, &#8220;believ&#8221;, &#8220;able&#8221;, &#8220;ness&#8221;]
&#8220;strawberry&#8221;       &#8594; [&#8221;straw&#8221;, &#8220;berry&#8221;]</code></code></pre><p>This choice is what makes models like GPT feasible in the first place.</p><div><hr></div><h2>How Byte Pair Encoding (BPE) Works</h2><p>Modern GPT-style models use a variant of Byte Pair Encoding.</p><p>You don&#8217;t need to memorize the algorithm, but understanding the idea pays off.</p><h3>The Training Idea, In Plain Language</h3><ol><li><p>Start with individual bytes as your basic tokens</p></li><li><p>Look at a huge corpus of text</p></li><li><p>Find the most frequent pair of tokens that occur together</p></li><li><p>Merge that pair into a new token</p></li><li><p>Repeat until you have the desired vocabulary size</p></li></ol><p>Widespread patterns become tokens:</p><ul><li><p>&#8220;the&#8221;</p></li><li><p>&#8220;ing&#8221;</p></li><li><p>&#8220;ion&#8221;</p></li><li><p>&#8220; ChatGPT&#8221;</p></li></ul><p>Rare patterns stay as combinations of existing tokens or bytes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KPpx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KPpx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 424w, https://substackcdn.com/image/fetch/$s_!KPpx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 848w, https://substackcdn.com/image/fetch/$s_!KPpx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 1272w, https://substackcdn.com/image/fetch/$s_!KPpx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KPpx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png" width="1456" height="812" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:812,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:639404,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/178056647?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KPpx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 424w, https://substackcdn.com/image/fetch/$s_!KPpx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 848w, https://substackcdn.com/image/fetch/$s_!KPpx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 1272w, https://substackcdn.com/image/fetch/$s_!KPpx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc4ad0da-d326-44b7-b9db-58788c02257d_2336x1302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Why This Is Powerful</h3><p>BPE discovers structure without any linguistic rules. It will naturally learn:</p><ul><li><p>Suffixes like &#8220;ing&#8221;, &#8220;ness&#8221;, &#8220;tion&#8221;</p></li><li><p>Prefixes like &#8220;un&#8221;, &#8220;re&#8221;</p></li><li><p>Common code patterns like <code>def </code>, <code>import </code>, <code>return</code></p></li></ul><p>From the model&#8217;s point of view, tokens are just IDs. But the tokenizer has arranged things so that frequent, meaningful chunks have their own IDs.</p><div><hr></div><h2>A Tiny Longest-Match Tokenizer</h2><p>To make this concrete, here&#8217;s a tiny &#8220;toy&#8221; tokenizer that behaves a bit like a BPE tokenizer at runtime.</p><p>We won&#8217;t train anything here. We just assume a tiny vocab that already contains some subwords:</p><pre><code><code>def simple_tokenizer(text, vocab):
    &#8220;&#8221;&#8220;Greedy longest-match tokenizer.&#8221;&#8220;&#8221;
    tokens = []
    i = 0

    while i &lt; len(text):
        matched = False

        # Try longest possible substring first
        for length in range(len(text) - i, 0, -1):
            piece = text[i:i + length]
            if piece in vocab:
                tokens.append(vocab[piece])
                i += length
                matched = True
                break

        if not matched:
            # Unknown token
            tokens.append(vocab.get(&#8221;&lt;UNK&gt;&#8221;, 0))
            i += 1

    return tokens


# Our tiny vocabulary
vocab = {
    &#8220;Hello&#8221;: 101,
    &#8220; world&#8221;: 102,
    &#8220;!&#8221;: 103,
    &#8220;straw&#8221;: 201,
    &#8220;berry&#8221;: 202,
    &#8220;&lt;UNK&gt;&#8221;: 0,
}

print(simple_tokenizer(&#8221;Hello world!&#8221;, vocab))
# Output: [101, 102, 103]

print(simple_tokenizer(&#8221;strawberry&#8221;, vocab))
# Output: [201, 202]
</code></code></pre><p>The important part is the strategy: <strong>always take the longest matching piece</strong>. Real GPT tokenizers follow the same greedy idea, just with a much larger and more complex vocabulary.</p><p><em>The actual BPE training and a fuller tokenizer implementation live in the repo. You don&#8217;t need all of that in your head to benefit from understanding what it&#8217;s doing.</em></p><div><hr></div><h2>Real Tokenization With tiktoken</h2><p>Now, let&#8217;s look at how OpenAI&#8217;s tokenizer, <code>tiktoken</code>, sees the same text.</p><pre><code><code>import tiktoken

encoder = tiktoken.get_encoding(&#8221;gpt2&#8221;)  # close enough for examples

# Simple sentence
text = &#8220;Hello world!&#8221;
tokens = encoder.encode(text)

print(tokens)
# Output: [15496, 995, 0]

print([encoder.decode([t]) for t in tokens])
# Output: [&#8217;Hello&#8217;, &#8216; world&#8217;, &#8216;!&#8217;]

# The strawberry example
text = &#8220;strawberry&#8221;
tokens = encoder.encode(text)

print(tokens)
# Output: [41449, 19772]

print([encoder.decode([t]) for t in tokens])
# Output: [&#8217;straw&#8217;, &#8216;berry&#8217;]
</code></code></pre><p><strong>Key observations:</strong></p><ul><li><p>&#8220;Hello world!&#8221; is 3 tokens, not 12</p></li><li><p>&#8220;strawberry&#8221; is 2 tokens, even though it has 10 characters</p></li><li><p>&#8220;straw&#8221; and &#8220;berry&#8221; are meaningful chunks that the tokenizer discovered</p></li></ul><div><hr></div><h2>Spaces Matter More Than You Think</h2><p>One of the surprising details in GPT tokenizers is how they handle spaces.</p><pre><code><code>text1 = &#8220;hello&#8221;
text2 = &#8220; hello&#8221;

tokens1 = encoder.encode(text1)
tokens2 = encoder.encode(text2)

print(tokens1, [encoder.decode([t]) for t in tokens1])
print(tokens2, [encoder.decode([t]) for t in tokens2])
</code></code></pre><p>Typical output looks like:</p><pre><code><code>[31373] [&#8217;hello&#8217;]
[23748] [&#8217; hello&#8217;]
</code></code></pre><p>So:</p><ul><li><p><code>&#8220;hello&#8221;</code> is one token</p></li><li><p><code>&#8220; hello&#8221;</code> (with a leading space) is <em>also</em> one token</p></li><li><p><strong>But they are different tokens</strong></p></li></ul><p>The tokenizer encodes the space into the token itself. That&#8217;s why models usually generate <code>&#8220; world&#8221;</code> as one token instead of <code>&#8220; &#8220;</code> followed by <code>&#8220;world&#8221;</code>.</p><h3>This Has Implications</h3><ul><li><p>Adding or removing spaces changes the token sequence</p></li><li><p>Slightly different prompts can have different costs and behaviour, even if they look the same at a glance</p></li><li><p>When you&#8217;re debugging strange behaviour, whitespace can be part of the story</p></li></ul><div><hr></div><h2>Gotchas That Actually Bite You</h2><p>Once you know how tokens work, you start to see a few failure modes over and over.</p><h3>1. Token Counts Are Not Intuitive</h3><p>This kind of thing is common:</p><pre><code><code>examples = [
    &#8220;cat&#8221;,
    &#8220;cats&#8221;,
    &#8220;ChatGPT&#8221;,
    &#8220;GPT-4&#8221;,
]

for text in examples:
    tokens = encoder.encode(text)
    print(f&#8221;{text!r}: {len(tokens)} token(s)&#8221;)
</code></code></pre><p>You might get:</p><pre><code><code>&#8216;cat&#8217;: 1 token
&#8216;cats&#8217;: 1 token
&#8216;ChatGPT&#8217;: 2 tokens      # [&#8217;Chat&#8217;, &#8216;GPT&#8217;]
&#8216;GPT-4&#8217;: 3 tokens        # [&#8217;G&#8217;, &#8216;PT&#8217;, &#8216;-4&#8217;]
</code></code></pre><p>So a short string like &#8220;GPT-4&#8221; can be more expensive than it looks, especially when you&#8217;re dealing with a lot of IDs, symbols, or emojis.</p><p><strong>Why &#8220;GPT-4&#8221; becomes 3 tokens:</strong> The tokenizer sees &#8216;G&#8217; as rare enough to be separate, &#8216;PT&#8217; as a common chunk (from words like &#8220;ception&#8221;), and &#8216;-4&#8217; as a number with punctuation. This is why brand names and technical identifiers often tokenize unexpectedly.</p><h3>2. Token Limits Are Hard Limits</h3><p>Models have a fixed context size, expressed in tokens, not characters or words.</p><p>For example, if a model has an 8,192-token limit:</p><ul><li><p>You cannot send 8,193 tokens</p></li><li><p>Anything beyond the limit is effectively invisible to the model</p></li><li><p>In many APIs, the excess text is silently truncated from the end</p></li></ul><p>That&#8217;s how you get bugs like:</p><ul><li><p>&#8220;The model ignored the last instruction&#8221;</p></li><li><p>&#8220;The summary stops mid-sentence&#8221;</p></li><li><p>&#8220;Some sections of the document were not considered&#8221;</p></li></ul><p>The text is not being ignored on purpose. It simply never made it into the context window.</p><h3>3. Word-Count Heuristics Lie To You</h3><p>Rough mental rules like:</p><ul><li><p>&#8220;1 token &#8776; 4 characters&#8221;</p></li><li><p>&#8220;1 token &#8776; 0.75 words&#8221;</p></li></ul><p>...are fine for back-of-the-envelope estimates, but they&#8217;re not accurate enough for anything serious.</p><p><strong>The only reliable approach</strong> if you care about correctness or cost is:</p><pre><code><code>tokens = encoder.encode(text)
actual_count = len(tokens)
</code></code></pre><p>This is especially true for:</p><ul><li><p>Code</p></li><li><p>Mixed-language content</p></li><li><p>Emoji-heavy text</p></li><li><p>Anything with a lot of punctuation or math</p></li></ul><div><hr></div><h2>Token Efficiency Across Text Types</h2><p>Different kinds of text &#8220;compress&#8221; differently into tokens.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nFKu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nFKu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 424w, https://substackcdn.com/image/fetch/$s_!nFKu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 848w, https://substackcdn.com/image/fetch/$s_!nFKu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 1272w, https://substackcdn.com/image/fetch/$s_!nFKu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nFKu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png" width="1456" height="864" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:864,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:273297,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/178056647?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nFKu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 424w, https://substackcdn.com/image/fetch/$s_!nFKu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 848w, https://substackcdn.com/image/fetch/$s_!nFKu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 1272w, https://substackcdn.com/image/fetch/$s_!nFKu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a1ab436-d59a-4799-a96c-3105f81e0ef2_2304x1368.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In practice, you&#8217;ll see patterns like:</p><p>Content Type Typical Chars/Token Plain English prose 4-5, Code 2-3, Math notation, emoji, rare symbols 1-2</p><h3>The Practical Point</h3><ul><li><p>A 1,000-character essay might be ~230 tokens</p></li><li><p>A 1,000-character code snippet might be ~400 tokens</p></li></ul><p><strong>If your product sends a lot of code to an LLM, your token bill will not look like your character count.</strong></p><div><hr></div><h2>A Small Helper To Inspect Tokenization</h2><p>Here&#8217;s a short helper that you can drop into your own code to understand how a string is being tokenized.</p><pre><code><code>import tiktoken

encoder = tiktoken.get_encoding(&#8221;gpt2&#8221;)

def analyze(text: str) -&gt; None:
    &#8220;&#8221;&#8220;Analyze how text is tokenized.&#8221;&#8220;&#8221;
    tokens = encoder.encode(text)
    pieces = [encoder.decode([t]) for t in tokens]

    print(f&#8221;Text: {text!r}&#8221;)
    print(f&#8221;Characters: {len(text)}&#8221;)
    print(f&#8221;Tokens: {len(tokens)}&#8221;)
    if tokens:
        print(f&#8221;Chars per token: {len(text) / len(tokens):.2f}&#8221;)
    print(&#8221;\nToken breakdown:&#8221;)
    for i, (tid, piece) in enumerate(zip(tokens, pieces)):
        # Make whitespace visible
        visible = (
            piece
            .replace(&#8221; &#8220;, &#8220;&#9251;&#8221;)
            .replace(&#8221;\n&#8221;, &#8220;&#8629;&#8221;)
        )
        print(f&#8221;  {i:2d}. id={tid:5d} piece={visible!r}&#8221;)

# Try it out
analyze(&#8221;Hello world!&#8221;)
print()
analyze(&#8221;strawberry&#8221;)
</code></code></pre><p><strong>Output example:</strong></p><pre><code><code>Text: &#8216;Hello world!&#8217;
Characters: 12
Tokens: 3
Chars per token: 4.00

Token breakdown:
   0. id=15496 piece=&#8217;Hello&#8217;
   1. id=  995 piece=&#8217;&#9251;world&#8217;
   2. id=    0 piece=&#8217;!&#8217;
</code></code></pre><p>Use it to try:</p><ul><li><p>Your name</p></li><li><p>Your product name</p></li><li><p>A typical user prompt</p></li><li><p>A code snippet from your app</p></li></ul><p>You&#8217;ll very quickly build intuition for what&#8217;s cheap, what&#8217;s expensive, and where surprising splits happen.</p><p><em>All of this is built out more fully in the notebook, including nicer formatting and comparison helpers.</em></p><div><hr></div><h2>The Bigger Picture</h2><p>Tokenization is only the first step in the pipeline, but it sets the ground rules for everything that follows.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J7ph!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J7ph!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 424w, https://substackcdn.com/image/fetch/$s_!J7ph!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 848w, https://substackcdn.com/image/fetch/$s_!J7ph!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 1272w, https://substackcdn.com/image/fetch/$s_!J7ph!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J7ph!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png" width="1456" height="1027" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1027,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:330412,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/178056647?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J7ph!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 424w, https://substackcdn.com/image/fetch/$s_!J7ph!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 848w, https://substackcdn.com/image/fetch/$s_!J7ph!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 1272w, https://substackcdn.com/image/fetch/$s_!J7ph!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1be4910-4ed7-48fa-991c-a289734e49b7_2294x1618.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It:</p><ul><li><p>Defines what the model can see at once</p></li><li><p>Shapes how meaning is represented</p></li><li><p>Controls how much you pay</p></li><li><p>Introduces quiet failure modes if you ignore it</p></li></ul><p>Once text is tokenized, the model throws away the original character boundaries. From that point on, it&#8217;s all vectors and matrices.</p><p>Understanding this step makes the next step much easier to follow.</p><p><strong>In Part 2</strong> we&#8217;ll take those token IDs and turn them into embeddings: high-dimensional vectors that capture meaning in a way that allows the model to reason. That&#8217;s where analogies like <code>king - man + woman &#8776; queen</code> come from. We&#8217;ll build the embedding layer ourselves so you can see that this is not magic either.</p><div><hr></div><h2>What To Do With This As A Builder</h2><p>If you&#8217;re building with LLMs today, you can start applying this immediately:</p><ol><li><p><strong>Log token counts</strong> for your prompts and responses</p></li><li><p><strong>Add checks</strong> that truncate or summarize text before you hit model limits</p></li><li><p><strong>Run your own product prompts</strong> through a tokenization helper and look for surprises</p></li><li><p><strong>Refine prompt templates</strong> to reduce tokens without losing meaning</p></li></ol><p>You don&#8217;t need to obsess over every token, but you do need to know when tokens start to dominate your costs and your failure modes.</p><div><hr></div><p><strong>Repo:</strong> <a href="http://github.com/naresh-sharma/mini-gpt">github.com/naresh-sharma/mini-gpt</a><br><strong>Colab:</strong> <a href="https://colab.research.google.com/github/naresh-sharma/mini-gpt/blob/main/notebooks/part1_tokenization.ipynb">Tokenization notebook</a><br><strong>Discussion:</strong> <a href="https://github.com/naresh-sharma/mini-gpt/discussions">GitHub Discussions</a></p><div><hr></div><p><em>This is Part 1 of the MiniGPT series.</em></p><p>&#8594; <a href="https://asyncthinking.com/p/minigpt-learn-by-building">Series introduction</a></p>]]></content:encoded></item><item><title><![CDATA[Introducing MiniGPT: Learn How LLMs Work by Building One]]></title><description><![CDATA[A hands-on series: Build a GPT from scratch and finally understand how LLMs actually work]]></description><link>https://asyncthinking.com/p/minigpt-learn-by-building</link><guid isPermaLink="false">https://asyncthinking.com/p/minigpt-learn-by-building</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Wed, 29 Oct 2025 03:27:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ldnD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ldnD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ldnD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 424w, https://substackcdn.com/image/fetch/$s_!ldnD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 848w, https://substackcdn.com/image/fetch/$s_!ldnD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 1272w, https://substackcdn.com/image/fetch/$s_!ldnD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ldnD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png" width="1200" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45345,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/177434676?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ldnD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 424w, https://substackcdn.com/image/fetch/$s_!ldnD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 848w, https://substackcdn.com/image/fetch/$s_!ldnD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 1272w, https://substackcdn.com/image/fetch/$s_!ldnD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f919b7a-b331-4994-b640-fc87a0f32d22_1200x400.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p>Most developers use LLMs every day, but few understand how they actually work.<br>When prompts break or models hallucinate, we treat it like magic failing instead of software misbehaving.<br>This series changes that.</p><p><em>MiniGPT</em> is a hands-on guide to understanding language models by <strong>building one from scratch</strong>&#8212;small enough to grasp fully, real enough to work.</p><div><hr></div><h2>What You&#8217;ll Build</h2><p>By the end of this series, you&#8217;ll build a working <strong>MiniGPT</strong> that can:</p><ul><li><p>Process text and generate human-like responses</p></li><li><p>Understand context across multiple sentences</p></li><li><p>Learn patterns from training data</p></li><li><p>Predict the next word with surprising accuracy</p></li></ul><p>More importantly, you&#8217;ll understand:</p><ul><li><p>Why LLMs sometimes &#8220;hallucinate&#8221;</p></li><li><p>Why prompt engineering works (and when it doesn&#8217;t)</p></li><li><p>How to debug LLM behaviour in production</p></li><li><p>The real constraints and tradeoffs of these systems</p></li></ul><div><hr></div><h2>Who This Is For</h2><p><strong>This series is for you if:</strong></p><p>&#9989; You&#8217;re a developer who uses LLMs (ChatGPT API, Copilot, etc.)<br>&#9989; You want to understand how they actually work<br>&#9989; You&#8217;re comfortable with Python and basic math (matrix multiplication, probability)<br>&#9989; You learn best by building, not just reading</p><p><strong>This series is NOT for you if:</strong></p><p>&#10060; You want a quick &#8220;10 ChatGPT prompts&#8221; listicle<br>&#10060; You&#8217;re looking for cutting-edge research papers<br>&#10060; You want to use OpenAI&#8217;s API without understanding the internals</p><div><hr></div><h2>The Approach: Learn by Building</h2><p>Each post follows the same structure:</p><ol><li><p><strong>A real problem</strong> - Why does GPT behave this way?</p></li><li><p><strong>The concept</strong> - Clear explanation with visuals</p></li><li><p><strong>Build it</strong> - Working code you can run and modify</p></li><li><p><strong>Real-world implications</strong> - How this affects production systems</p></li></ol><p><strong>No hand-waving.</strong> If we use a concept, we implement it.<br><strong>No prerequisites beyond Python.</strong> I&#8217;ll explain the math as we go.<br><strong>No fluff.</strong> Every section moves you toward understanding.</p><div><hr></div><h2>The Roadmap</h2><h3>Part 1: Tokenization (This Week)</h3><p><em>Why GPT can&#8217;t count letters in &#8220;strawberry&#8221;</em></p><ul><li><p>How text becomes numbers</p></li><li><p>Build a simple tokenizer</p></li><li><p>Why token limits break your prompts</p></li></ul><h3>Part 2: Embeddings</h3><p><em>How &#8220;king - man + woman = queen&#8221; actually works</em></p><ul><li><p>Turning tokens into vectors</p></li><li><p>Semantic similarity</p></li><li><p>Building an embedding layer</p></li></ul><h3>Part 3: Attention Is All You Need</h3><p><em>The mechanism that changed everything</em></p><ul><li><p>Self-attention from scratch</p></li><li><p>Why transformers replaced LSTMs</p></li><li><p>Implementing multi-head attention</p></li></ul><h3>Part 4: The Transformer Architecture</h3><p><em>Putting all the pieces together</em></p><ul><li><p>Encoder-decoder structure</p></li><li><p>Positional encoding</p></li><li><p>Building a mini transformer</p></li></ul><h3>Part 5: Training and Generation</h3><p><em>Making it actually work</em></p><ul><li><p>Training on real text</p></li><li><p>Sampling strategies</p></li><li><p>Why temperature matters</p></li></ul><h3>Part 6: Fine-tuning and Prompt Engineering</h3><p><em>Making it useful</em></p><ul><li><p>Transfer learning</p></li><li><p>Prompt design</p></li><li><p>Production deployment patterns</p></li></ul><div><hr></div><h2>What You&#8217;ll Need</h2><ul><li><p><strong>Python 3.8+</strong> (we&#8217;ll use PyTorch, but I&#8217;ll explain every line)</p></li><li><p><strong>Basic linear algebra</strong> (don&#8217;t worry, I&#8217;ll review as we go)</p></li><li><p><strong>30-45 minutes per week</strong> (reading + coding exercises)</p></li><li><p><strong>Curiosity</strong> (most important)</p></li></ul><p>All code is available on <a href="https://github.com/naresh-sharma/mini-gpt">GitHub</a> with Colab notebooks you can run in your browser. No GPU required.</p><div><hr></div><h2>What Makes This Different</h2><p>There are plenty of transformer tutorials out there. Here&#8217;s what makes this one different:</p><p><strong>1. Production-focused</strong><br>Every concept connects to real problems you&#8217;ll face building LLM apps. Not just &#8220;here&#8217;s how attention works,&#8221; but &#8220;here&#8217;s why your context window fills up faster than expected.&#8221;</p><p><strong>2. Complete implementation</strong><br>We build everything from scratch. No mysterious library calls. When we use PyTorch, you&#8217;ll understand what it&#8217;s doing under the hood.</p><p><strong>3. Progressive complexity</strong><br>Each part builds on the last. By Part 3, you&#8217;ll be reading transformer papers and actually understanding them.</p><p><strong>4. Debuggable intuition</strong><br>The goal isn&#8217;t memorization, it&#8217;s developing intuition. When something breaks, you&#8217;ll know where to look and why.</p><div><hr></div><h2>The Philosophy</h2><p><strong>Understanding &gt; Completion</strong></p><p>I&#8217;d rather you deeply understand Parts 1-3 than skim through all 6. Each part is designed to give you a mental model you can build on.</p><p><strong>Build &gt; Read</strong></p><p>Every concept includes working code. Type it out. Break it. Fix it. That&#8217;s where understanding happens.</p><p><strong>Why &gt; How</strong></p><p>We don&#8217;t just implement&#8212;we explain the tradeoffs. Why BPE instead of character-level? Why self-attention instead of RNNs? Understanding the &#8220;why&#8221; makes you a better engineer.</p><div><hr></div><h2>Join Me</h2><p><strong>Part 1 drops in 3 days: &#8220;How GPT Reads Your Words (And Why It Can&#8217;t Count Letters)&#8221;</strong></p><p>We&#8217;ll start with the most fundamental question: How does GPT actually &#8220;read&#8221; your text?</p><p>Spoiler: It doesn&#8217;t see letters at all.</p><p><strong>Want to follow along?</strong></p><ul><li><p>&#11088; <a href="https://github.com/naresh-sharma/mini-gpt">Star the repo</a> on GitHub to get notified</p></li><li><p>&#128187; <a href="https://github.com/naresh-sharma/mini-gpt">Clone the code</a> to code along</p></li><li><p>&#128172; Join the <a href="https://github.com/naresh-sharma/mini-gpt/discussions">discussions</a> to ask questions</p></li><li><p>&#128279; Connect on <a href="https://www.linkedin.com/in/naresh-sharma-865b3b24/">LinkedIn</a> for updates</p></li></ul><p>The best way to learn is to build. Let&#8217;s build together.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Get Notified</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div><hr></div>]]></content:encoded></item><item><title><![CDATA[Context Engineering: The Skill That Will Outlast Prompt Engineering]]></title><description><![CDATA[The overlooked skill that makes AI useful in real workflows]]></description><link>https://asyncthinking.com/p/context-vs-prompt-engineering</link><guid isPermaLink="false">https://asyncthinking.com/p/context-vs-prompt-engineering</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Fri, 19 Sep 2025 16:04:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/31f8808f-fe9a-401a-a1d3-f52c644a7525_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most people think prompts are magic spells. Add the right words, and an AI model suddenly delivers gold. That works for quick tricks. However, when you attempt to utilize AI for actual work, clever prompts alone often fall short.</p><p>The reason is simple. Models don't read your mind. They only see the context you give them.</p><h2>Why Prompts Alone Don't Cut It</h2><p>Picture a developer asking: "Review this pull request."</p><p>The AI might comment on variable names or reformat a line, but it misses bigger issues like performance, security, or consistency with the team's style guide.</p><p>Now compare that to: "You are reviewing a pull request for our backend service. Apply our Python style guide, flag any security risks with user input, and check if the changes follow the existing logging pattern. Use short comments with examples of fixes."</p><p>The second request works because the developer supplied context: coding standards, priorities, and the style of feedback they expect. That context turns the AI into a helpful teammate instead of a noisy lint tool.</p><h2>What Context Really Means</h2><p>Context is the background you wrap around your prompt. It can be examples, rules, documents, or even the audience you're targeting. Without it, AI fills in the gaps with guesses. With it, you guide the output toward something useful.</p><p>Think about how a marketing team works. If you ask an AI, "Write ad copy for our new headphones," you'll get generic text. But if you load it with brand voice guidelines, customer personas, and past campaigns that performed well, you give it a frame to work inside. Now the output isn't just text. It's on-brand campaign material.</p><h2>What the Research Shows</h2><p>This isn't just opinion. Studies back it up.</p><p>A 2025 benchmark on software engineering prompts found that structured prompts with examples and constraints improved accuracy by 10 to 15 percentage points compared to vague requests.</p><p>"Prompting in the Wild" (2024) analyzed thousands of real prompts in open-source codebases. Most edits weren't clever rewrites. They were context fixes: adding missing constraints, clarifying output formats, or specifying the audience.</p><p>In short, people don't get better results by writing prettier prompts. They get them by engineering a better context.</p><h2>Trade-Offs You Can't Ignore</h2><p>Context is powerful, but it isn't free.</p><p><strong>Cost:</strong> More tokens mean higher API bills.</p><p><strong>Speed:</strong> Longer prompts increase response time.</p><p><strong>Confusion:</strong> Irrelevant or contradictory context makes answers worse, not better.</p><p>A practical guideline: keep context at no more than half your output budget. If you expect 800 tokens of output, aim for 300 to 400 tokens of context. Summarize where possible. Use bullet points instead of long paragraphs.</p><h2>Common Mistakes That Kill Results</h2><p>Here are traps I see people fall into:</p><p><strong>Dumping raw documents:</strong> Pasting a 10-page manual instead of a 200-word summary.</p><p><strong>Mixing tones:</strong> Asking for formal and casual output in the same prompt.</p><p><strong>Stale context:</strong> Forgetting to update rules or data, so the model follows outdated instructions.</p><p><strong>Over-constraining creativity:</strong> Loading creative tasks with so many rules, the output becomes robotic.</p><p><strong>Context that fights itself:</strong> Saying "be concise" then asking for "detailed explanations with examples."</p><p>Avoid these, and you'll save yourself a lot of frustration.</p><h2>How to Debug Bad Context</h2><p>Don't expect to nail it on the first try. Context design is messy. Here's how to make it work:</p><p>Start with your basic context: purpose, audience, constraints, and examples.</p><p>Run the same prompt on three to five different inputs.</p><p>When it fails, ask why. Did it ignore your constraints? Was the tone wrong? Did it add unnecessary fluff?</p><p>Here's what a real debugging session looks like:</p><p><strong>Try 1:</strong> "Write a product description for wireless earbuds." <strong>Result:</strong> Generic, boring copy.</p><p><strong>Try 2:</strong> "Write a 50-word product description for wireless earbuds targeting fitness enthusiasts." <strong>Result:</strong> Better, but sounds like every other fitness ad.</p><p><strong>Try 3:</strong> "Write a 50-word product description for wireless earbuds targeting runners who hate when their music cuts out mid-workout. Focus on reliability, not features." <strong>Result:</strong> Now you have something that speaks to real pain points.</p><p>Each revision added context that mattered. That's how you get from "interesting" to "ready to use."</p><h2>Beyond Technical Skills</h2><p>Context engineering isn't just about writing better prompts. The best practitioners understand psychology, domain expertise, and system design.</p><p><strong>Psychology matters</strong> because you need to know how people process information. A legal brief and a social media post need completely different context structures.</p><p><strong>Domain expertise matters</strong> because the context that works for code reviews won't work for medical diagnoses. Each field has its own standards, risks, and success metrics.</p><p><strong>System design matters</strong> because context flows through workflows. You need to think about how context gets updated, who maintains it, and what happens when requirements change.</p><p>The strongest context engineers I know aren't just technical. They're translators between different worlds.</p><h2>Different Industries, Different Needs</h2><p>Context isn't one-size-fits-all. The stakes and details vary:</p><p><strong>Legal:</strong> Precision and citations are non-negotiable. Context needs to include references to statutes or contracts. One wrong interpretation could cost millions.</p><p><strong>Medical:</strong> Patient history and safety disclaimers must be front and center. Output without them isn't just bad. It's dangerous.</p><p><strong>Creative work:</strong> Style guides, character notes, and pacing matter more than strict rules. Too much structure kills the magic.</p><p><strong>Customer service:</strong> Cultural context matters. A response that works for American directness might seem rude to customers who expect formal acknowledgment of hierarchy.</p><p>Think about what context actually matters in your field, and design for it.</p><h2>The Collaboration Factor</h2><p>Context design works best as a team sport. Engineers provide technical constraints. Domain experts supply business rules. End users reveal real-world edge cases that no one thought about.</p><p>I watched a team spend weeks perfecting prompts for a customer service bot. The context looked perfect on paper. Then real customers started using it, and everything broke. Turns out, angry customers don't follow the polite scripts the team had imagined.</p><p>The fix wasn't better prompts. It was a better context that accounted for emotional states, incomplete information, and the chaos of real human communication.</p><h2>Making It Stick</h2><p>If you want to get good at context engineering, practice on problems that matter to you. Don't just optimize toy examples. Pick a real workflow where AI could help, then iterate on the context until it actually works.</p><p>Track what breaks and why. Build a personal library of context patterns that work in your domain. Share what you learn with your team.</p><p>Most importantly, remember that a perfect context doesn't exist. Good context evolves with your needs, your users, and your understanding of the problem.</p><p>The goal isn't to write the perfect prompt once. It's to build systems that keep working as the world changes around them.</p><p>Prompts fade. Context endures.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Startup vs Big Tech: The Career Choice That Keeps You Up at Night]]></title><description><![CDATA[Why the right move depends on your risk horizon, not the hype.]]></description><link>https://asyncthinking.com/p/startup-vs-big-tech-guide</link><guid isPermaLink="false">https://asyncthinking.com/p/startup-vs-big-tech-guide</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Thu, 03 Jul 2025 02:49:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/744dcd6b-e565-4ecb-97fd-782626d962d5_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>That moment when you're staring at two job offers on your laptop screen at 10 PM, wondering if you should chase the Google paycheck or bet on the Series B startup that "could be the next Stripe."</em></p><p>I've been there. We've all been there.</p><p>With 150k tech jobs cut in 2024 and another 22k gone by mid-2025, choosing your next move feels less like career planning and more like navigating a minefield. But here's the thing&#8212;both paths can work. The trick is figuring out which one works for <em>you</em> at the moment.</p><p>Let me walk you through what I've learned after talking to dozens of engineers, PMs, and designers who've made this jump in both directions.</p><h2><strong>The Money Talk (Because Let's Be Real)</strong></h2><p>Nobody likes to admit it, but most of us check the salary first. And honestly? The gap is real.</p><p>At Big Tech, you're looking at median SWE salaries around $184k nationally, with Google hitting $301k. Meanwhile, startups typically pay 30-40% lower for comparable levels. Ouch.</p><p>But here's where it gets interesting&#8212;equity.</p><p>Those Google RSUs? They vest quarterly, and you can sell them immediately. It's basically salary with extra steps. Startup equity? That's your lottery ticket. You might own 0.5-2% of something that could 10x, but realistically, about 90% of options expire worthless or get diluted into oblivion.</p><p>I know someone who turned down a $400k Google offer for a Series A startup. Three years later, that startup got acquired, and his equity payout bought him a house in Palo Alto. I also know someone who did the same thing and ended up with options worth approximately $0.</p><p><strong>Bottom line:</strong> Treat RSUs like salary. Treat startup equity like a lottery ticket you can afford to lose.</p><h2>Growth Curve &amp; Skill Depth</h2><p>This is where things get nuanced, and honestly, where most people get it wrong.</p><p>At Big Tech, you're going deep. Really deep. You'll have formal design reviews, polished infrastructure, and domain specialists who've seen every edge case. If you want to understand how to squeeze latency from billion-request services, this is your playground.</p><p>At startups? It's "whatever ships by Friday." Last week you were designing the database schema, this week you're answering support tickets, next week you're in the room when they're pitching Series B investors.</p><p>My friend put it perfectly: <em>"At the 20-person startup, I went from backend engineer to acting CTO in 8 months because our technical lead quit. Terrifying? Yes. But I learned more about system architecture, hiring, and business strategy in that year than I did in three years at Microsoft."</em></p><p>But here's what most people miss: "startup" covers everything from 3 founders in a garage to 500-person companies preparing for IPO. The experience varies wildly:</p><p><strong>Pre-Seed/Seed (2-15 people):</strong> You're basically a founding team member. Expect to wear 6 different hats and have massive influence on product direction. The equity upside is highest, but so is the "will we survive the quarter?" anxiety.</p><p><strong>Series A/B (15-100 people):</strong> Still scrappy, but with actual product-market fit signals. You'll have a defined role but flexible boundaries. The learning curve is steep but structured.</p><p><strong>Series C+ (100+ people):</strong> These feel more like small Big Tech companies than startups. You'll have the scale challenges without the Big Tech compensation or stability.</p><p>Here's my rule: If you want to become the world's expert in ML infrastructure, lean Big Tech. If you want to understand how an entire business works&#8212;from code to customers to cash flow&#8212;lean early-stage startup.</p><h2><strong>The Brand Game (And Why It Still Matters)</strong></h2><p>Let's talk about something uncomfortable: prestige still opens doors.</p><p>A year at a FAANG company can 10x your recruiter response rates. It's a signal that cuts through resume noise and unlocks higher-level interviews everywhere else. It's not fair, but it's real.</p><p>Startups can build founder credibility, but that recognition is hit-or-miss outside entrepreneurial circles. Unless your startup becomes the next Airbnb, most people won't recognize the name.</p><p><strong>The smart play?</strong> Collect one strong brand stamp and one strong narrative. Like "first infrastructure engineer who scaled Series B app to 10M MAU." Either alone is helpful; together, they compound.</p><h2><strong>The 2025 Reality Check</strong></h2><p>Here's what nobody wants to talk about: "stable" is relative in 2025.</p><p>Those Big Tech layoffs hit cloud giants and scrappy startups alike. Google, Meta, Amazon&#8212;they all cut thousands. But so did hundreds of startups when VC funding tightened.</p><p>The difference? Big Tech layoffs come with severance packages and LinkedIn sympathy. Startup layoffs come with "we ran out of money" and worthless equity.</p><p>But here's the twist&#8212;Big Tech alumni networks are incredibly strong for landing. Startup alumni networks open doors to founding opportunities. Both have value, just different kinds.</p><h2><strong>The Lifestyle Reality</strong></h2><p>Startups mean stress spikes that align with fundraising cliffs and production fires. You'll get pinged at weird hours, context-switch constantly, and sometimes wonder if you're building something people actually want.</p><p>But there's also this weird camaraderie. When you're 12 people trying to figure out product-market fit, everyone's in it together. You'll know everyone's name, their kids' names, and probably their coffee order.</p><p>Big Tech means meeting load and process drag that can kill momentum. But mature on-call rotations mean your weekends are actually yours. The benefits are luxe, the cafeteria food is free, and burnout risk is genuinely lower.</p><p><strong>Pros/Cons at a glance:</strong></p><p><strong>Startup Life:</strong></p><ul><li><p>&#9989; Direct impact, fast decision-making, equity upside</p></li><li><p>&#10060; Long hours, resource constraints, survival risk</p></li></ul><p><strong>Big Tech Life:</strong></p><ul><li><p>&#9989; Great mentorship, work-life balance, predictable growth</p></li><li><p>&#10060; Bureaucracy, narrow ownership, golden handcuffs</p></li></ul><p>Choose the adrenaline cocktail that sustains you, not the one that drains you.</p><h2><strong>Your 4-Question Decision Framework</strong></h2><p>When I'm helping friends think through these choices, I ask them to walk through these questions:</p><ol><li><p><strong>What's Your Runway?</strong> Could you live on just the cash portion for 2 years? If not, you're gambling rent money on options.</p></li><li><p><strong>Where's Your Risk Tolerance?</strong> Mortgage? Visa applications? Kids? Your risk tolerance at 25 is different from 35. Be honest about what you can afford to lose.</p></li><li><p><strong>What's Your Learning Plateau?</strong> Haven't fought a new problem in six months? Prioritize the environment that stretches you, even if it's scary.</p></li><li><p><strong>What's Your 5-Year Vision?</strong> Write down the role, skills, and network you want by 2030. Which offer gets you there faster?</p></li></ol><h2><strong>Questions That Cut Through the BS</strong></h2><p>Before you sign anything, ask these:</p><p><strong>For startups:</strong> What's your current burn rate and runway? What happens to my equity if I leave before the next round? What's Plan B if fundraising fails?</p><p><strong>For Big Tech:</strong> What has this team shipped in the last 12 months? Can you share promotion stories from people who've worked under my prospective manager?</p><p>Transparency is a health indicator. If they're evasive, that's your red flag&#8212;regardless of the brand name.</p><div><hr></div><h2><strong>TL;DR</strong></h2><p><strong>If you're optimizing for:</strong> immediate cash, visa sponsorship, or deep specialization &#8594; <strong>Big Tech is probably your move.</strong></p><p><strong>If you want:</strong> end-to-end ownership, broad skills, and outsized upside potential &#8594; <strong>Startup life might be calling.</strong></p><p><strong>Want the best of both?</strong> Do Big Tech for 2-4 years until your savings and network are solid, then make the startup jump.</p><p><strong>The real truth:</strong> Both paths can lead to incredible careers. The "wrong" choice is staying somewhere that doesn't challenge you or align with where you want to be in five years.</p><div><hr></div><p></p>]]></content:encoded></item><item><title><![CDATA[5 Design Principles Every Engineer Should Master (With Interview Cheat Codes)]]></title><description><![CDATA[In daily coding and high-pressure interviews alike, having solid design instincts sets you apart.]]></description><link>https://asyncthinking.com/p/5-design-principles-engineers-must-master</link><guid isPermaLink="false">https://asyncthinking.com/p/5-design-principles-engineers-must-master</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Wed, 30 Apr 2025 03:24:57 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/bc7c0d13-4c46-4be9-a15d-eba3fba2584b_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In daily coding and high-pressure interviews alike, having solid design instincts sets you apart. Instead of just churning out code, the best engineers lean on time-tested principles to guide decisions. This newsletter spotlights five such design principles that sharpen your engineering judgment <em>and</em> give you cheat codes for interviews. Mastering these will not only make your code cleaner but also help you articulate trade-offs and impress interviewers when it counts.</p><h2>Single Responsibility Principle (SRP)</h2><p><strong>One job per component&#8212;if it does two, it&#8217;s doing too much.</strong> SRP says a module or function should have only one reason to change. If you mix salary calculation with email notification, you&#8217;ll break both when either requirement shifts. By splitting into focused units, changes stay isolated and tests stay simple.</p><p><strong>Why It Matters:</strong> Changes to one feature shouldn&#8217;t break unrelated ones.</p><pre><code><em># &#10060; Violates SRP: mixes user role update and email logic  </em>
def make_user_admin(user):  
    user.role = 'admin'  
    send_email(user.email, "You&#8217;re now an admin")  

<em># &#9989; SRP-compliant: split responsibilities  </em>
def set_admin(user):  
    user.role = 'admin'  

def notify_admin(email):  
    send_email(email, "You&#8217;re now an admin")  </code></pre><p><strong>Interview Script:</strong></p><blockquote><p><em>&#8220;Let&#8217;s split this into two modules&#8212;updating roles and sending emails. That way, changing the email service won&#8217;t break user management.&#8221;</em></p></blockquote><h2>Don't Repeat Yourself (DRY)</h2><p><strong>Stop the copy-paste&#8212;one place for each logic.</strong> DRY means each piece of knowledge lives in just one spot. If you find the same formula in five functions, one tweak becomes five potential bugs. Extract a helper, update once, ship safely.</p><p><strong>Why It Matters:</strong> Duplicate code = duplicate bugs.</p><pre><code><em># &#10060; Repeats area calculation  </em>
print(f"Area: {width * height}")  
volume = (width * height) * depth  

<em># &#9989; DRY: centralize logic  </em>
def calculate_area(w, h):  
    return w * h  

print(f"Area: {calculate_area(width, height)}")  </code></pre><p><strong>Interview Script:</strong></p><blockquote><p><em>&#8220;I notice some repeated logic here &#8211; I'll refactor into a helper function to keep things DRY and maintainable.&#8221;</em></p></blockquote><h2>YAGNI (You Aren&#8217;t Gonna Need It)</h2><p><strong>No crystal ball&#8212;implement features only when needed.</strong> YAGNI warns against building for hypothetical futures. Over-engineering bloats code and slows you down. Solve today&#8217;s problem simply; you can evolve the design when new requirements arrive.</p><p><strong>Why It Matters:</strong> Over-engineering kills agility.</p><pre><code><em># &#10060; Premature discount feature (unused)  </em>
def total(price, qty, discount=0):  
    return price * qty * (1 - discount)  

<em># &#9989; YAGNI: keep it simple  </em>
def total(price, qty):  
    return price * qty  </code></pre><p><strong>Interview Script:</strong></p><blockquote><p><em>&#8220;Let&#8217;s skip the discount logic for now&#8212;we can add it later if needed. YAGNI keeps our MVP lean.&#8221;</em></p></blockquote><h2>CAP Theorem Tradeoffs</h2><p><strong>Consistency or availability&#8212;in a partition, pick one.</strong> In distributed systems, you can only have two of Consistency, Availability, and Partition Tolerance. Partitions happen, so choose between consistency (fresh data) or availability (always up). A social feed tolerates slight staleness (AP); a payment system probably errs out until data syncs (CP).</p><p><strong>Why It Matters:</strong> Distributed systems require brutal prioritization.</p><blockquote><p><em>&#8220;Given this is a payment system, I&#8217;d prioritize Consistency. During a partition, we&#8217;ll error out instead of risking bad data.&#8221;</em></p></blockquote><h2>Design for Failure</h2><p><strong>Everything fails eventually&#8212;design like you know it.</strong> Murphy&#8217;s Law rules: servers crash, networks go down, disks corrupt. Build resilience with retries, fallbacks, and redundancy. If one zone goes dark, others pick up the slack; if a config file is missing, fall back to safe defaults.</p><p><strong>Why It Matters:</strong> Resilient systems survive chaos.</p><pre><code><em># Handle missing configs gracefully  </em>
try:  
    config = json.load(open('config.json'))  
except FileNotFoundError:  
    config = {"mode": "default"}  <em># Fail-safe default  </em></code></pre><blockquote><p><em>&#8220;If the database goes down, we&#8217;ll serve cached data and log the outage. No single point of failure.&#8221;</em></p></blockquote><h2>Final Thought</h2><p>At the end of the day, these principles are guides, not hard laws. Great engineers (and interviewees) use judgment to decide when to apply each principle and when to bend it. It&#8217;s better to <strong>understand the trade-offs</strong> than to blindly chant &#8220;SOLID&#8221; or &#8220;DRY&#8221; at every turn. So remember: knowing the name is good, but knowing <em>when and why</em> to use it is the real cheat code.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Beating LeetCode with Systematic Thinking: A Step-by-Step Framework for Coding Interviews]]></title><description><![CDATA[How to methodically dissect problems, avoid common pitfalls, and write solutions that impress interviewers.]]></description><link>https://asyncthinking.com/p/beating-leetcode-systematic-framework</link><guid isPermaLink="false">https://asyncthinking.com/p/beating-leetcode-systematic-framework</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Thu, 27 Feb 2025 04:39:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/64af919f-50ed-4be7-9bcc-30ca0c7668ae_1024x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>You&#8217;ve been here before</strong>: staring at a LeetCode problem, unsure where to start. You brute-force an approach, get stuck optimizing, and panic as time ticks away. What if you could turn chaotic problem-solving into a repeatable process?</p><p>In this article, I&#8217;ll share the <strong>4-step framework</strong> I used to solve LeetCode problems. No memorization is required&#8212;just systematic thinking.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Step 1: Categorize the Problem</h2><blockquote><p><strong>Goal</strong>: Identify the pattern in <strong>under 2 minutes</strong> by looking for <strong>key signals</strong>&#8212;input type, common keywords, and problem constraints.</p></blockquote><h4>1. Inspect the Input Type</h4><ul><li><p><strong>Arrays &amp; Strings</strong>: Potential for <strong>sliding window</strong>, <strong>two pointers</strong>, <strong>prefix sums</strong>, or <strong>sorting</strong> strategies.</p></li><li><p><strong>Trees &amp; Graphs</strong>: Look for <strong>DFS</strong>, <strong>BFS</strong>, <strong>topological sort</strong>, <strong>union-find</strong> (disjoint sets).</p></li><li><p><strong>Linked Lists</strong>: Often revolve around <strong>pointer manipulation</strong> (slow/fast pointers), reversing lists, or merging.</p></li><li><p><strong>Matrices/2D Grids</strong>: Typically <strong>DFS</strong>, <strong>BFS</strong> for &#8220;island&#8221; or &#8220;path&#8221; style problems, or <strong>dynamic programming</strong> for path optimizations.</p></li></ul><h4>2. Scan for Keywords</h4><p><strong>Certain words hint at certain algorithms or data structures.</strong> Use this quick-reference table to match <strong>keywords</strong> to <strong>likely patterns</strong>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-IzN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-IzN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 424w, https://substackcdn.com/image/fetch/$s_!-IzN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 848w, https://substackcdn.com/image/fetch/$s_!-IzN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 1272w, https://substackcdn.com/image/fetch/$s_!-IzN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-IzN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png" width="978" height="1480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1480,&quot;width&quot;:978,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:673750,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://asyncthinking.com/i/158012487?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-IzN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 424w, https://substackcdn.com/image/fetch/$s_!-IzN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 848w, https://substackcdn.com/image/fetch/$s_!-IzN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 1272w, https://substackcdn.com/image/fetch/$s_!-IzN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4194dde2-b167-4067-a9e5-ebe74cdbeb16_978x1480.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Example</strong>:</p><ul><li><p><strong>&#8220;Longest substring without repeating characters&#8221;</strong> &#8594; <strong>Sliding Window</strong></p><ul><li><p>Reason: &#8220;substring&#8221; implies a <strong>contiguous</strong> portion of a string; O(n) time implies a single-pass approach with two pointers.</p></li></ul></li></ul><h4>3. Consider Constraints (Time &amp; Space)</h4><ul><li><p>If the input size can be up to <strong>10^5</strong> or <strong>10^6</strong>, an <strong>O(n^2)</strong> approach will be <strong>too slow</strong>; aim for <strong>O(n)</strong> or <strong>O(n log n)</strong>.</p></li><li><p>If space is limited (e.g., &#8220;constant extra space&#8221; or &#8220;in-place&#8221; requirement), solutions like <strong>in-place</strong> sorting or <strong>two-pointer swaps</strong> may be necessary.</p></li><li><p><strong>O(log n)</strong> time constraints often signal <strong>binary search</strong> or <strong>tree-based</strong> approaches.</p></li></ul><blockquote><p><strong>Tip</strong>: The problem statement&#8217;s <strong>desired complexity</strong> (often hinted by constraints) narrows down possible algorithms. For instance, an O(n) or O(n log n) time requirement is a strong clue you shouldn&#8217;t be attempting an exhaustive <strong>backtracking</strong> or naive <strong>double loop</strong>.</p></blockquote><div><hr></div><h2><strong>Step 2: The 4-Step Framework</strong></h2><h3><strong>1. Break It Down</strong></h3><p>Rephrase the problem in plain English.</p><ul><li><p><em>Bad</em>: &#8220;I need to find the longest substring.&#8221;</p></li><li><p><em>Good</em>: &#8220;Track unique characters in a window, expand until duplicates appear, then shrink from the left.&#8221;</p></li></ul><p><strong>Identify Edge Cases</strong>:</p><ul><li><p>Empty input? All duplicates? Case sensitivity?</p></li></ul><h3><strong>2. Visualize</strong></h3><p>Sketch scenarios (even for non-visual problems):</p><ul><li><p><strong>Arrays</strong>: Draw pointers, partitions.</p></li><li><p><strong>Trees</strong>: Sketch recursion paths.</p></li><li><p><strong>Graphs</strong>: Map nodes and edges.</p></li></ul><p><strong>Example for <a href="https://leetcode.com/problems/binary-tree-maximum-path-sum/">LeetCode 124: Binary Tree Max Path Sum</a></strong>:</p><p>Copy</p><pre><code>     -10  
     /  \  
    9    20  
        /  \  
       15   7  </code></pre><p><em>Visual Insight</em>: The max path could be 15 &#8594; 20 &#8594; 7 (sum 42), ignoring the root.</p><h3><strong>3. Optimize</strong></h3><p><strong>Time-Space Tradeoffs</strong>:</p><ul><li><p>Replace nested loops with hash maps (e.g., two-sum).</p></li><li><p>Use recursion with memoization for overlapping subproblems (DP).</p></li><li><p>Precompute values (prefix sums, frequency counts).</p></li></ul><p><strong>Red Flags</strong>:</p><ul><li><p>Brute-force solutions with <em>O(n&#178;)</em> time.</p></li><li><p>Recursion without memoization (stack overflow risk).</p></li></ul><h3><strong>4. Code</strong></h3><p><strong>Interview-Ready Code Checklist</strong>:</p><ul><li><p>Descriptive variable names (<code>left_ptr</code>, <code>max_sum</code>).</p></li><li><p>Handle edge cases upfront.</p></li><li><p>Add brief comments for complex logic.</p></li></ul><p><strong>Bad vs Good Code</strong>:</p><pre><code># Bad: Unclear variables  
def f(s):  
    d = {}  
    l = 0  
    ...  

# Good: Self-documenting  
def longest_unique_substring(s: str) -&gt; int:  
    char_index_map = {}  
    left = 0  
    max_length = 0  
    ...  </code></pre><div><hr></div><h2>Step 3: Avoid These 3 Deadly Traps</h2><h3>1. The &#8220;Code First, Think Later&#8221; Mistake</h3><ul><li><p><strong>Why It Fails</strong>: Jumping into code without planning leads to confusion, endless debugging, and missed edge cases.</p></li><li><p><strong>How to Fix It</strong>: Spend at least <strong>10 minutes</strong> on problem analysis (Steps 1&#8211;3) before writing a single line of code. Outline your approach, consider edge cases, and confirm time/space constraints.</p></li></ul><h3>2. Overcomplicating Solutions</h3><ul><li><p><strong>Why It Fails</strong>: Using advanced data structures or algorithms when simpler ones suffice wastes time and increases bug risk.</p></li><li><p><strong>How to Fix It</strong>: Always ask, &#8220;What&#8217;s the <strong>simplest</strong> approach that meets the <strong>constraints</strong>?&#8221; Start with that and only optimize further if needed.</p></li></ul><h3>3. Ignoring Space Complexity</h3><ul><li><p><strong>Why It Fails</strong>: Focusing solely on time complexity can lead to memory bloat or stack overflow&#8212;problems you discover too late.</p></li><li><p><strong>How to Fix It</strong>: <strong>Calculate</strong> space complexity upfront. If recursion or extra data structures could get too large, switch to an <strong>iterative</strong> or more memory-efficient approach.</p></li></ul><div><hr></div><h2>Case Study: LeetCode 239 &#8211; Sliding Window Maximum</h2><p><strong>Problem Statement</strong><br>You are given an integer array <code>nums</code> and an integer <code>k</code>, representing the size of a sliding window. For each valid window position, return the maximum value within that window.</p><div><hr></div><h3><strong>Step 1: Categorize the Problem</strong></h3><ol><li><p><strong>Identify the Input Type</strong></p><ul><li><p>Input is an <strong>array</strong> (<code>nums</code>) with the potential for repeated elements.</p></li></ul></li><li><p><strong>Look for Keywords</strong></p><ul><li><p>&#8220;Sliding Window,&#8221; &#8220;Maximum,&#8221; and &#8220;Size k.&#8221;</p></li><li><p>These keywords strongly hint at the <strong>Sliding Window</strong> pattern and the possibility of a <strong>deque</strong> (double-ended queue) solution to keep track of maximum elements.</p></li></ul></li><li><p><strong>Check Constraints</strong></p><ul><li><p>Typically, <code>n</code> can be large (e.g., up to <code>10^5</code>).</p></li><li><p>A naive O(n*k) approach will be too slow for large <code>n</code> if <code>k</code> is also large.</p></li><li><p>This suggests we need an <strong>O(n)</strong> or <strong>O(n log n)</strong> approach.</p></li></ul></li></ol><blockquote><p><strong>Result</strong>: We&#8217;ve placed the problem into the <strong>Sliding Window</strong> category, where we keep track of the <strong>maximum</strong> using a <strong>deque</strong> or similar structure.</p></blockquote><div><hr></div><h3><strong>Step 2: Use the 4-Step Framework</strong></h3><p>Now that we&#8217;ve categorized it, let&#8217;s apply the framework in detail.</p><h4>1. Break It Down</h4><ul><li><p><strong>Plain English Restatement</strong><br>&#8220;We slide a window of size <code>k</code> across the array. For every window position, find the maximum element.&#8221;</p></li><li><p><strong>Edge Cases</strong></p><ul><li><p><strong>k = 1</strong>: Return the array as-is (every element is its own max).</p></li><li><p><strong>k = len(nums)</strong>: Only one window; the result is a single value&#8212;the max of the entire array.</p></li><li><p><strong>Mixed or Negative Values</strong>: Ensure we handle them correctly (the max may be negative).</p></li></ul></li></ul><div><hr></div><h4>2. Visualize</h4><p>To really <em>see</em> how this works, consider a concrete example:</p><pre><code>nums = [1, 3, -1, -3, 5, 3, 6], k = 3

Window positions:
1) [1, 3, -1], -3, 5, 3, 6  -&gt; max = 3
2) 1, [3, -1, -3], 5, 3, 6  -&gt; max = 3
3) 1, 3, [-1, -3, 5], 3, 6  -&gt; max = 5
4) 1, 3, -1, [-3, 5, 3], 6  -&gt; max = 5
5) 1, 3, -1, -3, [5, 3, 6]  -&gt; max = 6
</code></pre><ul><li><p><strong>Naive Approach</strong>: For each window, scan <code>k</code> elements. This is <strong>O(n*k)</strong>, which can be costly for large <code>n</code>.</p></li><li><p><strong>Key Insight</strong>: We can maintain a <strong>deque</strong> that stores indices of elements in <strong>descending order</strong>. The element at the front is always the window&#8217;s maximum.</p></li></ul><div><hr></div><h4>3. Optimize</h4><ul><li><p><strong>Time Complexity Goals</strong></p><ul><li><p>A direct approach: O(n*k) &#8211; <strong>too slow</strong> for large <code>n</code> and <code>k</code>.</p></li><li><p>Optimized approach: <strong>O(n)</strong>, by ensuring each index enters and leaves the deque <em>at most once</em>.</p></li></ul></li><li><p><strong>Why a Deque?</strong></p><ul><li><p>We can <strong>push</strong> new elements (by index) at the back.</p></li><li><p><strong>Pop</strong> from the back any elements smaller or equal to the new element (they&#8217;ll never be needed).</p></li><li><p><strong>Pop</strong> from the front if the front index is out of the current window (i.e., <code>front == i - k</code>).</p></li><li><p>The <strong>front</strong> of the deque is always the index of the current window&#8217;s maximum element.</p></li></ul></li></ul><blockquote><p><strong>Result</strong>: Each element is processed in constant time, leading to a total of <strong>O(n)</strong>.</p></blockquote><div><hr></div><h4>4. Code</h4><p>Below is an <strong>interview-ready</strong> Python solution. Note the <strong>inline comments</strong> that map back to our strategy:</p><pre><code>from collections import deque
from typing import List

def max_sliding_window(nums: List[int], k: int) -&gt; List[int]:
    # Handle trivial case
    if k == 1:
        return nums
    
    q = deque()  # will store indices of potential maxima
    result = []
    
    for i, num in enumerate(nums):
        # 1. Pop from the back while the current num is &gt;= the element at q[-1]
        #    Those smaller elements can't be a future max
        while q and nums[q[-1]] &lt;= num:
            q.pop()
        
        # 2. Push the current index onto the back
        q.append(i)
        
        # 3. If the front of the deque is out of the window, pop it
        if q[0] == i - k:
            q.popleft()
        
        # 4. Once we've processed at least k elements, the front of q is the max
        if i &gt;= k - 1:
            result.append(nums[q[0]])
    
    return result</code></pre><div><hr></div><h2>Mental Models from Top Engineers</h2><ol><li><p><strong>The 20-Minute Rule</strong></p><ul><li><p><strong>What It Is</strong>: Spend no more than 20 minutes stuck on a single approach. If you&#8217;re still spinning your wheels, seek a hint or switch tactics.</p></li><li><p><strong>Why It Works</strong>: Timeboxing prevents you from wasting hours on a dead end and encourages you to explore alternative methods sooner.</p></li></ul></li><li><p><strong>Spaced Repetition</strong></p><ul><li><p><strong>What It Is</strong>: Revisit problems and patterns weekly to consolidate learning (tools: Anki, LeetCode&#8217;s &#8220;Review&#8221; feature).</p></li><li><p><strong>Why It Works</strong>: The human brain retains information more effectively when it&#8217;s reinforced at <strong>structured intervals</strong> rather than cramped.</p></li></ul></li><li><p><strong>Mock Interviews</strong></p><ul><li><p><strong>What It Is</strong>: Practice out loud with friends or online platforms (e.g., Pramp, Interviewing.io).</p></li><li><p><strong>Why It Works</strong>: Verbalizing solutions reveal gaps in your reasoning and help you simulate real interview pressure.</p></li></ul></li><li><p><strong>The Feynman Technique</strong></p><ul><li><p><strong>What It Is</strong>: Teach or explain a problem in your own words as if you&#8217;re instructing a beginner.</p></li><li><p><strong>Why It Works</strong>: Breaking down complex ideas into simple explanations clarifies your thought process and uncovers hidden assumptions.</p></li></ul></li><li><p><strong>&#8220;Post-Mortem&#8221; Analysis</strong></p><ul><li><p><strong>What It Is</strong>: After solving each problem (or failing to), jot down what went well, where you struggled, and how you&#8217;d improve next time.</p></li><li><p><strong>Why It Works</strong>: Reflection cements lessons learned and highlights recurring mistakes, so you don&#8217;t repeat them.</p></li></ul></li><li><p><strong>The Pareto Principle (80/20 Rule)</strong></p><ul><li><p><strong>What It Is</strong>: Focus on the 20% of problem types or patterns (e.g., sliding window, DFS, DP) that appear 80% of the time in interviews.</p></li><li><p><strong>Why It Works</strong>: Targeted practice on the most common patterns yields the biggest bang for your buck in a limited timeframe.</p></li></ul></li><li><p><strong>Rubber Duck Debugging</strong></p><ul><li><p><strong>What It Is</strong>: Explain each line of your logic to an inanimate &#8220;listener&#8221; (like a rubber duck) or even just yourself.</p></li><li><p><strong>Why It Works</strong>: Speaking out loud forces you to slow down and identify subtle errors or assumptions in your reasoning.</p></li></ul></li></ol><div><hr></div><h2><strong>Your Action Plan</strong></h2><ol><li><p><strong>Learn Patterns, Not Problems</strong>: Focus on categories (e.g., sliding window, DFS).</p></li><li><p><strong>Time Yourself</strong>: Solve easies in 10 minutes, mediums in 20, hards in 30.</p></li><li><p><strong>Analyze Failures</strong>: For every wrong answer, write down why (e.g., missed edge case).</p></li></ol><div><hr></div><h4><strong>Final Tip: Embrace the Process, Not Just the Answer</strong></h4><p>LeetCode success isn&#8217;t about raw talent or memorizing a hundred solutions&#8212;it&#8217;s about using a <strong>consistent, repeatable framework</strong>. The next time you face a challenging problem:</p><ol><li><p><strong>Categorize</strong> the question type (arrays, graphs, DP, etc.).</p></li><li><p><strong>Visualize</strong> the steps or data structures involved.</p></li><li><p><strong>Optimize</strong> with an eye on time and space constraints.</p></li><li><p><strong>Code</strong> cleanly, handling edge cases upfront.</p></li></ol><p>By shifting from guesswork to <strong>structured problem-solving</strong>, you&#8217;ll tackle even the toughest interviews with confidence. More importantly, these skills carry over to real-world engineering, turning every coding challenge into a stepping stone for your growth.</p><div><hr></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How TikTok Keeps 1.2 Billion Hooked: The Engineering Behind Its Addictive Feed]]></title><description><![CDATA[The AI, Microservices, and CDN Magic That Keep TikTok Running at Lightning Speed]]></description><link>https://asyncthinking.com/p/tiktok-architecture-secrets</link><guid isPermaLink="false">https://asyncthinking.com/p/tiktok-architecture-secrets</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Thu, 30 Jan 2025 16:01:31 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/85a7327f-0589-401a-af5d-435c9626c3b9_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Async Thinkers! &#128075;</p><div><hr></div><h2><strong>Setting the Stage</strong></h2><p>Imagine this: every minute, TikTok users upload more than <strong>16000+ videos</strong>, tap <strong>11 million likes</strong>, and hammer out <strong>5 million comments</strong>&#8212;while an AI feed seemingly knows your taste in music, your sense of humor, and your pet&#8217;s name better than you do.</p><p>This is the platform that turned short-form video into a global obsession. Love it or hate it, TikTok&#8217;s engineering is a marvel of modern system design.</p><p>Today, we&#8217;re cracking open the black box. Let&#8217;s dissect how TikTok handles:</p><p>&#9989; <strong>Petabyte-scale uploads</strong><br>&#9989; <strong>Sub-50ms AI recommendations</strong><br>&#9989; <strong>A global CDN built for speed</strong></p><p>Grab your popcorn, because we&#8217;re about to see how the engineers at ByteDance keep the show rolling for over <strong>a billion users&#8212;without missing a single beat.</strong></p><div><hr></div><h2><strong>1. The 10-Second Time Bomb: TikTok&#8217;s Core Challenges</strong></h2><p>TikTok isn&#8217;t just another social media platform&#8212;it&#8217;s an endless, real-time content tsunami that devours bandwidth, compute power, and developer ingenuity. At its core, engineers must tackle:</p><h3><strong>Upload Avalanche</strong></h3><p>&#128249; Over <strong>350 hours of video uploaded every minute</strong> (~5GB/hour for 4K).<br>&#9889; A complex workflow ensures minimal friction for creators worldwide.</p><h3><strong>Scroll Apocalypse</strong></h3><p>&#128241; Over <strong>a billion daily video views</strong> demanding near-instant feed loading.</p><h3><strong>AI Mind-Reader</strong></h3><p>&#129504; Recommending videos <strong>within 50 ms</strong> of app launch for maximum engagement.</p><p>These aren&#8217;t solved by magic. They&#8217;re solved by <strong>brutal system design optimizations, geo-distributed microservices, and borderline obsessive testing.</strong></p><div><hr></div><h2><strong>2. Handling the Upload Deluge: How TikTok Digests 350+ Hours of Video per Minute</strong></h2><h3><strong>Solution: Geo-Distributed Microservices</strong></h3><h4><strong>Chunk &amp; Conquer</strong></h4><p>&#128230; Videos are split into <strong>1&#8211;5 MB chunks via MPEG-DASH</strong>, allowing parallel processing across <strong>200+ global Points of Presence (PoPs).</strong><br>&#9889; This parallelism ensures that even massive uploads are completed quickly.</p><h4><strong>Edge Encoding</strong></h4><p>&#127902;&#65039; Real-time transcoding <strong>using GPUs at edge nodes</strong>, not just plain old FFmpeg scripts.<br>&#128260; In most regions, <strong>720p is prioritized for immediate availability</strong>, with full-resolution versions processed in the background. (Some bandwidth-constrained regions may start at 480p.)</p><h4><strong>Priority Tiers</strong></h4><p>&#128202; TikTok <strong>prioritizes high-profile uploaders</strong>, ensuring creators with high engagement (often monetized) get faster throughput.<br>&#128257; ByteDance leans heavily on <strong>Pulsar (over Kafka)</strong> to orchestrate and buffer these upload pipelines, though some legacy systems still rely on Kafka.</p><h4><strong>Custom Storage Layers</strong></h4><p>&#128293; <strong>&#8220;Hot&#8221; videos</strong>&#8212;recently uploaded or going viral&#8212;reside on <strong>NVMe SSDs</strong> for ~48 hours.<br>&#128194; After trending periods end, they&#8217;re shifted to ByteDance&#8217;s <strong>in-house &#8220;HDFS++&#8221; object store</strong> (because apparently, AWS S3 wasn&#8217;t enough).</p><p>&#128161; <strong>Pro Tip:</strong> TikTok actively monitors <strong>regional usage patterns</strong> to distribute heavy encoding tasks to off-peak hours&#8212;so your <strong>midnight</strong> upload may process faster than a prime-time post.</p><div><hr></div><h2><strong>3. The &#8220;For You Page&#8221; AI: Hypnotizing You in 50 ms</strong></h2><p>If there&#8217;s a secret sauce that turned TikTok into a cultural phenomenon, it&#8217;s the <strong>For You Page (FYP).</strong> It&#8217;s an <strong>ensemble of AI models</strong> that are really good at predicting what you want to watch next.</p><h3><strong>Step 1: Real-Time Feature Extraction</strong></h3><p>&#128269; <strong>Micro-Gesture Tracking:</strong> TikTok tracks <strong>swipe velocity</strong> (users dwell for ~2.1 seconds per video) and <strong>&#8220;scroll hysteresis&#8221;</strong> (how forcefully you stop scrolling).<br>&#127917; <strong>Multi-Modal Fusion:</strong> Leveraging <strong>CLIP-like models</strong> to analyze video frames, text overlays, audio, and voice transcripts <strong>simultaneously.</strong></p><h3><strong>Step 2: Model Training</strong></h3><p>&#129504; <strong>Hybrid Learning:</strong> A mix of <strong>federated learning (on devices)</strong> + centralized training on <strong>10,000+ A100 GPUs.</strong><br>&#128260; <strong>Real-Time Feedback Loop:</strong> Most user preference updates happen <strong>within 90 seconds, but some adapt in just seconds</strong> if engagement shifts sharply.</p><h3><strong>Step 3: Inference &amp; Delivery</strong></h3><p>&#128225; <strong>Edge Caching:</strong> TikTok pre-computes <strong>three potential feed variants per user</strong>, caching them in <strong>local data centers</strong>&#8212;so videos load instantly.<br>&#9889; <strong>Fallback Mechanism:</strong> If something fails, TikTok switches to <strong>geo-local trending videos</strong>, serving them <strong>400 million times a day&#8212;without you noticing.</strong></p><div><hr></div><h2><strong>4. The CDN Illusion: How TikTok Delivers Videos at Warp Speed</strong></h2><p>TikTok&#8217;s secret? A <strong>globally distributed nervous system</strong>:</p><p><strong>A. Edge Caching</strong><br>&#128450;&#65039; <strong>8,000+ servers</strong> inside ISP hubs store the top 0.1% of viral videos (your cousin&#8217;s dance reel? Probably not here).</p><p><strong>B. Adaptive Protocols</strong><br>&#128640; <strong>QUIC protocol</strong> (Google&#8217;s faster alternative to TCP) slashes buffering by <strong>75%</strong>.</p><p><strong>C. Codec Wars</strong><br>&#127909; <strong>H.266/VVC codecs</strong> save <strong>50% bandwidth</strong> vs. AV1&#8212;critical for users on potato-tier networks.</p><p><em>&#128176; Money Shot: TikTok&#8217;s private CDN costs <strong>$1.3B/year</strong>, but ad revenue covers it 1.5x over.</em></p><div><hr></div><h2><strong>5. Real-Time Chaos: Likes, Comments, and Digital Anarchy</strong></h2><p><strong>7 million likes/second?</strong> Here&#8217;s how TikTok avoids meltdowns:</p><p>&#9889; <strong>RedisCell</strong>: Atomic counters keep likes synced globally (no double-tap ghosts).<br>&#9878;&#65039; <strong>CRDTs</strong>: Conflict-free data types resolve comment clashes in <strong>11ms</strong> (faster than your Wi-Fi latency).<br>&#128680; <strong>AI Moderation</strong>: 30+ models scan comments <em>as you type</em>, blocking spam before it&#8217;s posted.</p><p><em>&#128293; Fail-Safe: If likes break, TikTok lies to you (&#8220;Liked!&#8221;) while frantically fixing things backend.</em></p><div><hr></div><h2><strong>6. Disaster Mode: When Systems Implode</strong></h2><h3><strong>Case Study: 2023 LIVE Shopping Day Crash</strong></h3><p>&#128201; <strong>28 million concurrent viewers</strong> overwhelmed product link servers.</p><h3><strong>The Fix:</strong></h3><p>&#9889; <strong>22-second fallback UI</strong> using <strong>WebAssembly.</strong><br>&#128260; <strong>Traffic rerouted</strong> to Moscow PoP (lowest load).<br>&#127908; <strong>Influencers prioritized</strong> to keep major creators online.</p><p>&#128165; <strong>Chaos Engineering:</strong> TikTok <strong>intentionally crashes a cluster daily</strong> to test real-time recovery. <strong>Average fix time? 9.7 seconds.</strong></p><div><hr></div><h2><strong>What&#8217;s Next? Your Call!</strong></h2><p>What should we break down next?</p><p>1&#65039;&#8419; <strong>Netflix: Why Buffering is Basically Dead</strong><br>2&#65039;&#8419; <strong>Uber: The Real-Time Surge Pricing Engine</strong><br>3&#65039;&#8419; <strong>X/Twitter: 300K TPS Meltdown (and Recovery)</strong></p><p>Reply with your pick&#8212;or just drop a note if you&#8217;re vibing with this style!</p><p>Until next week&#8212;<strong>keep scaling the impossible, one microservice at a time.</strong></p><p>Heads up&#8212;I&#8217;m trying out something new this week with a slightly bolder, more conversational style. Let me know if you dig this new tone or if you prefer the old vibe!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Thanks for reading Async Thinking!</strong> If you found this newsletter helpful, consider sharing it with a friend or colleague. And if you haven&#8217;t already, subscribe for free to receive more deep dives on engineering, architecture, and beyond.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[System Design Interviews Are a Game: Here’s How to Win]]></title><description><![CDATA[A Proven Blueprint for Handling High-Stakes System Design in 45 Minutes or Less.]]></description><link>https://asyncthinking.com/p/master-system-design-interviews</link><guid isPermaLink="false">https://asyncthinking.com/p/master-system-design-interviews</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Sun, 26 Jan 2025 21:37:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1bc4dbc5-508a-4f4e-8155-9b25649794d0_640x640.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello and welcome to <strong>Async Thinking</strong>! If you&#8217;ve ever felt the pressure of designing a massive platform like <strong>YouTube</strong> in under an hour, you know just how high the stakes can feel. <strong>System design interviews</strong> might seem like a game of impossible expectations. But here&#8217;s the secret: once you learn the rules, you can play&#8212;and win.</p><div><hr></div><h2>The High-Stakes Game of System Design</h2><p>System design interviews often come with:</p><ul><li><p><strong>Ambiguous requirements</strong> that demand clarifying questions</p></li><li><p><strong>Time pressure</strong> (usually 45&#8211;60 minutes)</p></li><li><p><strong>Unclear best answers</strong> but a high bar for demonstrating structured thinking</p></li></ul><p>Despite these challenges, system design interviews aren&#8217;t about perfection. They&#8217;re about showing how you <strong>approach</strong> and <strong>break down</strong> complex problems. By the end of this newsletter, you&#8217;ll know the core framework for tackling any system design prompt&#8212;and you&#8217;ll be one step closer to thinking like an architect under pressure.</p><div><hr></div><h2>My First System Design Interview (And the Lessons Learned)</h2><p>I still remember my first attempt at a system design interview. The prompt? <strong>&#8220;Design a scalable, real-time messaging system like WhatsApp.&#8221;</strong></p><p>I started confident, sketching a quick architecture with users, servers, and databases. But then came the deeper questions:</p><blockquote><p>&#8220;How would you ensure real-time message delivery under heavy traffic?&#8221;<br>&#8220;What about fault tolerance and data durability?&#8221;<br>&#8220;How do you handle encryption and privacy?&#8221;</p></blockquote><p>Suddenly, I realized <strong>just how intricate</strong> messaging at scale can be. I stumbled through suggestions&#8212;a pub-sub model, message queues&#8212;but missed key considerations like <strong>database sharding</strong>, <strong>caching</strong>, and <strong>encryption</strong>.</p><p>The <strong>big lesson?</strong> System design isn&#8217;t about cramming in every possible component; it&#8217;s about systematically <strong>asking the right questions</strong>, <strong>considering trade-offs</strong>, and <strong>justifying your decisions</strong>.</p><div><hr></div><h2>Why It Feels Like a Game</h2><p>In a system design interview, you&#8217;re under the gun to:</p><ol><li><p><strong>Clarify vague requirements</strong> (the interviewer expects you to ask questions).</p></li><li><p><strong>Manage your time</strong> (45 minutes goes fast).</p></li><li><p><strong>Analyze trade-offs</strong> (strong vs. eventual consistency, monolith vs. microservices, SQL vs. NoSQL, etc.).</p></li><li><p><strong>Communicate effectively</strong> (while thinking on your feet).</p></li></ol><p>When you understand these &#8220;rules,&#8221; the interview transforms from an impossible task into a <strong>focused</strong> exercise in architectural thinking.</p><div><hr></div><h2>A Framework to Dominate Any System Design Interview</h2><p>Whether you&#8217;re designing <strong>YouTube</strong>, <strong>a Chat App</strong>, or <strong>a Rate Limiter</strong>, you can follow this structured approach:</p><h3>1. <strong>Clarify Requirements</strong></h3><ul><li><p>Ask specific questions to understand the scope.</p></li><li><p>Examples:</p><ul><li><p>&#8220;How many daily active users are we expecting?&#8221;</p></li><li><p>&#8220;Is strict ordering of messages crucial?&#8221;</p></li><li><p>&#8220;Are we prioritizing <strong>low latency</strong>, <strong>high availability</strong>, or <strong>strong consistency</strong>?&#8221;</p></li></ul></li></ul><h3>2. <strong>Define Key Constraints</strong></h3><ul><li><p>Identify critical factors like <strong>throughput</strong>, <strong>latency requirements</strong>, <strong>fault tolerance</strong>, and <strong>data consistency</strong>.</p></li><li><p>Example: &#8220;For a messaging system, <strong>real-time delivery</strong> is essential, but we may accept <strong>eventual consistency</strong> for read operations.&#8221;</p></li></ul><h3>3. <strong>Sketch a High-Level Architecture</strong></h3><ul><li><p>Draw out main components: load balancer, application servers, databases, caches.</p></li><li><p>Example for a messaging app:</p><ul><li><p><strong>Load Balancer</strong>: Distributes traffic across multiple server instances.</p></li><li><p><strong>Pub-Sub or Message Queue</strong>: Handles asynchronous message delivery.</p></li><li><p><strong>Database</strong>: Stores messages, user data, metadata. Consider <strong>sharding</strong> or <strong>replication</strong> strategies.</p></li></ul></li></ul><h3>4. <strong>Dive into Critical Components</strong></h3><ul><li><p>Pick 1&#8211;2 areas to detail (e.g., real-time messaging pipeline, database sharding strategy, or encryption).</p></li><li><p>Show <strong>depth</strong> in explaining these choices.</p></li></ul><h3>5. <strong>Discuss Trade-Offs</strong></h3><ul><li><p>Compare potential solutions (e.g., SQL vs. NoSQL).</p></li><li><p>Explain the pros and cons (e.g., &#8220;NoSQL offers flexibility and easier sharding, but SQL can provide stronger ACID guarantees.&#8221;)</p></li></ul><h3>6. <strong>Plan for Scaling</strong></h3><ul><li><p>Address future growth: &#8220;We&#8217;ll shard the database using consistent hashing and replicate to different regions for lower latency.&#8221;</p></li><li><p>Mention tools or services that handle large-scale operations (e.g., Kafka, Redis, Cassandra).</p></li></ul><h3>7. <strong>Wrap Up</strong></h3><ul><li><p>Summarize your design and highlight <strong>key decisions</strong>.</p></li><li><p>Ask for clarifications or indicate areas you could dive deeper into if time allows.</p></li></ul><div><hr></div><h2>Popular Prompts &amp; What They Test</h2><ol><li><p><strong>Design a URL Shortener</strong></p><ul><li><p>Hashing, database design, read/write performance.</p></li></ul></li><li><p><strong>Design a Chat Application</strong></p><ul><li><p>Real-time messaging, fault tolerance, encryption.</p></li></ul></li><li><p><strong>Design YouTube</strong></p><ul><li><p>Video storage, CDN, streaming, recommendation engine basics.</p></li></ul></li><li><p><strong>Design an E-Commerce Platform</strong></p><ul><li><p>Inventory management, transaction handling, caching.</p></li></ul></li><li><p><strong>Design a Rate Limiter</strong></p><ul><li><p>Distributed counters, throttling, consistency.</p></li></ul></li></ol><div><hr></div><h2>How to Prepare</h2><ol><li><p><strong>Study Core Concepts</strong>: CAP theorem, load balancing, caching strategies, database sharding, replication, consistency models.</p></li><li><p><strong>Practice Frameworks</strong>: Keep refining a reusable approach for clarifying requirements, picking components, and scaling strategies.</p></li><li><p><strong>Use Real-World Case Studies</strong>: Netflix and AWS blog posts often share how they handle billions of requests&#8212;gold mines for learning about distributed systems.</p></li><li><p><strong>Mock Interviews</strong>: Platforms like Pramp or Interviewing.io help you practice communicating your ideas under time pressure.</p></li><li><p><strong>Think Aloud</strong>: Get comfortable articulating your thoughts so your interviewer sees how you approach problems.</p></li></ol><div><hr></div><h2>Bonus: Quick Cheat Sheet</h2><ol><li><p><strong>Ask Questions</strong> (Users, Data, Traffic, Requirements)</p></li><li><p><strong>Identify Key Constraints</strong> (Latency, Consistency, Availability)</p></li><li><p><strong>Outline a High-Level Design</strong> (Load Balancer, App Servers, Database, Cache)</p></li><li><p><strong>Deep Dive</strong> on 1&#8211;2 Components (Pub-Sub, DB Sharding, etc.)</p></li><li><p><strong>Highlight Trade-Offs</strong> (SQL vs. NoSQL, Microservices vs. Monolith)</p></li><li><p><strong>Scaling Strategy</strong> (Horizontal vs. Vertical Scaling)</p></li><li><p><strong>Summarize and Clarify Next Steps</strong></p></li></ol><div><hr></div><h2>Conclusion: Think Like an Architect</h2><p>System design interviews are a <strong>valuable exercise</strong> in tackling large-scale engineering problems under pressure. They&#8217;re not about constructing a perfect solution in 45 minutes&#8212;they&#8217;re about showcasing your <strong>structured thinking</strong>, <strong>trade-off analysis</strong>, and <strong>communication skills</strong>.</p><p>Master the framework, practice with real examples, and you&#8217;ll soon find these interviews aren&#8217;t an impossible game&#8212;they&#8217;re a <strong>playground</strong> for innovative thinking.</p><p>Happy designing!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Thanks for reading Async Thinking!</strong> If you found this newsletter helpful, consider sharing it with a friend or colleague preparing for system design interviews. And if you haven&#8217;t already, subscribe for free to receive more deep dives on engineering, architecture, and beyond.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Art of REST API Design: Building Intuitive and Scalable Systems]]></title><description><![CDATA[Master the Essentials of REST API Design in Simple Steps]]></description><link>https://asyncthinking.com/p/the-art-of-rest-api-design</link><guid isPermaLink="false">https://asyncthinking.com/p/the-art-of-rest-api-design</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Thu, 09 Jan 2025 04:59:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lYXm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lYXm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lYXm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 424w, https://substackcdn.com/image/fetch/$s_!lYXm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 848w, https://substackcdn.com/image/fetch/$s_!lYXm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 1272w, https://substackcdn.com/image/fetch/$s_!lYXm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lYXm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png" width="1456" height="784" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:784,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:118294,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lYXm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 424w, https://substackcdn.com/image/fetch/$s_!lYXm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 848w, https://substackcdn.com/image/fetch/$s_!lYXm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 1272w, https://substackcdn.com/image/fetch/$s_!lYXm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff25f5fee-4a16-4d1e-9864-b766050b60f3_1560x840.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>REST APIs are the invisible workhorses of modern software, powering everything from your favourite mobile apps to massive cloud-based systems. They&#8217;re the bridges that connect disparate systems, enabling seamless data exchange. But when an API is poorly designed, it can frustrate developers, degrade user experiences, and stifle innovation.</p><p>That&#8217;s why thoughtful API design isn&#8217;t a luxury&#8212;it&#8217;s a necessity. A well-designed API doesn&#8217;t just work; it&#8217;s intuitive, reliable, and a delight to use. In this newsletter, we&#8217;ll break down actionable best practices to help you craft REST APIs that developers will love.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3>1. Master the Basics: HTTP Methods</h3><p>HTTP methods are the backbone of REST APIs. When used correctly, they make your API intuitive and predictable. Let&#8217;s dive deeper into what makes each method essential.</p><h4><strong>GET: Retrieve Resources</strong></h4><ul><li><p><strong>Use Case:</strong> Fetch data without making changes.</p></li><li><p><strong>Examples:</strong></p><ul><li><p><code>GET /users</code> retrieves a list of users.</p></li><li><p><code>GET /users/123</code> fetches details about the user with ID 123.</p></li></ul></li><li><p><strong>Best Practices:</strong></p><ul><li><p>Use query parameters for filtering, sorting, or pagination.<br>Example: <code>GET /users?status=active&amp;page=2&amp;limit=10</code>.</p></li><li><p>Return appropriate status codes:</p><ul><li><p><code>200 OK</code> for successful retrieval.</p></li><li><p><code>404 Not Found</code> if the resource doesn&#8217;t exist.</p></li></ul></li></ul></li><li><p><strong>Tip:</strong> Avoid using GET for operations that change the server state, as this can lead to unexpected side effects.</p></li></ul><h4><strong>POST: Create Resources</strong></h4><ul><li><p><strong>Use Case:</strong> Add a new resource to the system.</p></li><li><p><strong>Examples:</strong></p><ul><li><p><code>POST /users</code> creates a new user with the provided payload.</p></li></ul></li></ul><pre><code><code>{
  "name": "Jane Doe",
  "email": "jane.doe@example.com"
}</code></code></pre><ul><li><p><strong>Best Practices:</strong></p><ul><li><p>Return <code>201 Created</code> on success.</p></li><li><p>Include the URI of the newly created resource in the <code>Location</code> header.</p></li></ul></li></ul><pre><code><code>Location: /users/123</code></code></pre><ul><li><p>Validate input to ensure only valid data is processed.</p></li></ul><h4><strong>PUT and PATCH: Update Resources</strong></h4><ul><li><p><strong>PUT</strong>: Replace the entire resource.</p></li></ul><pre><code><code>PUT /users/123
{
  "name": "John Doe",
  "email": "john.doe@example.com"
}</code></code></pre><ul><li><p><strong>PATCH</strong>: Partially update specific fields.</p></li></ul><pre><code><code>PATCH /users/123
{
  "email": "john.new@example.com"
}</code></code></pre><ul><li><p><strong>Best Practices:</strong></p><ul><li><p>Use <code>404 Not Found</code> if the resource doesn&#8217;t exist.</p></li><li><p>Document which fields are required for PUT and optional for PATCH.</p></li></ul></li></ul><h4><strong>DELETE: Remove Resources</strong></h4><ul><li><p><strong>Use Case:</strong> Permanently delete a resource.</p></li><li><p><strong>Example:</strong><br><code>DELETE /users/123</code> removes the user with ID 123.</p></li><li><p><strong>Best Practices:</strong></p><ul><li><p>Return <code>204 No Content</code> on successful deletion.</p></li><li><p>Avoid destructive operations for resources in use; consider soft deletes where applicable.</p></li></ul></li></ul><div><hr></div><h3>2. Design Clear, Consistent URIs</h3><p>URIs are the front door of your API. A well-designed URI structure makes your API easier to use and maintain.</p><h4><strong>Core Principles</strong></h4><ol><li><p><strong>Human-Readable:</strong><br>A URI should be self-explanatory:</p><ul><li><p>&#9989; <code>/users</code> (clear and concise).</p></li><li><p>&#10060; <code>/getAllUsers</code> (exposes implementation details).</p></li></ul></li><li><p><strong>Use Plural Nouns for Collections:</strong></p><ul><li><p>&#9989; <code>/users</code> (for a collection of users).</p></li><li><p>&#10060; <code>/userList</code> (inconsistent naming).</p></li></ul></li><li><p><strong>Avoid Verb-Based URIs:</strong><br>Let the HTTP method dictate the operation:</p><ul><li><p>&#9989; <code>POST /users</code> (to create a user).</p></li><li><p>&#10060; <code>/createUser</code>.</p></li></ul></li></ol><h4><strong>Advanced Design Patterns</strong></h4><ul><li><p><strong>Hierarchical Relationships:</strong><br>Represent relationships between resources:</p><ul><li><p>Example:<br><code>GET /users/123/orders</code> retrieves all orders for the user with ID 123.</p></li></ul></li><li><p><strong>Filtering and Searching:</strong><br>Use query parameters for complex queries:</p><ul><li><p>Example: <code>GET /products?category=electronics&amp;price_lt=1000</code>.</p></li></ul></li></ul><div><hr></div><h3>3. Versioning Your API</h3><p>APIs are living systems that evolve. Proper versioning ensures stability and backward compatibility.</p><h4><strong>Versioning Strategies</strong></h4><ol><li><p><strong>URI-Based Versioning:</strong></p><ul><li><p>Example:<br><code>GET /api/v1/users</code> (Version 1).<br><code>GET /api/v2/users</code> (Version 2 with new features).</p></li></ul></li><li><p><strong>Header-Based Versioning:</strong></p></li></ol><pre><code><code>GET /users
Accept: application/vnd.example.v2+json</code></code></pre><ol start="3"><li><p><strong>Semantic Versioning:</strong></p></li></ol><ul><li><p>Increment versions based on changes:</p><ul><li><p><code>v1.0.0</code>: Initial release.</p></li><li><p><code>v1.1.0</code>: Backward-compatible updates.</p></li><li><p><code>v2.0.0</code>: Breaking changes.</p></li></ul></li></ul><h4><strong>Best Practices</strong></h4><ul><li><p>Communicate deprecation timelines for older versions.</p></li><li><p>Include migration guides for smooth transitions.</p></li></ul><div><hr></div><h3>4. Thoughtful Error Handling</h3><p>Errors are inevitable. The key is to provide clear, actionable feedback when they occur.</p><h4><strong>Best Practices</strong></h4><ul><li><p><strong>Use Appropriate HTTP Status Codes:</strong></p><ul><li><p><code>400 Bad Request</code>: Invalid input.</p></li><li><p><code>401 Unauthorized</code>: Missing or invalid authentication.</p></li><li><p><code>403 Forbidden</code>: Access denied.</p></li><li><p><code>404 Not Found</code>: Resource doesn&#8217;t exist.</p></li><li><p><code>500 Internal Server Error</code>: Something went wrong on the server.</p></li></ul></li><li><p><strong>Standardize Error Responses:</strong></p></li></ul><pre><code><code>{
  "error": {
    "code": "INVALID_INPUT",
    "message": "The 'email' field is required.",
    "details": {
      "field": "email",
      "expected": "A valid email address"
    }
  }
}</code></code></pre><ul><li><p><strong>Avoid Leaking Sensitive Information:</strong></p><ul><li><p>&#10060; <code>"message": "Database connection failed at line 123."</code></p></li><li><p>&#9989; <code>"message": "An internal error occurred. Please try again later."</code></p></li></ul></li></ul><div><hr></div><h3>5. Securing Your API</h3><p>APIs handle sensitive data, making security a top priority.</p><h4><strong>Best Practices</strong></h4><ol><li><p><strong>Authentication:</strong></p><ul><li><p>Use OAuth 2.0 for secure and flexible access control.</p></li></ul></li></ol><pre><code><code>Authorization: Bearer &lt;access_token&gt;</code></code></pre><ol><li><p><strong>Encryption:</strong></p><ul><li><p>Enforce HTTPS for all API traffic.</p></li></ul></li><li><p><strong>Rate Limiting:</strong></p><ul><li><p>Protect against abuse:</p></li></ul></li></ol><pre><code><code>X-RateLimit-Limit: 100
X-RateLimit-Remaining: 50</code></code></pre><div><hr></div><h3>6. Scale for Performance</h3><p>Scalability ensures your API remains reliable under increasing load.</p><h4><strong>Techniques</strong></h4><ul><li><p><strong>Caching:</strong></p><ul><li><p>Use <code>Cache-Control</code> and <code>ETag</code> headers to store frequently requested data.</p></li></ul></li><li><p><strong>Pagination:</strong></p><ul><li><p>Limit large datasets:</p></li></ul></li></ul><pre><code><code>GET /users?page=1&amp;limit=10</code></code></pre><ul><li><p><strong>Asynchronous Processing:</strong></p><ul><li><p>Use background jobs for long-running tasks, returning <code>202 Accepted</code> for immediate responses.</p></li></ul></li></ul><div><hr></div><h3>7. Document Everything</h3><p>Great documentation drives adoption. Include:</p><ul><li><p>Detailed descriptions of endpoints, parameters, and responses.</p></li><li><p>Real-world examples with tools like Swagger or Postman.</p></li><li><p>Error codes and their meanings.</p></li></ul><div><hr></div><p><strong>Closing Thoughts</strong></p><p>Designing a great REST API isn&#8217;t just about functionality&#8212;it&#8217;s about creating a delightful developer experience. By following these best practices, you&#8217;ll build APIs that are not only reliable and secure but also intuitive and scalable.</p><p>What&#8217;s your biggest challenge in API design? Let&#8217;s discuss&#8212;I&#8217;d love to hear from you!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Software Development in 2024: AI Dominance, Cloud Evolution, and the Rise of Low-Code]]></title><description><![CDATA[Explore the key trends that defined software development in 2024 and discover what&#8217;s next as we move into 2025, from AI-driven advancements to sustainability-focused solutions.]]></description><link>https://asyncthinking.com/p/software-development-in-2024-ai-dominance</link><guid isPermaLink="false">https://asyncthinking.com/p/software-development-in-2024-ai-dominance</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Fri, 27 Dec 2024 00:09:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fd69ca08-9bac-40f7-af30-cfc27fb1ac35_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As we approach the end of 2024, let's reflect on the transformative shifts in software development. From AI-driven innovations reshaping coding practices to the evolution of cloud computing and the rise of low-code platforms, this year has brought remarkable breakthroughs. Let's explore the key trends that define 2024 and set the stage for exciting developments in 2025.</p><h3><strong>AI/ML Dominance</strong></h3><p><strong>Artificial intelligence</strong> and <strong>machine learning</strong> transformed software development in 2024, evolving from helpful tools to essential parts of workflows.</p><ul><li><p><strong>Example:</strong> <strong>GitHub Copilot</strong> introduced more advanced <strong>context-aware code suggestions</strong>, predicting developer needs based on project history. <strong>Amazon CodeWhisperer</strong> expanded compatibility, integrating seamlessly with <strong>IDEs</strong> like <strong>IntelliJ</strong> and <strong>VS Code</strong>. Tools like <strong>Tabnine</strong> added <strong>real-time code quality checks</strong> powered by AI, while <strong>Diffblue Cover</strong> enabled deeper coverage analysis for automated unit tests.</p></li><li><p><strong>Why It Matters:</strong> 2024 marked the year <strong>AI tools evolved beyond automation</strong> to become <strong>strategic collaborators</strong>, significantly improving <strong>code quality</strong> and <strong>team productivity</strong>.</p></li></ul><h3><strong>Cloud Computing Evolution</strong></h3><p>The cloud ecosystem matured in 2024, emphasizing specialization and edge computing to create more robust and flexible cloud-native architectures.</p><ul><li><p><strong>Example:</strong> AWS enhanced <strong>Lambda at the Edge</strong>, enabling real-time invocation with sub-10ms latency, making it ideal for IoT applications and low-latency use cases. Google Cloud boosted <strong>Vertex AI&#8217;s integration with BigQuery</strong>, reducing ML model training time by 40%. Kubernetes adoption surged, aided by <strong>OpenCost 2.0</strong>, which optimized resource allocation, cutting costs for enterprises by up to 20%.</p></li><li><p><strong>Why It Matters:</strong> These advancements make cutting-edge computing accessible to developers at every scale, unlocking new possibilities for innovation and efficiency.</p></li></ul><h3><strong>The Rise of Low-Code/No-Code</strong></h3><p><strong>Low-code</strong> and <strong>no-code</strong> platforms gained sophistication, enabling non-technical users to create advanced, production-ready solutions.</p><ul><li><p><strong>Example:</strong> <strong>Bubble</strong> introduced <strong>AI-generated workflows</strong> that recommend automation based on user actions. <strong>Microsoft Power Apps</strong> unveiled <strong>advanced connectors</strong> to enterprise data lakes, enabling complex data manipulation without code. Startups used these platforms to launch <strong>MVPs</strong> with <strong>AI-integrated features</strong> in weeks rather than months.</p></li><li><p><strong>Why It Matters:</strong> 2024 saw <strong>low-code tools mature</strong> into platforms capable of handling <strong>enterprise-grade applications</strong>, <strong>levelling the playing field</strong> for innovation.</p></li></ul><h3><strong>Focus on Developer Experience (DX)</strong></h3><p>The <strong>developer community</strong> prioritized <strong>DX</strong> in 2024, introducing tools and practices that minimized friction and maximizing productivity.</p><ul><li><p><strong>Example:</strong> <strong>GitHub Codespaces</strong> enhanced <strong>live collaboration</strong>, allowing teams to work simultaneously on <strong>cloud-based IDEs</strong>. <strong>JetBrains Space</strong> integrated <strong>AI for task prioritization</strong>, reducing <strong>context-switching</strong>. <strong>ChatGPT plugins for DevOps</strong> automated troubleshooting, transforming <strong>incident response times</strong>.</p></li><li><p><strong>Why It Matters:</strong> <strong>Happy developers</strong> build better software, and investments in <strong>DX</strong> are increasingly viewed as <strong>essential for competitive advantage</strong>.</p></li></ul><h3><strong>Security at the Forefront</strong></h3><p>2024 reinforced <strong>security</strong> as a cornerstone of software development, driven by increasing <strong>cyber threats</strong> and <strong>regulatory demands</strong>.</p><ul><li><p><strong>Example:</strong> <strong>GitLab</strong> released a <strong>vulnerability prioritization tool</strong> that combines <strong>AI</strong> and <strong>real-world exploit likelihood</strong>. <strong>OWASP's 2024 updates</strong> introduced new guidelines for securing <strong>APIs</strong>, which gained rapid adoption. <strong>Snyk</strong> launched <strong>real-time security feedback</strong> during local development, identifying potential risks before code hits a repository.</p></li><li><p><strong>Why It Matters:</strong> Integrating <strong>security early</strong> in the lifecycle reduces <strong>vulnerabilities</strong> and builds <strong>user trust</strong>, a critical differentiator in today&#8217;s market.</p></li></ul><p><strong>Looking Ahead to 2025</strong></p><ul><li><p><strong>AI/ML Integration Deepens:</strong> Artificial Intelligence (AI) and Machine Learning (ML) are set to evolve from assistive tools to integral components of software development workflows. By 2025, AI-driven solutions will automate complex tasks such as debugging, refactoring, and managing technical debt, leading to more efficient and reliable codebases.</p></li><li><p><strong>Edge Computing Takes Center Stage:</strong> The proliferation of Internet of Things (IoT) devices and applications requiring real-time processing will drive the demand for edge computing solutions. Technologies like 5G will enable near-zero latency, making edge computing essential for applications in augmented reality (AR), virtual reality (VR), and autonomous systems.</p></li><li><p><strong>Quantum Computing on the Horizon:</strong> Quantum computing is advancing rapidly, with companies like IBM and Google making significant strides. By 2025, emerging Software Development Kits (SDKs) and cloud-based quantum services are expected to facilitate breakthroughs in optimization and security, offering unprecedented computational power for complex problem-solving.</p></li><li><p><strong>Sustainability Focus:</strong> As environmental concerns intensify, there will be a stronger emphasis on sustainable technology practices. Organizations are expected to invest in energy-efficient hardware, adopt cloud services powered by renewable energy, and implement green coding practices to minimize carbon footprints.</p></li></ul><p>Happy New Year, fellow developers!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Building Strong Foundations: A Developer’s Guide to Starting Software Projects]]></title><description><![CDATA[Unlock the best practices for building a solid code foundation, launching your MVP, and growing your startup.]]></description><link>https://asyncthinking.com/p/the-developers-guide-to-building</link><guid isPermaLink="false">https://asyncthinking.com/p/the-developers-guide-to-building</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Wed, 18 Dec 2024 04:35:02 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/81d401a8-e35f-4321-9b57-b2123165ac6e_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Starting a new project is one of the most exciting parts of software development. It&#8217;s a fresh slate full of possibilities. Whether it&#8217;s a side hustle, an internal company tool, or the foundation of your next startup, setting up your project correctly at the beginning can make all the difference. Proper initialization ensures your project stays maintainable, scalable, and enjoyable to work on as it grows.</p><p>Here&#8217;s a step-by-step guide to getting it right from the start.</p><div><hr></div><h4><strong>1. Define Clear Objectives and Scope</strong></h4><p>Before writing even a single line of code, clarify what you are building and why. Answer questions like:</p><ul><li><p>Who are your target users?</p></li><li><p>What specific problem are you solving for them?</p></li><li><p>What does the Minimum Viable Product (MVP) look like?</p></li></ul><p>Without a clear direction, it&#8217;s easy to get lost in feature creep or spend time solving problems that don&#8217;t matter. For inspiration, browse platforms like <a href="https://www.reddit.com/r/SomebodyMakeThis">r/SomebodyMakeThis</a>, where users post real-world problems they&#8217;d like solved. This can spark ideas and give you insight into unmet needs.</p><div><hr></div><h4><strong>2. Choose a Tech Stack That Fits</strong></h4><p>Your tech stack should align with your project&#8217;s goals, scalability needs, and your team&#8217;s expertise. Avoid chasing trends; instead, prioritize tools you&#8217;re comfortable with and that are proven in the domain. Here are a few examples:</p><ul><li><p><strong>Web Applications</strong>: React (front-end), Node.js or Django (back-end), PostgreSQL (database).</p></li><li><p><strong>Mobile Apps</strong>: Flutter (cross-platform) or native development with Swift (iOS) and Kotlin (Android).</p></li><li><p><strong>Data-Intensive Projects</strong>: Python with frameworks like Flask or FastAPI and a NoSQL database such as MongoDB.</p></li><li><p><strong>Real-Time Systems</strong>: Use WebSockets with libraries like Socket.IO or frameworks like NestJS and Django Channels.</p></li></ul><p>Starting with tools you know ensures you&#8217;re productive from the beginning, even if you switch or expand your stack later.</p><div><hr></div><h4><strong>3. Set Up Version Control and Collaboration Tools</strong></h4><p>Using Git from the very start is non-negotiable. Set up a remote repository on platforms like GitHub, GitLab, or Bitbucket. A well-defined branching strategy&#8212;like Git Flow&#8212;keeps your codebase organized and simplifies collaboration.</p><p>Complement version control with tools that streamline teamwork:</p><ul><li><p><strong>Code Reviews</strong>: Use pull requests to ensure high-quality code and collective ownership.</p></li><li><p><strong>Task Management</strong>: Platforms like Jira, Notion, or Trello help you stay on top of priorities and deadlines.</p></li><li><p><strong>CI/CD</strong>: Automate testing and deployments with tools like GitHub Actions, CircleCI, or Jenkins.</p></li></ul><div><hr></div><h4><strong>4. Establish a Scalable Codebase Structure</strong></h4><p>A well-organized codebase prevents chaos as your project grows. Here&#8217;s an example of a clean folder structure for a web application:</p><pre><code><code>project/
  src/
    components/      # Reusable UI components
    pages/           # Page-level components
    services/        # API calls, business logic
    utils/           # Helper functions
    hooks/           # Custom React hooks 
    store/           # State management (e.g., Redux, Context API)
    assets/          # Images, fonts, icons
    styles/          # Global styles, CSS/SASS files
    tests/           # Unit and integration tests
  public/            # Static assets (images, fonts, etc.)
  config/            # Configuration files for build tools (Webpack etc)
  .env               # Environment variables (API keys, app config)
  README.md          # Project documentation
  package.json       # Dependency management, scripts
  tsconfig.json      # TypeScript configuration (if applicable)
  .gitignore         # Files and directories to ignore in version     control

Backend codebase Structure

project/
  src/
    controllers/      # Express or other framework controllers
    models/           # Database models
    routes/           # API endpoint routing
    services/         # Business logic and helpers
    middlewares/      # Custom middlewares
    config/           # Configuration files (e.g., database connections, JWT settings)
    tests/            # Unit and integration tests
  .env                # Sensitive keys, tokens
  .gitignore          # Ignore unnecessary files/folders
  app.js / server.js  # Main entry point for the application</code></code></pre><p>Each folder has a single responsibility, making the codebase easier to navigate and extend. Modularization is key&#8212;group functionality logically so changes in one area don&#8217;t inadvertently break another.</p><div><hr></div><h4><strong>5. Write a Comprehensive README and Contribution Guide</strong></h4><p>Your README is the project&#8217;s first impression. A good README should:</p><ul><li><p>Clearly describe the project&#8217;s purpose.</p></li><li><p>Provide installation and setup instructions.</p></li><li><p>List prerequisites (e.g., Node.js version).</p></li><li><p>Explain how to run and test the project locally.</p></li></ul><p>If you&#8217;re planning to make your project open source, add a CONTRIBUTING.md file to guide others on how to contribute effectively. Use examples from well-maintained repositories like <a href="https://github.com/facebook/react">React</a> or <a href="https://github.com/expressjs/express">Express</a> for inspiration.</p><div><hr></div><h4><strong>6. Automate Early and Often</strong></h4><p>Automation saves time and reduces human error. Here&#8217;s where to focus:</p><ul><li><p><strong>Linting and Formatting</strong>: Use tools like ESLint or Prettier to enforce consistent code styles.</p></li><li><p><strong>Testing</strong>: Start with basic unit tests using Jest, Mocha, or PyTest. Expand to integration and end-to-end tests as your project grows.</p></li><li><p><strong>Deployment</strong>: Use containerization tools like Docker to ensure consistency across environments. Automate deployments with platforms like Vercel, Netlify, or AWS CodePipeline.</p></li></ul><p>Setting up automation might feel like overkill early on, but it pays off as your project scales.</p><div><hr></div><h4><strong>7. Prioritize Security From Day One</strong></h4><p>Security is often overlooked in the rush to get things working but is critical to prevent future vulnerabilities. Best practices include:</p><ul><li><p><strong>Environment Variables</strong>: Store sensitive information (e.g., API keys) in <code>.env</code> files and never hardcode them.</p></li><li><p><strong>Authentication</strong>: Use secure methods like OAuth2 or JWT for user authentication.</p></li><li><p><strong>Dependencies</strong>: Regularly audit your dependencies using tools like Dependabot or Snyk.</p></li></ul><p>Implement HTTPS for web applications from the start to protect data in transit.</p><div><hr></div><h4><strong>8. Build for the Future, but Start Simple</strong></h4><p>It&#8217;s tempting to overengineer, but simplicity should guide your decisions early on. For example:</p><ul><li><p>Don&#8217;t implement a full microservices architecture for a small MVP.</p></li><li><p>Use an off-the-shelf authentication service (e.g., Auth0) instead of rolling your own.</p></li><li><p>Avoid pre-optimizing performance until it&#8217;s necessary.</p></li></ul><p>Focus on delivering value quickly, then iterate and scale as needed. For instance, if your database queries slow down as usage grows, add indexing or caching layers like Redis. But start with a basic, functional system.</p><div><hr></div><h4><strong>9. Stay Inspired and Keep Learning</strong></h4><p>Starting a project is just the beginning. To stay motivated, continuously seek out inspiration and opportunities to grow. Follow tech blogs, explore developer communities, or look for problem-solving forums where others share unique ideas. Participating in hackathons or asking yourself, <em>&#8220;What&#8217;s something I wish existed?&#8221;</em> can also spark new perspectives.</p><p>By staying curious and open to new ideas, you'll keep your momentum high and fuel your creativity throughout the project.</p><div><hr></div><p>Starting a new project is like planting a seed. With the right foundation and care, it can grow into something impactful. By following these best practices, you can set yourself up for success and ensure your project is both enjoyable to work on and resilient to future challenges.</p><p>What ideas are you excited to bring to life? Let&#8217;s discuss in the comments!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Mastering Effective Code Reviews: Strategies for Developers and Team Leads]]></title><description><![CDATA[Code reviews are a cornerstone of collaborative software development, fostering better code quality, knowledge sharing, and team cohesion.]]></description><link>https://asyncthinking.com/p/conducting-an-effective-code-review</link><guid isPermaLink="false">https://asyncthinking.com/p/conducting-an-effective-code-review</guid><dc:creator><![CDATA[Naresh Sharma]]></dc:creator><pubDate>Thu, 12 Dec 2024 06:15:37 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4cde2af9-fb62-4ca8-86b4-559bb5d4140d_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Code reviews are a cornerstone of collaborative software development, fostering better code quality, knowledge sharing, and team cohesion. An effective review goes beyond spotting issues; it ensures the code aligns with team standards and project goals. Here&#8217;s a detailed guide to conducting a code review that adds real value.</p><h2><strong>1. Set the Right Tone</strong></h2><p>Code reviews are opportunities for collaboration, not criticism. Approach them with the intent to improve the code while fostering a positive relationship with the author. Here are some tips:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><ul><li><p><strong>Be Respectful:</strong> Use language that shows empathy and respect. For example, say, &#8220;Could we simplify this logic?&#8221; rather than, &#8220;This is unnecessarily complex.&#8221;</p></li><li><p><strong>Be Constructive:</strong> Frame your feedback as suggestions rather than directives. Phrases like &#8220;Have you considered...&#8221; or &#8220;Would it make sense to...&#8221; are more collaborative.</p></li><li><p><strong>Acknowledge Good Work:</strong> Call out parts of the code you find well-written, efficient, or particularly clever. This motivates the author and fosters goodwill.</p></li></ul><div><hr></div><h2><strong>2. Understand the Context</strong></h2><p>Before diving into the code, ensure you understand why the pull request (PR) exists and what it aims to achieve:</p><ul><li><p><strong>Read the Description:</strong> Thoroughly review the PR title and description. Look for explanations about the change&#8217;s purpose and implementation.</p></li><li><p><strong>Review Linked Issues or Tickets:</strong> Check references to related tasks or issues to ensure you&#8217;re aligned with the project&#8217;s goals.</p></li><li><p><strong>Understand the Bigger Picture:</strong> Consider how the change fits into the overall system and whether it aligns with long-term architectural plans.</p></li></ul><div><hr></div><h2><strong>3. Evaluate Code Quality</strong></h2><p>Assessing the quality of the code is central to any review. Keep these criteria in mind:</p><h3><strong>a. Readability and Maintainability</strong></h3><ul><li><p>Is the code easy to understand?</p></li><li><p>Are variable and function names descriptive?</p></li><li><p>Is the logic straightforward and broken into digestible chunks?</p></li></ul><h3><strong>b. Adherence to Standards</strong></h3><ul><li><p>Does the code follow team style guides and conventions?</p></li><li><p>Are there unnecessary comments or overly complex structures that could be simplified?</p></li></ul><h3><strong>c. Modular Design</strong></h3><ul><li><p>Is the code modular and reusable?</p></li><li><p>Are functions or classes single-responsibility and well-encapsulated?</p></li></ul><div><hr></div><h2><strong>4. Test the Code</strong></h2><p>Verifying that the code works as expected is critical. This step goes beyond automated tests:</p><ul><li><p><strong>Run the Branch Locally:</strong> If possible, pull the branch and test the functionality in a realistic environment.</p></li><li><p><strong>Check Edge Cases:</strong> Look for scenarios the author might not have considered. Does the code handle invalid inputs, errors, or unusual user behavior?</p></li><li><p><strong>Assess Performance:</strong> Test the code under conditions it&#8217;s likely to face in production. Are there bottlenecks or inefficiencies?</p></li></ul><div><hr></div><h2><strong>5. Focus on Key Areas</strong></h2><p>A good code review doesn&#8217;t nitpick minor issues while missing critical problems. Focus on:</p><ul><li><p><strong>Logic Correctness:</strong> Verify that the code&#8217;s logic aligns with requirements and produces expected outcomes.</p></li><li><p><strong>Error Handling:</strong> Ensure the code gracefully handles errors and edge cases without exposing vulnerabilities.</p></li><li><p><strong>Security:</strong> Check for potential security risks, such as unchecked inputs or improper access controls.</p></li></ul><div><hr></div><h2><strong>6. Provide Clear and Actionable Feedback</strong></h2><p>The way you articulate your feedback can significantly impact the review&#8217;s effectiveness:</p><ul><li><p><strong>Be Specific:</strong> Instead of saying, &#8220;This isn&#8217;t clear,&#8221; point to a specific line and explain why it&#8217;s unclear.</p></li><li><p><strong>Use Examples:</strong> Offer alternatives or suggestions. For instance, &#8220;Consider using a ternary operator here for simplicity.&#8221;</p></li><li><p><strong>Prioritize:</strong> Distinguish between critical issues that must be addressed before merging and optional improvements.</p></li></ul><div><hr></div><h2><strong>7. Use the Right Tools</strong></h2><p>Take advantage of tools that streamline the review process:</p><ul><li><p><strong>Integrated Code Review Platforms:</strong> Tools like GitHub, GitLab, or Bitbucket provide in-line comments and change tracking.</p></li><li><p><strong>Linting and Formatting Tools:</strong> Ensure automated tools are in place to catch style and syntax issues, allowing you to focus on higher-level concerns.</p></li><li><p><strong>Testing Frameworks:</strong> Use automated tests to confirm functionality, leaving manual testing for edge cases and usability.</p></li></ul><div><hr></div><h2><strong>8. Know When to Approve or Reject</strong></h2><p>Not every PR will be perfect, but it&#8217;s important to know when it&#8217;s &#8220;good enough&#8221; to merge:</p><ul><li><p><strong>Approve:</strong> If the code meets standards, aligns with project goals, and any major concerns have been addressed.</p></li><li><p><strong>Request Changes:</strong> When critical issues remain unresolved or the code introduces risks to the project.</p></li><li><p><strong>Add Comments:</strong> For minor suggestions that don&#8217;t block the merge.</p></li></ul><div><hr></div><h2><strong>Why Effective Code Reviews Matter</strong></h2><p>Effective code reviews:</p><ul><li><p><strong>Improve Code Quality:</strong> They catch bugs, enforce standards, and ensure maintainability.</p></li><li><p><strong>Facilitate Knowledge Sharing:</strong> They expose team members to different parts of the codebase, fostering a shared understanding.</p></li><li><p><strong>Build Team Culture:</strong> Collaborative and respectful reviews strengthen trust and teamwork.</p></li></ul><p>By following these principles, you can make your code reviews both productive and positive, ultimately leading to better outcomes for your projects and team.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://asyncthinking.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Async Thinking! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>