<?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[The T-Shaped Dev]]></title><description><![CDATA[A newsletter sharing practical tips on React, Node, Software Architecture, and AI. Elevate your Full-Stack JavaScript skills to the next level!]]></description><link>https://thetshaped.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!9lD-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f66bb7c-c96f-4c71-ba2d-d561152c83a2_600x600.png</url><title>The T-Shaped Dev</title><link>https://thetshaped.dev</link></image><generator>Substack</generator><lastBuildDate>Fri, 15 May 2026 11:37:40 GMT</lastBuildDate><atom:link href="https://thetshaped.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Petar Ivanov]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[petarivanovv9@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[petarivanovv9@substack.com]]></itunes:email><itunes:name><![CDATA[Petar Ivanov]]></itunes:name></itunes:owner><itunes:author><![CDATA[Petar Ivanov]]></itunes:author><googleplay:owner><![CDATA[petarivanovv9@substack.com]]></googleplay:owner><googleplay:email><![CDATA[petarivanovv9@substack.com]]></googleplay:email><googleplay:author><![CDATA[Petar Ivanov]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Stacked PRs: The Code Review Workflow That Changed How I Ship Features]]></title><description><![CDATA[Stacked diffs, the workflow Meta and Google ship on. (7 min)]]></description><link>https://thetshaped.dev/p/stacked-prs-the-code-review-workflow-that-makes-difference</link><guid isPermaLink="false">https://thetshaped.dev/p/stacked-prs-the-code-review-workflow-that-makes-difference</guid><pubDate>Wed, 13 May 2026 02:19:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4c86b65d-f8b0-4097-9db0-b44af1c2a343_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 30,000+ Engineers learning production-ready React.js, Node.js, and Software Architecture:</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><p>I used to think waiting on code reviews was just part of the job.</p><p>Finish a feature, open a PR, sit on it for a day or two. Context-switch to something unrelated, or branch off the unreviewed PR and start the next piece. </p><p>That second branch was technically a stack. Just an undisciplined one. </p><p>When PR 1 came back with feedback, my &#8220;head start&#8221; on PR 2 turned into a rebase nightmare.</p><p>The first time I worked with a properly stacked PR workflow, the difference was immediate.</p><p>I was still building on top of unreviewed work, but the rebases stopped hurting, the reviewers stopped drowning, and nothing got lost between layers.</p><p>Here&#8217;s what I wish someone had walked me through.</p><ul><li><p><em><a href="https://thetshaped.dev/p/c870c171-a85e-4cd9-90d9-dd671aad1ab5">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><h2><strong><a href="https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer">The AI code reviewer that thinks like a senior engineer (Partner)</a></strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JCm6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!JCm6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!JCm6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!JCm6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JCm6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png" width="671" height="671" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1200,&quot;width&quot;:1200,&quot;resizeWidth&quot;:671,&quot;bytes&quot;:736323,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/196755788?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.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_!JCm6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!JCm6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!JCm6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!JCm6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16ab503c-b8b1-4617-85a0-c8ab19659e44_1200x1200.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>AI writes code faster than teams can review. </p><p><a href="https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer">Codacy</a> understands your codebase, catches real issues and intent gaps, and hands fixes to your agent.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer&quot;,&quot;text&quot;:&quot;Run it on your next PR &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer"><span>Run it on your next PR &#8594;</span></a></p><p>(Thanks to <a href="https://www.codacy.com/ai-reviewer?utm_campaign=386376943-AI%20Code%20Review%20%7C%20Newsletters&amp;utm_source=TheTShapedDev&amp;utm_medium=partnership&amp;utm_term=ai-reviewer">Codacy</a> for partnering on this post.)</p><div><hr></div><h2><strong>What Stacked PRs Are (and Aren&#8217;t)</strong></h2><p>A stacked PR, also called a stacked diff, is a pull request whose base branch is another PR&#8217;s branch instead of <code>main</code>.</p><p>Instead of one big PR with 1,200 lines across 15 files, you break the work into a chain:</p><ul><li><p><strong>PR 1</strong> &#8594; base: <code>main</code>. Ships the data model change.</p></li><li><p><strong>PR 2</strong> &#8594; base: PR 1&#8217;s branch. Ships the API layer.</p></li><li><p><strong>PR 3</strong> &#8594; base: PR 2&#8217;s branch. Ships the UI.</p></li></ul><p>Each PR is small, focused, and independently reviewable.</p><p>They merge bottom-up: PR 1 lands first, then PR 2, then PR 3. (More on the retargeting magic in a minute.)</p><p>This isn&#8217;t about creating more work. It&#8217;s about making the unit of review smaller and keeping yourself unblocked.</p><p>What it isn&#8217;t: a rule that says &#8220;one commit per PR&#8221;. It isn&#8217;t about turning your git history into art. It&#8217;s a practical workflow for shipping complex features without sitting on your hands.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jYw_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jYw_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 424w, https://substackcdn.com/image/fetch/$s_!jYw_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 848w, https://substackcdn.com/image/fetch/$s_!jYw_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 1272w, https://substackcdn.com/image/fetch/$s_!jYw_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jYw_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png" width="1456" height="749" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:749,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:300614,&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://thetshaped.dev/i/196755788?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.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_!jYw_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 424w, https://substackcdn.com/image/fetch/$s_!jYw_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 848w, https://substackcdn.com/image/fetch/$s_!jYw_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.png 1272w, https://substackcdn.com/image/fetch/$s_!jYw_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3069dcc-b1f3-4e42-a38e-48c91fac4482_2820x1450.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><div><hr></div><h2><strong>Why Long-Lived Feature Branches Are the Real Problem</strong></h2><p>The traditional PR workflow looks like this:</p><ol><li><p>Branch off <code>main</code></p></li><li><p>Build the whole feature</p></li><li><p>Open one big PR</p></li><li><p>Wait</p></li><li><p>Address feedback (which has now diverged from what you remember)</p></li><li><p>Merge</p></li></ol><p>The problems compound.</p><p><strong>Big PRs get shallow reviews.</strong> Nobody reviews 1,200 lines of code carefully. They scan for obvious bugs, eyeball the logic, approve. The subtle stuff slips through.</p><p><strong>You&#8217;re blocked while you wait.</strong> If the next piece depends on this one, you&#8217;re stuck. Or you do what I used to do &#8212; branch off the unreviewed PR with no plan for handling the rebases later.</p><p><strong>Feedback loops are long.</strong> A comment lands on day 2. You&#8217;ve moved on mentally. Now you reload the context on the code you wrote 48 hours ago.</p><p><strong>Merge conflicts compound.</strong> The longer a branch lives, the more it diverges from <code>main</code>. Every merge becomes a negotiation.</p><p>The idea is simple:</p><blockquote><p><strong>A feature isn&#8217;t the right unit of review. A focused change is.</strong></p></blockquote><div><hr></div><h2><strong>A Concrete Example</strong></h2><p>You&#8217;re building user authentication: a new <code>users</code> table, a REST endpoint, and a login form.</p><p><strong>Traditional approach</strong>:</p><ul><li><p>One branch: <code>feature/auth</code></p></li><li><p>One PR: ~1,200 lines, three subsystems, no clear entry point for a reviewer</p></li></ul><p><strong>Stacked approach</strong> (same total work, split into reviewable pieces):</p><ul><li><p><code>auth/01-users-table</code> &#8594; base <code>main</code> (~200 lines, schema + migration)</p></li><li><p><code>auth/02-auth-endpoint</code> &#8594; base <code>auth/01-users-table</code> (~400 lines, <code>POST /login</code>)</p></li><li><p><code>auth/03-login-form</code> &#8594; base <code>auth/02-auth-endpoint</code> (~600 lines, React form + hook)</p></li></ul><p>You open all three at once. Reviewers can start on PR 1 immediately. While they review, you keep working. When PR 1 gets feedback, you fix it on <code>auth/01-users-table</code> and rebase the rest of the stack on top.</p><p>The key shift: you don&#8217;t wait. You keep building on top of pending work, and reviews come in asynchronously.</p><div><hr></div><h2><strong>Cascading Rebases: The Hard Part</strong></h2><p>Most posts about stacked PRs hand-wave this part. It&#8217;s actually where most of the pain lives.</p><p>This is what happens during review, before anything merges.</p><p>PR 1 gets feedback. You change history on <code>auth/01-users-table</code> &#8212; say, by amending the commit or rebasing, and every PR above it now points at a stale parent. You need to rebase the rest of the stack on top of the updated PR 1, in order.</p><p><em>If &#8220;rebase&#8221; is fuzzy: it means &#8220;take my commits, lift them off their old base, and stick them on top of a new one&#8221;. The commits get rewritten: same diff, new parent, new hash.</em></p><p>Manually, that&#8217;s:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Update PR 1 (amend keeps the PR to one clean commit)
git checkout auth/01-users-table
# ...address feedback...
git commit --amend
git push --force-with-lease

# Rebase PR 2 onto the updated PR 1
git checkout auth/02-auth-endpoint
git rebase auth/01-users-table
git push --force-with-lease

# Rebase PR 3 onto the updated PR 2
git checkout auth/03-login-form
git rebase auth/02-auth-endpoint
git push --force-with-lease</code></pre></div><p>Three things to remember:</p><ol><li><p><code>--force-with-lease</code><strong>, not </strong><code>--force</code><strong>.</strong> It refuses to overwrite remote changes you haven&#8217;t seen, saving you the day a teammate pushes a commit to your branch.</p></li><li><p><strong>Conflicts compound.</strong> If your edit to PR 1 collides with PR 2, you&#8217;ll resolve it during the PR 2 rebase. If it also collides with PR 3, you&#8217;ll resolve it again during PR 3.</p></li><li><p><strong>If you see weird duplicate commits or unexpected conflicts</strong>, plain <code>git rebase</code> got confused about where PR 2 starts. Drop to the explicit form: <code>git rebase --onto auth/01-users-table @{u} auth/02-auth-endpoint</code> &#8212; replays only the commits that are on the remote PR 2 branch but not on the new PR 1.</p></li></ol><p>Once you've manually cascaded a few times, the value clicks.</p><p>There are many tools out there that automate this part. Pick whichever tool matches your team's appetite for new tooling.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><strong>When to Use Stacked PRs (and When Not To)</strong></h2><p><strong>Use them when:</strong></p><ul><li><p>A feature naturally layers: schema &#8594; API &#8594; UI</p></li><li><p>Any one part is large enough to deserve a focused review on its own</p></li><li><p>You want to keep moving while reviews come in</p></li><li><p>Your team has slow review cycles</p></li></ul><p><strong>Skip them when:</strong></p><ul><li><p>The change is genuinely atomic (a one-line fix, a config update)</p></li><li><p>The layers are so interdependent that splitting them adds noise instead of clarity</p></li><li><p>The team has never done this and isn&#8217;t ready for the tooling overhead</p></li></ul><p>The rule I use:</p><blockquote><p><strong>If a PR has more than ~300 lines of substantive logic, I ask whether it can be split.<br>Not every PR needs to be, but the question is worth asking every time.</strong></p></blockquote><div><hr></div><h2><strong>Practical Tips for Getting Started</strong></h2><p><strong>1. Start with the mental model, not the tooling.</strong> Do one stack by hand using the commands above. Feel the workflow. Understand why the tooling exists before installing it.</p><p><strong>2. Name your branches clearly.</strong> Use a prefix pattern: <code>auth/01-users-table</code>, <code>auth/02-api</code>, <code>auth/03-ui</code>. The chain becomes visible without looking at the PR graph.</p><p><strong>3. Write context-rich PR descriptions.</strong> Each PR should explain what it does in isolation, and where it sits in the stack. &#8220;This PR adds the schema. PR 2 adds the API. PR 3 adds the UI.&#8221; Reviewers should never have to reverse-engineer the intent.</p><p><strong>4. Keep each PR independently runnable where you can.</strong> If PR 2 can be tested without PR 1 being merged &#8212; great. If not, say so in the description. The more each layer stands alone, the easier the reviews get.</p><p><strong>5. Batch your feedback fixes.</strong> If PRs 1 and 2 both get comments, fix both before rebasing the stack. One cascading rebase beats two.</p><p><strong>6. Use </strong><code>--force-with-lease</code><strong>, never </strong><code>--force</code><strong>.</strong> This is the one-line rule that saves you from clobbering a teammate&#8217;s commit.</p><div><hr></div><h2><strong>The Culture Shift That Actually Matters</strong></h2><p>Tooling is secondary. The real shift is in how the team thinks about review.</p><p>Big PRs are a symptom of a team that has implicitly agreed that waiting is normal.</p><p>The author doesn&#8217;t want to open multiple PRs (more overhead). The reviewer doesn&#8217;t want to navigate a stack (more context).</p><p>Everyone tolerates the friction because it&#8217;s symmetric: everybody suffers the same way.</p><p>Stacked PRs break that. You do a bit more thinking upfront: splitting the work into layers. The reviewer gets a much easier job. Reviews come back faster, feedback is sharper, and merging hurts less.</p><p>Once you&#8217;ve shipped this way for a few weeks, the old workflow feels like trying to write a function with no return statement: technically possible, but you&#8217;re fighting the tool the whole way.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PRvR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PRvR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 424w, https://substackcdn.com/image/fetch/$s_!PRvR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 848w, https://substackcdn.com/image/fetch/$s_!PRvR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 1272w, https://substackcdn.com/image/fetch/$s_!PRvR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PRvR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png" width="601" height="1071.423860329777" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1838,&quot;width&quot;:1031,&quot;resizeWidth&quot;:601,&quot;bytes&quot;:3928603,&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://thetshaped.dev/i/196755788?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f44d20a-a8f4-4f59-af35-61a5d93b0d19_1056x1840.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_!PRvR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 424w, https://substackcdn.com/image/fetch/$s_!PRvR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 848w, https://substackcdn.com/image/fetch/$s_!PRvR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.png 1272w, https://substackcdn.com/image/fetch/$s_!PRvR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fd129-04b6-4828-a770-e33928fbec99_1031x1838.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><div><hr></div><h2><strong>&#128204; TL;DR</strong></h2><ul><li><p><strong>Stacked PRs</strong> break a feature into a chain of small, focused PRs, each one&#8217;s base branch is the PR below it</p></li><li><p>They keep you unblocked: you keep building while reviews come in asynchronously</p></li><li><p>The hard part is <strong>cascading rebases</strong> when an earlier layer changes; tooling solves this</p></li><li><p>The workflow needs a small culture shift: many small PRs instead of a few big ones</p></li><li><p>Do one stack manually before touching tooling, that&#8217;s how you learn what the tool is buying you</p></li></ul><p>Thanks for reading, and stay awesome! &#128591;</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/stacked-prs-the-code-review-workflow-that-makes-difference?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/stacked-prs-the-code-review-workflow-that-makes-difference?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[20 Mistakes That Quietly Destroy JavaScript/TypeScript Codebases (Part 2)]]></title><description><![CDATA[Common JS/TS patterns that feel fine until they don't. 11 mistakes, before/after code for each. (11 min)]]></description><link>https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns-async-performance-testing</link><guid isPermaLink="false">https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns-async-performance-testing</guid><pubDate>Sat, 09 May 2026 02:19:51 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/17c7e008-b603-4780-8cac-e0a51bf93617_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 30,000+ Engineers learning production-ready React.js, Node.js, and Software Architecture:</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><p>In <a href="https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns">Part 1</a>, I covered the foundational mistakes: type safety, error handling, and architecture. The kind that shapes how your codebase grows.</p><p>This post covers the rest: the runtime and code quality mistakes that don't break your build but break your production. Code Hygiene, Async &amp; Performance, Testing &amp; Validation.</p><ul><li><p><em><a href="https://thetshaped.dev/p/c2e812da-42ec-4385-9073-f0c4e1675bba">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><h2><strong><a href="https://brdta.com/star_cli_t-shaped_dev">Give Your AI Agent Eyes on the Web (Partner)</a></strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://brdta.com/star_cli_t-shaped_dev" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bzng!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!bzng!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!bzng!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!bzng!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bzng!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1467094,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://brdta.com/star_cli_t-shaped_dev&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/193244550?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.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_!bzng!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!bzng!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!bzng!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!bzng!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d056cdc-5d8b-46f1-bea9-13f3bfb20e38_1376x768.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>MCP servers eat 72% of your agent&#8217;s context window before it reads a single user message. There&#8217;s a simpler way.</p><p><a href="https://brdta.com/star_cli_t-shaped_dev">Bright Data CLI</a> gives coding agents like Claude Code, Cursor, and Copilot direct access to real-time web data - from the terminal. No MCP schema bloat. No server setup. Just one command:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">brightdata scrape https://any-website.com &#8594; structured JSON</code></pre></div><p>Scrape any URL with automatic CAPTCHA bypass. Search Google/Bing/Yandex. Extract structured data from 40+ platforms (Amazon, LinkedIn, Instagram, TikTok, YouTube, Reddit, and more).</p><p>One install. Works with 46+ AI agents. 10-32x cheaper than MCP for the same tasks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://brdta.com/star_cli_t-shaped_dev&quot;,&quot;text&quot;:&quot;&#11088; Star on GitHub &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://brdta.com/star_cli_t-shaped_dev"><span>&#11088; Star on GitHub &#8594;</span></a></p><p>(Thanks to <a href="https://brdta.com/star_cli_t-shaped_dev">BrightData</a> for partnering on this post.)</p><div><hr></div><h2>12. Mutating Function Parameters</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">interface Order {
  id: string;
  total: number;
  discountApplied?: boolean;
}

// &#10060; Surprise mutation
function applyDiscount(order: Order, discount: number) {
  order.total *= 1 - discount / 100; // Mutates the original!
  order.discountApplied = true;
  return order;
}</code></pre></div><p>The caller passes an order object and gets it back mutated. Every other reference to that object now sees the changed values. This creates action-at-a-distance bugs that are nearly impossible to trace.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Return a new object
function applyDiscount(order: Order, discount: number): Order {
  return {
    ...order,
    total: order.total * (1 - discount / 100),
    discountApplied: true,
  };
}</code></pre></div><p>Functions that return new values instead of mutating inputs are easier to test, easier to reason about, and compose naturally. </p><p>Use <code>readonly</code> parameter types to enforce this at compile time.</p><div><hr></div><h2>13. Leaking Memory with Uncleared Listeners, Timers, and Subscriptions</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Event listener that outlives the thing it's attached to
class WebSocketManager {
  private ws?: WebSocket;
  private handleMessage = (event: MessageEvent) =&gt; { /* ... */ };
  private handleError = (event: Event) =&gt; { /* ... */ };

  connect(url: string) {
    this.ws = new WebSocket(url);
    this.ws.addEventListener("message", this.handleMessage);
    this.ws.addEventListener("error", this.handleError);

    // Health check every 30 seconds &#8212; but nobody ever stops it
    setInterval(() =&gt; this.ping(), 30_000);
  }

  ping() { /* ... */ }
}</code></pre></div><p>The <code>setInterval</code> runs forever. The event listeners hold references to <code>this</code>, keeping the entire class instance (and everything it references) alive in memory.</p><p>Multiply this by reconnections and you&#8217;ve got a slow leak that crashes your Node.js process at 3am on a Saturday.</p><p>The tricky part: memory leaks don&#8217;t show up in tests. They show up after hours or days of uptime.</p><p>If your Node.js process memory keeps climbing when traffic is flat, run <code>node --inspect</code> and take heap snapshots 5 minutes apart &#8212; growing object counts point straight at the leak.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Track everything. Clean up everything.
class WebSocketManager {
  private ws?: WebSocket;

  // Arrow-function class fields: auto-bound `this` AND stable references
  // so removeEventListener can actually find them.
  private handleMessage = (event: MessageEvent) =&gt; { /* ... */ };
  private handleError = (event: Event) =&gt; { /* ... */ };
  private pingInterval?: ReturnType&lt;typeof setInterval&gt;;

  connect(url: string) {
    this.ws = new WebSocket(url);
    this.ws.addEventListener("message", this.handleMessage);
    this.ws.addEventListener("error", this.handleError);
    this.pingInterval = setInterval(() =&gt; this.ping(), 30_000);
  }

  disconnect() {
    this.ws?.removeEventListener("message", this.handleMessage);
    this.ws?.removeEventListener("error", this.handleError);
    clearInterval(this.pingInterval);
    this.ws?.close();
  }

  ping() { /* ... */ }
}</code></pre></div><p>Every <code>addEventListener</code> needs a <code>removeEventListener</code>. Every <code>setInterval</code> needs a <code>clearInterval</code>. Every subscription needs an <code>unsubscribe</code>.</p><blockquote><p>If your class has a <code>connect</code> or <code>start</code> &#8212; it needs a <code>disconnect</code> or <code>stop</code>. No exceptions.</p></blockquote><p>One snag worth flagging: <code>removeEventListener</code> only removes a handler when you pass the <em>same function reference</em> that was added. Regular methods don&#8217;t auto-bind.</p><p>If you write <code>addEventListener("message", this.handleMessage.bind(this))</code>, the <code>.bind</code> returns a <em>new</em> function each time and the removal silently no-ops.</p><p>Arrow-function class fields (shown above) give you both a stable reference and a <code>this</code> that points at the instance.</p><div><hr></div><h2>14. Never Cancelling Async Operations</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Fetch that can't be stopped
async function searchUsers(query: string) {
  const response = await fetch(`/api/users?q=${query}`);
  return response.json();
}

// User types "al", "ali", "alic", "alice" &#8212; 4 requests fly out
// The response for "al" might arrive AFTER "alice"
// Now your UI shows results for "al" while the search box says "alice"</code></pre></div><p>No cancellation means wasted requests, race conditions, and stale data rendering on screen.</p><p>In React, this is the #1 cause of "my component shows old data" bugs.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; AbortController &#8212; the native cancellation primitive
function searchUsers(query: string, signal?: AbortSignal) {
  return fetch(`/api/users?q=${query}`, { signal }).then((r) =&gt; r.json());
}

// In the caller &#8212; cancel the previous request before starting a new one
let controller: AbortController | null = null;

function onSearchChange(query: string) {
  controller?.abort(); // Cancel whatever's in flight
  controller = new AbortController();

  searchUsers(query, controller.signal)
    .then(setResults)
    .catch((err) =&gt; {
      if (err.name !== "AbortError") throw err; // Ignore expected aborts
    });
}</code></pre></div><p><code>AbortController</code> works with <code>fetch</code>, Node.js streams, database drivers, and most async APIs.</p><p>In React, use it inside <code>useEffect</code> cleanup.</p><p>In Node.js, pass it to long-running operations so callers can cancel them.</p><p>For CPU-bound or polling code that doesn't natively accept a signal, check <code>signal.aborted</code> between iterations and bail out early. If your async function doesn't accept a signal, it's a foot-gun waiting to fire.</p><div><hr></div><h2>15. No HTTP / fetch Timeouts</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; A fetch with no timeout is a fetch that can hang forever
async function getUser(id: string) {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}</code></pre></div><p><code>fetch</code> has no default timeout. If the upstream service is slow or hung, the request waits indefinitely.</p><p>On a server under load, that means every slow request consumes a connection and a chunk of your concurrency budget &#8212; slow upstreams cascade into your service hanging too.</p><p>Same shape on the client: the spinner spins forever and the user reloads the tab.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; AbortSignal.timeout &#8212; the modern, native way
async function getUser(id: string) {
  const response = await fetch(`/api/users/${id}`, {
    signal: AbortSignal.timeout(5000), // 5s &#8212; fails fast if the server doesn't respond
  });
  return response.json();
}</code></pre></div><p><code>AbortSignal.timeout(ms)</code> (Node 17.3+, all modern browsers) returns a signal that aborts itself after the timeout. Combine with the cancellation pattern from #14 using <code>AbortSignal.any([userSignal, AbortSignal.timeout(5000)])</code> when you want both user cancellation and a hard ceiling.</p><blockquote><p><strong>Pick a timeout for every outbound HTTP call.</strong></p></blockquote><p>The right value depends on the operation: 2&#8211;5 seconds for user-facing reads, 30+ seconds for bulk imports, but never &#8220;no limit&#8221;.</p><p>A &#8220;missing&#8221; timeout is the silent default that bites you under load.</p><div><hr></div><h2>16. Running Independent Async Operations Sequentially</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Sequential &#8212; total time = sum of all operations
const user = await getUser(id);
const orders = await getOrders(id);
const notifications = await getNotifications(id);
// If each takes 200ms, total = 600ms</code></pre></div><p>If the operations don&#8217;t depend on each other, running them sequentially wastes time.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Parallel &#8212; total time = slowest operation
const [user, orders, notifications] = await Promise.all([
  getUser(id),
  getOrders(id),
  getNotifications(id),
]);
// If each takes 200ms, total = 200ms</code></pre></div><p>Use <code>Promise.all</code> when all operations must succeed. Use <code>Promise.allSettled</code> when some can fail independently &#8212; like loading a dashboard where each widget fetches its own data.</p><blockquote><p>Keep sequential <code>await</code> for operations where each step depends on the previous one.</p></blockquote><p>One related foot-gun related to this:</p><blockquote><p><strong>Don&#8217;t use </strong><code>arr.forEach(async ...)</code><strong> for any of this!</strong></p></blockquote><p><code>forEach</code> ignores the promise its callback returns, so you fire N parallel async calls and the function returns <em>before any of them complete</em>, including writes that haven&#8217;t happened yet.</p><p>Logs say &#8220;done&#8221;; the database says otherwise. </p><p>Use <code>Promise.all(arr.map(...))</code> for parallel, or <code>for...of</code> with <code>await</code> for sequential.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><h2>17. <strong>Blocking the Event Loop</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Sync I/O on a hot path &#8212; the entire process freezes here
import fs from "node:fs";

app.get("/config", (req, res) =&gt; {
  const config = fs.readFileSync("./config.json", "utf8"); // blocks!
  res.json(JSON.parse(config));
});

// &#10060; Heavy CPU work on the main thread
app.post("/report", (req, res) =&gt; {
  const csv = generateMassiveCsv(req.body); // 800ms of pure CPU
  res.send(csv);
});</code></pre></div><p>Node.js runs your code on a single thread. While that thread is busy, <strong>nothing else runs</strong> &#8212; no other requests, no timers, no I/O callbacks. A 200ms sync read or a 500ms <code>JSON.parse</code> on a fat payload pauses every concurrent user of your service. Under any real load this looks like random latency spikes that nobody can reproduce locally.</p><p>The usual offenders: <code>fs.readFileSync</code>, <code>crypto.pbkdf2Sync</code>, <code>child_process.execSync</code>, parsing huge JSON or XML payloads, regex with catastrophic backtracking, and tight loops over big arrays.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Async I/O &#8212; the event loop keeps serving other requests
import fs from "node:fs/promises";

app.get("/config", async (req, res) =&gt; {
  const config = await fs.readFile("./config.json", "utf8");
  res.json(JSON.parse(config));
});

// &#9989; Move CPU-heavy work off the main thread
import { Worker } from "node:worker_threads";

app.post("/report", async (req, res) =&gt; {
  const worker = new Worker("./csv-worker.js", { workerData: req.body });
  worker.once("message", (csv) =&gt; res.send(csv));
});</code></pre></div><p>For I/O, the rule is simple: never use the <code>*Sync</code> variant in request-handling code.</p><p>For CPU-heavy work, move it to a worker thread (<code>worker_threads</code>) or a background queue (BullMQ, etc.). For regex, audit any pattern that contains nested quantifiers (<code>(a+)+</code>) &#8212; those are how a 50-char user input becomes a 30-second freeze.</p><p>How to spot it in production:</p><blockquote><p>enable Node&#8217;s built-in <code>perf_hooks.monitorEventLoopDelay()</code> or watch for <code>event_loop_lag</code> in your APM.</p></blockquote><p>A loop delay above ~50ms during normal traffic means something is blocking, and it&#8217;s almost always one of the patterns above.</p><div><hr></div><h2>18. <strong>Using </strong><code>Date</code><strong> for Everything</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Timezone roulette
const meetingTime = new Date("2024-03-15T10:00:00");
// What timezone is this? The answer: it depends on where the code runs.</code></pre></div><p>JavaScript's <code>Date</code> always represents an instant (UTC milliseconds), but parsing a date-time string without an offset uses the <strong>local timezone of the machine running the code</strong>. Engines agree on this, that's the spec. The problem is that your machines disagree on what "local" means:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">// Your server (UTC): parses as 2024-03-15T10:00:00.000Z
// Your laptop (UTC+2): parses as 2024-03-15T10:00:00.000+02:00 &#8594; 08:00 UTC
// Your US colleague (UTC-5): parses as 2024-03-15T10:00:00.000-05:00 &#8594; 15:00 UTC
// Same string, three different instants in time.</code></pre></div><p>Store that in a database, render it for a user in Tokyo, and you&#8217;ve got a meeting that nobody shows up to at the right time.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Use Temporal (shipping in Firefox, polyfill elsewhere) or date-fns with explicit timezones
import { Temporal } from "@js-temporal/polyfill";

const meeting = Temporal.ZonedDateTime.from({
  year: 2024,
  month: 3,
  day: 15,
  hour: 10,
  minute: 0,
  timeZone: "Europe/Sofia",
});

// &#9989; Or with date-fns v3+ (lighter weight, no polyfill needed)
import { TZDate } from "@date-fns/tz";

const meetingInSofia = new TZDate("2024-03-15T10:00:00", "Europe/Sofia");</code></pre></div><p> Check your support matrix before you drop the Temporal polyfill.</p><p>If Temporal feels too heavy, <code>date-fns</code> with <code>@date-fns/tz</code> is solid and tree-shakeable.</p><p><strong>The point isn't which library. It's that you pick one that forces timezone-awareness instead of letting </strong><code>Date</code><strong> guess.</strong></p><div><hr></div><h2>19. <strong>Testing for Coverage, Not for Value</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; 100% coverage, 0% confidence
it("should create an instance", () =&gt; {
  const service = new UserService(mockDeps);
  expect(service).toBeDefined(); // Yes... constructors construct things
});

it("should call the database", async () =&gt; {
  await service.getUser("123");
  expect(mockDb.findById).toHaveBeenCalledWith("123");
  // Congrats, you've tested that your code... calls code
});</code></pre></div><p>These tests verify implementation details, not behavior.</p><p>They break on every refactor and catch zero bugs. (Spy assertions like <code>toHaveBeenCalledWith</code> are fine <strong>alongside</strong> behavior assertions, for example, when you need to verify a side effect on a mocked dependency. They&#8217;re not fine as a substitute.)</p><p><strong>The fix:</strong> Test behavior. What comes out given what goes in?</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Tests that verify behavior
it("returns the user when found", async () =&gt; {
  mockDb.findById.mockResolvedValue({ id: "123", name: "Alice" });
  const user = await service.getUser("123");
  expect(user).toEqual({ id: "123", name: "Alice" });
});

it("throws NotFoundError when user does not exist", async () =&gt; {
  mockDb.findById.mockResolvedValue(null);
  await expect(service.getUser("123")).rejects.toThrow(NotFoundError);
});

it("applies discount correctly", () =&gt; {
  expect(calculateDiscount(100, "SAVE20")).toBe(80);
  expect(calculateDiscount(100, "INVALID")).toBe(100);
  expect(calculateDiscount(0, "SAVE20")).toBe(0);
});</code></pre></div><blockquote><p><strong>Test the contract, not the implementation.<br>A good test should survive a refactor that doesn't change behavior.</strong></p></blockquote><div><hr></div><h2>20. <strong>Not Validating Input at the Boundary</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Trust-based programming
app.post("/users", async (req, res) =&gt; {
  const user = await db
    .insertInto("users")
    .values(req.body) // Whatever you send, we store
    .returningAll()
    .executeTakeFirstOrThrow();
  res.json(user);
});</code></pre></div><p><code>req.body</code> could be anything. A missing field crashes your database query. An extra field like <code>{ role: 'admin' }</code> silently grants privilege escalation. That&#8217;s classic mass assignment, and it&#8217;s the single most common way one of these handlers becomes a security incident.</p><p>(Prototype pollution via <code>__proto__</code> is a separate concern with its own mitigations, but mass assignment is what you&#8217;ll actually see in production logs.)</p><p><strong>The fix:</strong> Validate at the edge, trust internally.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">import { z } from "zod";

const CreateUserSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  role: z.enum(["admin", "user"]).default("user"),
});

app.post("/users", async (req, res) =&gt; {
  const input = CreateUserSchema.parse(req.body);
  // input is typed and validated &#8212; only the fields you defined, nothing extra
  const user = await db
    .insertInto("users")
    .values(input)
    .returningAll()
    .executeTakeFirstOrThrow();
  res.json(user);
});</code></pre></div><p>Zod gives you runtime validation and TypeScript types from a single schema definition. The <code>.parse()</code> call strips unknown fields by default, so no mass assignment attacks.</p><blockquote><p>Validate at every boundary: API routes, queue consumers, webhook handlers, file parsers.</p></blockquote><p>Once data passes validation, trust it downstream:<br>=&gt; No defensive checks scattered through your business logic.</p><p>One pairing worth naming: input validation (this section) and <strong>parameterized queries</strong> (the Kysely <code>.values(input)</code> call above parameterizes for you) solve different attacks &#8212; mass assignment vs. SQL injection.</p><p>They&#8217;re complementary, not interchangeable; both belong at the boundary, never in your business logic.</p><p><em>Note: SQL injection deserves its own deep dive, which I&#8217;ll cover in a future post.</em></p><div><hr></div><h2><strong>&#128204; TL;DR</strong></h2><p>In this post, we covered:</p><ul><li><p><strong>Code Hygiene</strong>: parameter mutation</p></li><li><p><strong>Async &amp; Performance</strong>: memory leaks, cancellation, HTTP timeouts, sequential operations, blocking the event loop, <code>Date</code></p></li><li><p><strong>Testing &amp; Validation</strong>: coverage vs. value, input validation</p></li></ul><p>If you missed Part 1, <a href="https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns">start there</a>. It covers the foundational mistakes in type safety, error handling, and architecture that shape everything else.</p><p>Thanks for reading, and stay awesome!</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns-async-performance-testing?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns-async-performance-testing?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[20 Mistakes That Quietly Destroy JavaScript/TypeScript Codebases (Part 1)]]></title><description><![CDATA[Common JS/TS patterns that feel fine until they don't. 11 mistakes, before/after code for each. (11 min)]]></description><link>https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns</link><guid isPermaLink="false">https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns</guid><pubDate>Sat, 02 May 2026 02:19:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a08009e3-478f-4469-abca-7979c6ac4720_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><p>Every JS/TS codebase collects the same kinds of mistakes. </p><p>They don&#8217;t break the build. They don&#8217;t fail tests. They rarely show up in PR review. They just sit there, quietly making every change a little more expensive, until one of them surfaces as a production incident at 2am.</p><p>I&#8217;ve hit every one of these across 9+ years of shipping JavaScript and TypeScript. Twenty in total, too many for one post, so I split them into two parts.</p><p>This post covers the foundations: how you model types, how you handle errors, and how you shape your modules. Get these wrong and everything you build on top compounds the pain.</p><p><em><a href="https://thetshaped.dev/p/e6ada6a0-8eb5-462d-bdfd-306a0ec7b864">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p><div><hr></div><h2><strong><a href="https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev">Issues that fix themselves?</a></strong><a href="https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev"> (Sentry Seer, Partner)</a></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8xQI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 424w, https://substackcdn.com/image/fetch/$s_!8xQI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 848w, https://substackcdn.com/image/fetch/$s_!8xQI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 1272w, https://substackcdn.com/image/fetch/$s_!8xQI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8xQI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87319,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/avif&quot;,&quot;href&quot;:&quot;https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/193242518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8xQI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 424w, https://substackcdn.com/image/fetch/$s_!8xQI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 848w, https://substackcdn.com/image/fetch/$s_!8xQI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 1272w, https://substackcdn.com/image/fetch/$s_!8xQI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dc5c51b-c405-434a-ac95-3f7502586f32_1280x720.avif 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><a href="https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev">Seer</a> is Sentry&#8217;s AI debugging agent. It uses everything <a href="https://sentry.io/welcome/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=general-fy27q1-evergreen&amp;utm_content=partner-homepage-trysentry&amp;code=tshapeddev">Sentry</a> knows (errors, traces, logs, replays, profiles, and your code) to automatically fix production issues, investigate problems alongside you, and predict bugs before they ship.</p><p>Every error <a href="https://sentry.io/welcome/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=general-fy27q1-evergreen&amp;utm_content=partner-homepage-trysentry&amp;code=tshapeddev">Sentry</a> captures comes with a stack trace, a span tree, a breadcrumb trail, session replay, profiles, logs, and the surrounding code. <a href="https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev">Seer</a> is a <strong>reasoning layer built specifically for debugging</strong> and wired directly into all of that telemetry.</p><p>Other AI tools can help you write code or search docs. <strong><a href="https://sentry.io/product/seer/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=seer-fy27q1-seerlaunch&amp;utm_content=partner-product-trysentry&amp;code=tshapeddev">Seer</a> understands why your app is broken.</strong></p><ul><li><p><strong>Autofix </strong>kicks in directly on issues in Sentry and in your Slack alerts.</p></li><li><p><strong>Seer Agent </strong>lets you investigate proactively&#8212;ask questions, explore patterns, dig into incidents conversationally.</p></li><li><p><strong>AI Code Review </strong>catches bugs before they ship, scanning PRs against production behavior.</p></li><li><p><strong>Sentry&#8217;s MCP </strong>brings Seer&#8217;s context directly into your coding agent (Cursor, Copilot, Claude) in your editor or terminal.</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://sentry.io/signup/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=general-fy27q1-evergreen&amp;utm_content=partner-signup-trysentry&amp;code=tshapeddev&quot;,&quot;text&quot;:&quot;Try For Free&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://sentry.io/signup/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=general-fy27q1-evergreen&amp;utm_content=partner-signup-trysentry&amp;code=tshapeddev"><span>Try For Free</span></a></p><p><em>PS: Use the <strong>tshapeddev</strong> promo code to get 3 months <strong>free</strong> on the Team plan of <a href="https://sentry.io/signup/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=general-fy27q1-evergreen&amp;utm_content=partner-signup-trysentry&amp;code=tshapeddev">Sentry</a> for any new accounts.</em></p><p>(Thanks to <a href="https://sentry.io/welcome/?utm_source=tshapeddev&amp;utm_medium=paid-community&amp;utm_campaign=general-fy27q1-evergreen&amp;utm_content=partner-homepage-trysentry&amp;code=tshapeddev">Sentry</a> for partnering on this post.)</p><div><hr></div><h2><strong>1. Not Enabling TypeScript Strict Mode</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">// tsconfig.json &#8212; the default sin
{
  "compilerOptions": {
    "strict": false // or just not setting it
  }
}</code></pre></div><p>Without strict mode, TypeScript silently allows <code>null</code> where you expect a string, <code>undefined</code> where you expect an object, and implicit <code>any</code> on every untyped parameter. You get half the type safety and all of the tooling overhead.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "compilerOptions": {
    "strict": true
  }
}</code></pre></div><p>This enables <code>strictNullChecks</code>, <code>noImplicitAny</code>, <code>strictFunctionTypes</code>, and more. </p><p>Yes, migrating an existing project hurts. Do it anyway. Enable strict flags incrementally if you must, but <code>strictNullChecks</code> alone prevents more runtime errors than everything else combined.</p><div><hr></div><h2><strong>2. Using </strong><code>any</code><strong> as an Escape Hatch</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; The "make TypeScript shut up" approach
function processData(data: any) {
  return data.items.map((item: any) =&gt; item.name.toUpperCase());
}</code></pre></div><p><code>any</code> disables type checking entirely. It&#8217;s contagious. Once <code>any</code> enters a chain, everything downstream is unchecked. You&#8217;ve just written JavaScript with extra build steps.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Use unknown + a type guard to narrow
function isValidResponse(data: unknown): data is { items: { name: string }[] } {
  if (typeof data !== "object" || data === null) return false;
  const maybe = data as { items?: unknown };
  if (!Array.isArray(maybe.items)) return false;
  return maybe.items.every(
    (item) =&gt;
      typeof item === "object" &amp;&amp;
      item !== null &amp;&amp;
      typeof (item as { name?: unknown }).name === "string",
  );
}

function processData(data: unknown): string[] {
  if (!isValidResponse(data)) {
    throw new Error("Invalid data format");
  }
  // After the guard, TypeScript knows data.items exists and is typed
  return data.items.map((item) =&gt; item.name.toUpperCase());
}

// Or use generics when the type is truly variable
function firstElement&lt;T&gt;(arr: T[]): T | undefined {
  return arr[0];
}</code></pre></div><p><code>unknown</code> is the type-safe cousin of <code>any</code>. It forces you to narrow before accessing properties.</p><p>Type guards (the <code>data is X</code> return type, also called a <em>type predicate</em>) teach the compiler what shape to expect after the check.</p><p>Important: the compiler takes your word for it. If the guard body doesn't actually verify every field you claim, you get a typed lie. </p><p>For non-trivial shapes, reach for a schema library like <a href="https://zod.dev/">Zod</a> instead of hand-rolling guards. </p><p>Use generics when you need flexibility. Reserve <code>any</code> for genuinely untyped boundaries (third-party libs with no types), and mark those with <code>// eslint-disable-next-line @typescript-eslint/no-explicit-any</code>.</p><div><hr></div><h2><strong>3. Not Using Discriminated Unions</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Optional field soup
interface ApiResponse {
  data?: UserData;
  error?: string;
  loading?: boolean;
}

// Is this valid? { data: undefined, error: "fail", loading: true }
// What about { data: someData, error: "also fail" }?
// The type allows both. Your runtime won't.</code></pre></div><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Discriminated union &#8212; each state is explicit
type ApiResponse =
  | { status: 'loading' }
  | { status: 'success'; data: UserData }
  | { status: 'error'; error: string };

function handleResponse(response: ApiResponse) {
  switch (response.status) {
    case 'loading':
      return &lt;Spinner /&gt;;
    case 'success':
      return &lt;UserProfile data={response.data} /&gt;;  // data is guaranteed
    case 'error':
      return &lt;ErrorBanner message={response.error} /&gt;;  // error is guaranteed
  }
}</code></pre></div><p>Discriminated unions make impossible states unrepresentable. TypeScript automatically narrows the type in each branch; no null checks needed.</p><div><hr></div><h2><strong>4. Ignoring Return Types on Exported Functions</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; No return type &#8212; the API contract is implicit
export async function getUser(id: string) {
  const user = await db
    .selectFrom("users")
    .where("id", "=", id)
    .selectAll()
    .executeTakeFirst();
  if (!user) throw new NotFoundError("User not found");
  return user;
}</code></pre></div><p>TypeScript infers the return type, but the inference is tied to the implementation.</p><p>Change how you query the database and the return type silently changes, breaking every caller without a compile error.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Explicit return type on exported functions
export async function getUser(id: string): Promise&lt;User&gt; {
  const user = await db
    .selectFrom("users")
    .where("id", "=", id)
    .selectAll()
    .executeTakeFirst();
  if (!user) throw new NotFoundError("User not found");
  return user;
}</code></pre></div><p>Explicit return types on exported functions serve as a contract. If the implementation changes in a way that breaks the contract, the <em>function itself</em> errors, not every downstream consumer.</p><p><strong>Rule of thumb</strong>: always type exports. Let inference handle private/local functions.</p><div><hr></div><h2><strong>5. Catching Errors and Swallowing Them</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; The silent failure
try {
  await processPayment(order);
} catch (error) {
  console.log("Payment failed");
  // Cool, so... now what?
}</code></pre></div><p>The order continues as if payment succeeded. The user gets charged nothing. You get no alert. The bug sits in production for weeks until someone checks the logs.</p><p><strong>The fix:</strong> every catch block needs exactly one strategy. </p><p>Here are your three options (pick one, not all):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Strategy A &#8212; Rethrow (let the caller decide)
try {
  await processPayment(order);
} catch (error) {
  logger.error("Payment failed", { orderId: order.id, error });
  throw error;
}</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Strategy B &#8212; Recover (handle it yourself)
try {
  await processPayment(order);
} catch (error) {
  logger.error("Payment failed", { orderId: order.id, error });
  await markOrderAsPendingPayment(order.id);
  await notifyPaymentTeam(order.id);
}</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Strategy C &#8212; Transform into a domain error
try {
  await processPayment(order);
} catch (error) {
  logger.error("Payment failed", { orderId: order.id, error });
  throw new PaymentFailedError(order.id, { cause: error });
}</code></pre></div><p>&#8220;Log and continue&#8221; is almost never the right answer. If you&#8217;re not rethrowing, recovering, or transforming, you&#8217;re hiding bugs.</p><p><strong>Strategy D: Make errors impossible to ignore with the <a href="https://thetshaped.dev/p/functional-error-handling-in-nodejs-with-the-result-pattern">Result pattern</a>.</strong></p><p><code>try/catch</code> has a design flaw &#8212; nothing forces the caller to handle the error.</p><p>The <a href="https://thetshaped.dev/p/functional-error-handling-in-nodejs-with-the-result-pattern">Result pattern</a> encodes success and failure in the return type itself. You can&#8217;t access the data without checking first.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Result type &#8212; errors are values, not exceptions
type Result&lt;T, E = Error&gt; = { ok: true; value: T } | { ok: false; error: E };

async function processPayment(
  order: Order,
): Promise&lt;Result&lt;Receipt, PaymentError&gt;&gt; {
  try {
    const receipt = await stripe.charges.create({ /* ... */ });
    return { ok: true, value: receipt };
  } catch (err) {
    return { ok: false, error: new PaymentError(order.id, { cause: err }) };
  }
}

// The caller CAN'T ignore the error &#8212; TypeScript won't let you access .value without checking .ok
const result = await processPayment(order);
if (!result.ok) {
  await markOrderAsPendingPayment(order.id);
  return;
}
sendConfirmation(result.value);  // result.value is typed as Receipt here</code></pre></div><p>This works great for operations where failure is expected and the caller should decide what to do, like payments, validation, external API calls.</p><p>Save <code>try/catch</code> for truly exceptional cases (database down, out of memory).</p><p>Use Result for &#8220;this might not work and that&#8217;s fine&#8221;.</p><div><hr></div><h2><strong>6. Not Handling Promise Rejections</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Fire and forget
app.post("/webhook", (req, res) =&gt; {
  processWebhook(req.body); // Returns a Promise &#8212; but nobody awaits it
  res.sendStatus(200);
});</code></pre></div><p>If <code>processWebhook</code> throws, you get an unhandled rejection. </p><p>In Node.js 15+, that crashes the process. Even with a global handler, you&#8217;ve lost the request context.</p><p><strong>The fix:</strong></p><pre><code><code>// &#9989; Always await or explicitly handle
app.post("/webhook", async (req, res, next) =&gt; {
  try {
    await processWebhook(req.body);
    res.sendStatus(200);
  } catch (error) {
    next(error);  // Let Express error handler deal with it
  }
});

// If you truly need fire-and-forget:
processWebhook(req.body).catch((error) =&gt; {
  logger.error("Webhook processing failed", { error });
});</code></code></pre><p><strong>Rule</strong>: every Promise either gets <code>await</code>ed or gets a <code>.catch()</code>. No exceptions.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><strong>7. Hardcoding Dependencies Instead of Injecting Them</strong></h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Welded to implementations
import { db } from "../lib/db";
import { sendEmail } from "../lib/email";

export async function createOrder(data: CreateOrderInput) {
  const order = await db
    .insertInto("orders")
    .values(data)
    .returningAll()
    .executeTakeFirstOrThrow();
  await sendEmail(order.email, "Confirmed", template(order));
  return order;
}</code></pre></div><p>This function is impossible to unit test without <code>jest.mock('../lib/db')</code>, and the moment you rename that file or move it, every mock breaks. You end up testing your mock wiring, not your business logic.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Dependencies come from the outside
interface OrderServiceDeps {
  db: Database;
  email: EmailService;
}

export function createOrderService({ db, email }: OrderServiceDeps) {
  return {
    async createOrder(data: CreateOrderInput) {
      const order = await db.orders.create(data);
      await email.send(order.email, "Confirmed", template(order));
      return order;
    },
  };
}</code></pre></div><p>Now testing is trivial: pass in fakes. No <code>jest.mock</code>, no module path fragility. Wire real implementations at the entry point.</p><p><em>(For a deep dive, see <a href="https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you">Dependency Injection in Node.js &amp; TypeScript. The Part Nobody Teaches You</a>)</em></p><div><hr></div><h2>8. Over-Engineering with Microservices Too Early</h2><pre><code><code>// &#10060; 3 developers, 500 users, and this repo structure:
api-gateway/          &#8592; own Docker, CI/CD, database
user-service/         &#8592; own Docker, CI/CD, database
order-service/        &#8592; own Docker, CI/CD, database
payment-service/      &#8592; own Docker, CI/CD, database
notification-service/ &#8592; own Docker, CI/CD, database
// 5 deploys, 5 sets of logs, 5 things to debug at 2am
</code></code></pre><p>You&#8217;re spending more time debugging network calls between your own services than building features. Every &#8220;simple&#8221; change touches three repos and needs coordinated deploys.</p><p><strong>The fix:</strong> Start with a <a href="https://thetshaped.dev/p/what-is-a-modular-monolith-benefits-and-microservices-challenges">modular monolith</a>. Same domain boundaries, one deploy.</p><pre><code><code>// &#9989; Modular monolith &#8212; clear boundaries, zero network overhead
src/
  modules/
    users/        # own routes, service, repository, schema
    orders/       # own routes, service, repository, schema
    payments/     # own routes, service, repository, schema
    notifications/# own routes, service, repository, schema
  shared/         # cross-module types, utils, middleware
</code></code></pre><p>Each module owns its slice of the database and exposes a clean interface. No module reaches into another&#8217;s tables. When (not if) you need to extract a module into a service, the boundary is already there &#8212; it&#8217;s a deployment change, not a rewrite.</p><p>Extract to services only when you have a concrete scaling bottleneck &#8212; not because a conference talk said microservices are the future. Most teams that &#8220;need microservices&#8221; actually need better module boundaries in their monolith.</p><div><hr></div><h2>9. Writing 100+ Line Functions</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; The god function
export async function handleCheckout(req: Request, res: Response) {
  // Validate input (20 lines)
  // Check inventory (15 lines)
  // Calculate pricing (25 lines)
  // Apply discount codes (20 lines)
  // Process payment (15 lines)
  // Create order (10 lines)
  // Send confirmation (10 lines)
  // Update analytics (10 lines)
  res.json({ orderId: order.id });
}</code></pre></div><p><strong>The fix:</strong> Extract each block into a named function, not for reuse, but for readability.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">export async function handleCheckout(req: Request, res: Response) {
  const input = validateCheckoutInput(req.body);
  await checkInventory(input.items);
  const pricing = calculatePricing(input.items, input.discountCode);
  const charge = await processPayment(pricing, input.paymentMethod);
  const order = await createOrder(input, pricing, charge);
  await sendConfirmation(order);
  trackCheckout(order);
  res.json({ orderId: order.id });
}</code></pre></div><p>Each function name tells you what happens. You can read the checkout flow in 10 seconds without scrolling through 125 lines of implementation.</p><div><hr></div><h2>10. Putting Business Logic in Controllers</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; Controller knows too much
app.post("/orders", async (req, res) =&gt; {
  const items = req.body.items;
  let total = 0;
  for (const item of items) {
    const product = await db
      .selectFrom("products")
      .where("id", "=", item.productId)
      .selectAll()
      .executeTakeFirstOrThrow();
    if (product.stock &lt; item.quantity) {
      return res.status(400).json({ error: "Out of stock" });
    }
    total += product.price * item.quantity;
  }
  if (req.body.discountCode) {
    const discount = await db
      .selectFrom("discounts")
      .where("code", "=", req.body.discountCode)
      .selectAll()
      .executeTakeFirstOrThrow();
    total *= 1 - discount.percentage / 100;
  }
  const order = await db
    .insertInto("orders")
    .values({ items, total, userId: req.user.id })
    .returningAll()
    .executeTakeFirstOrThrow();
  res.json(order);
});</code></pre></div><p>Now your business rules are trapped in an HTTP handler. Can&#8217;t reuse them for a CLI, a queue consumer, or a GraphQL resolver.</p><p><strong>The fix:</strong> Controllers do three things: parse input, call a service, format output.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// Controller &#8212; thin
app.post("/orders", async (req, res) =&gt; {
  const input = parseCreateOrderInput(req.body);
  const order = await orderService.createOrder(input, req.user.id);
  res.json(formatOrderResponse(order));
});

// Service &#8212; contains business logic
class OrderService {
  async createOrder(input: CreateOrderInput, userId: string) {
    await this.validateInventory(input.items);
    const total = this.calculateTotal(input.items, input.discountCode);
    return this.db.orders.create({ ...input, total, userId });
  }
}</code></pre></div><div><hr></div><h2><strong>11. Circular Dependencies Between Modules</strong></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#10060; user.ts imports order.ts, order.ts imports user.ts
// user.ts
import { Order } from "./order";
export class User {
  orders: Order[] = [];
}

// order.ts
import { User } from "./user";
// Module top-level use of the cyclic import &#8212; User is still undefined here
// because user.ts hasn't finished evaluating yet.
export class Order extends User {}
// &#128165; TypeError: Class extends value undefined is not a constructor or null</code></pre></div><p>Circular imports are silent killers.</p><p>When the runtime hits a cycle, it hands the second module a half-initialized copy of the first. The bindings exist, but their values are still <code>undefined</code>. </p><p>Use those bindings at the module top level (<code>extends</code>, <code>new</code>, calling a function, reading a constant) and you get a crash. Use them only inside a method body, and it usually "works", until someone adds a top-level reference and the file blows up on import.</p><p>The stack trace rarely points to the real cause.</p><p><strong>The fix:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// &#9989; Option 1: Extract the shared contract into a third module
// types.ts
export interface IUser { name: string; orders: IOrder[]; }
export interface IOrder { owner: IUser; }

// user.ts &#8212; depends on types, not on order.ts
import { IOrder } from "./types";
export class User implements IUser {
  name!: string;
  orders: IOrder[] = [];
}

// order.ts &#8212; depends on types, not on user.ts
import { IUser } from "./types";
export class Order implements IOrder {
  owner!: IUser;
}

// &#9989; Option 2: Break the cycle by inverting the dependency direction.
// "Lower-level" modules shouldn't reach up into "higher-level" ones.
// Orders don't need the whole User &#8212; pass what they actually use.
export class Order {
  constructor(public ownerName: string) {}
}</code></pre></div><p>If two modules import each other, one of them knows too much. Fix the dependency direction or extract the shared contract into a third module. </p><p>Types alone (<code>interface</code>, <code>type</code>) are erased at compile time and don&#8217;t cause runtime cycles, so moving the shared types into a separate file is the cheapest way out. </p><p>Turn on <code>eslint-plugin-import</code>&#8216;s <code>no-cycle</code> rule so new cycles fail CI instead of hiding until the wrong person imports the wrong file.</p><div><hr></div><h2><strong>&#128204; TL;DR</strong></h2><p>In this post (Part 1), we&#8217;ve covered the foundational mistakes that shape everything else:</p><ul><li><p><strong>Type Safety</strong>: strict mode, <code>any</code>, discriminated unions, return types.</p></li><li><p><strong>Error Handling</strong>: swallowing errors, unhandled rejections, the Result pattern.</p></li><li><p><strong>Architecture &amp; Design</strong>: dependency injection, microservices, long functions, controllers, circular deps.</p></li></ul><p>In Part 2, we will cover runtime and quality mistakes that bite you in production like Code Hygiene, Async &amp; Performance, Testing &amp; Validation.</p><p>Thanks for reading, and stay awesome!</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-common-code-smell-patterns?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[ES2025 Features You Should Actually Use]]></title><description><![CDATA[Learn about eight features you must adapt today in your production codebase. (9 min)]]></description><link>https://thetshaped.dev/p/es2025-javascript-typescript-eight-features-you-should-actually-use-production-codebase</link><guid isPermaLink="false">https://thetshaped.dev/p/es2025-javascript-typescript-eight-features-you-should-actually-use-production-codebase</guid><pubDate>Wed, 22 Apr 2026 12:04:34 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/32e77a16-cd55-4ced-a67a-7ddeac11a200_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 30,000+ engineers to receive one practical tip on JS, React, Node.js, Software Design, and Architecture every week.</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><em><a href="https://thetshaped.dev/p/e548d343-c5ea-465b-b8fa-4fcfa799f734">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><p><a href="https://tc39.es/ecma262/2025/">ES2025</a> is finalized. You&#8217;ve probably seen the listicles.</p><p>Here&#8217;s what&#8217;s different about this one: I took features from the spec and ran them against code I&#8217;ve written in the past year.</p><p>Some are genuinely useful. Others are niche enough that you&#8217;ll forget they exist in a month.</p><p>Let&#8217;s separate what matters from what doesn&#8217;t.</p><div><hr></div><h2><strong><a href="https://cline.gg/thetshaped">The tax you pay to run multiple agents. Cline Kanban (Partner)</a></strong></h2><p>If you&#8217;ve spent any time with coding agents, you know the feeling. You start the morning with a clean plan. Spin up a few agents. One is refactoring the auth module. Another is writing tests. A third is scaffolding a new API endpoint. You&#8217;re flying.</p><p>Then, around 10:30 AM, you look up and realize you have 20 terminal windows open. One agent is blocked waiting for a decision you forgot to make. Another finished 40 minutes ago, and you never noticed. A third went sideways three commits back. You&#8217;re no longer flying. You&#8217;re drowning.</p><p>You&#8217;ve shifted from human as driver to human as director. When running coding agents in parallel, the bottleneck isn&#8217;t just context. It&#8217;s your own attention trying to manage 10 agents across 10 terminals. You&#8217;re losing your mind to terminal chaos.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://cline.gg/thetshaped" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fUlB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fUlB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:&quot;https://cline.gg/thetshaped&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!fUlB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.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>Meet <a href="https://cline.gg/thetshaped">Cline Kanban</a>, a CLI-agnostic visual orchestration layer that makes multi-agent workflows usable across providers. Multiple agents, one UI. It&#8217;s the air traffic controller for the agents you&#8217;re already running, regardless of where they live.</p><ul><li><p><strong>Interoperable</strong>: Claude Code and Codex compatible, with more coming soon.</p></li><li><p><strong>Full Visibility</strong>: Confidently run multiple agents and work through your backlog faster.</p></li><li><p><strong>Smart Triage</strong>: See which agents are blocked or in review and jump in to unblock them.</p></li><li><p><strong>Chain Tasks</strong>: Set dependencies so Agent B won&#8217;t start until Agent A is complete.</p></li><li><p><strong>Familiar UI</strong>: Everything in a single Kanban view.</p></li></ul><p>Stop tracking agents and start directing them. Get a meaningful edge with the beta release.</p><p><strong>Install <a href="https://cline.gg/thetshaped">Cline Kanban</a> Today</strong>: npm i -g cline</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://cline.gg/thetshaped&quot;,&quot;text&quot;:&quot;Get Started Today&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://cline.gg/thetshaped"><span>Get Started Today</span></a></p><p>(Thanks to <a href="https://cline.gg/thetshaped">Cline Kanban</a> for partnering on this post.)</p><div><hr></div><h2><strong>1. </strong><code>Set</code><strong> Methods</strong></h2><p>Sets have been half-baked since ES6.</p><p>You could create them, add to them, and check membership.</p><p>However, if you wanted to intersect, union, or diff two sets, you had to write it yourself or reach for lodash.</p><p>Not anymore.</p><p><strong>Before:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">function intersect&lt;T&gt;(a: Set&lt;T&gt;, b: Set&lt;T&gt;): Set&lt;T&gt; {
  const result = new Set&lt;T&gt;();
  for (const item of a) {
    if (b.has(item)) result.add(item);
  }
  return result;
}

const allowedRoles = new Set(['admin', 'editor', 'viewer']);
const userRoles = new Set(['editor', 'commenter']);
const effectiveRoles = intersect(allowedRoles, userRoles);</code></pre></div><p><strong>After:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">const allowedRoles = new Set(['admin', 'editor', 'viewer']);
const userRoles = new Set(['editor', 'commenter']);
const effectiveRoles = allowedRoles.intersection(userRoles);
// Set {'editor'}</code></pre></div><p>The full list: <code>.intersection()</code>, <code>.union()</code>, <code>.difference()</code>, <code>.symmetricDifference()</code>, <code>.isSubsetOf()</code>, <code>.isSupersetOf()</code>, <code>.isDisjointFrom()</code>.</p><p>These are immutable. They return new Sets. That&#8217;s the right call.</p><p>If you&#8217;re doing any kind of permissions, feature flags, or tag filtering, this cleans up real code today. TypeScript support landed in 5.5.</p><div><hr></div><h2><strong>2. </strong><code>Promise.withResolvers()</code><strong>, Externalized Control</strong></h2><p>Ever needed to create a promise and resolve it from outside the executor callback?</p><p>You&#8217;ve probably written this pattern dozens of times:</p><p><strong>Before:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">let resolve: (value: string) =&gt; void;
let reject: (reason: Error) =&gt; void;

const promise = new Promise&lt;string&gt;((res, rej) =&gt; {
  resolve = res;
  reject = rej;
});

// Later, somewhere else...
eventEmitter.on('data', (data) =&gt; resolve(data));
eventEmitter.on('error', (err) =&gt; reject(err));</code></pre></div><p><strong>After:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">const { promise, resolve, reject } = Promise.withResolvers&lt;string&gt;();

eventEmitter.on('data', (data) =&gt; resolve(data));
eventEmitter.on('error', (err) =&gt; reject(err));</code></pre></div><p>No more dangling <code>let</code> declarations. No more praying that <code>resolve</code> was assigned before someone calls it.</p><p>Any time you&#8217;re bridging between callback/event-based code and promises, like WebSocket message handlers, test utilities, and manual coordination. This approach is cleaner.</p><p>TypeScript has supported it since 5.4.</p><div><hr></div><h2><strong>3. </strong><code>Iterator.prototype</code><strong> Methods, Lazy Pipeline Operations</strong></h2><p>Arrays have had <code>.map()</code>, <code>.filter()</code>, <code>.reduce()</code> forever.</p><p>But iterators, the things you get from generators, <code>Map.keys()</code>, <code>Set.values()</code>, had nothing. You&#8217;d spread them into arrays just to use basic operations.</p><p><strong>Before:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">function* generateUsers(): Generator&lt;User&gt; {
  // yields users from a paginated API
}

// Wasteful: materializes entire iterator into memory
const activeEmails = [...generateUsers()]
  .filter(user =&gt; user.isActive)
  .map(user =&gt; user.email)
  .slice(0, 10);</code></pre></div><p><strong>After:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">const activeEmails = generateUsers()
  .filter(user =&gt; user.isActive)
  .map(user =&gt; user.email)
  .take(10)
  .toArray();</code></pre></div><p>The key difference: the new version is <strong>lazy</strong>. It only processes elements as needed. When <code>.take(10)</code> has enough, it stops. No intermediate arrays. No wasted work.</p><p>Available methods: <code>.map()</code>, <code>.filter()</code>, <code>.take()</code>, <code>.drop()</code>, <code>.flatMap()</code>, <code>.reduce()</code>, <code>.toArray()</code>, <code>.forEach()</code>, <code>.some()</code>, <code>.every()</code>, <code>.find()</code>.</p><p>If you work with generators, streams, or any large datasets where you don&#8217;t want to materialize everything into an array first, this is a significant improvement. </p><p>TypeScript support: 5.6+.</p><div><hr></div><h2><strong>4. </strong><code>RegExp.escape()</code><strong>, The One We&#8217;ve Been Waiting 15 Years For</strong></h2><p>If you&#8217;ve ever built a regex from user input, you&#8217;ve either used a library or written a janky escape function that probably misses edge cases.</p><p><strong>Before:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// Did you remember all the special chars?
function escapeRegex(str: string): string {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&amp;');
}

const searchTerm = 'price: $5.00 (USD)';
const pattern = new RegExp(escapeRegex(searchTerm), 'i');</code></pre></div><p><strong>After:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">const searchTerm = 'price: $5.00 (USD)';
const pattern = new RegExp(RegExp.escape(searchTerm), 'i');</code></pre></div><p>It&#8217;s a small thing, but it removes a class of bugs.</p><p>Any time you&#8217;re building dynamic regex patterns from external input (search, filtering, highlighting), use this.</p><div><hr></div><h2><strong>5. </strong><code>Float16Array</code><strong>, Typed Array for ML and Graphics</strong></h2><p>A new typed array for 16-bit floating point numbers. Half the memory of <code>Float32Array</code>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">const weights = new Float16Array([0.5, -0.3, 0.8, 0.1]);
// Half the memory of Float32Array for the same data</code></pre></div><p>If you&#8217;re doing ML inference in the browser, WebGPU work, or processing large numeric datasets where memory matters more than precision, this is useful.</p><p>For everyone else, you&#8217;ll never touch it.</p><p>But it&#8217;s good that the platform supports it. This means less reason to drop to WASM for numeric work.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><strong>6. </strong><code>using</code><strong>  /  </strong><code>await using</code><strong>, Automatic Cleanup</strong></h2><p>If you&#8217;ve ever forgotten to close a file handle, release a database connection, or clear a timer, this one&#8217;s for you.</p><p>Explicit Resource Management adds <code>using</code> and <code>await using</code> declarations that automatically call a cleanup function when the variable goes out of scope.</p><p>Think Python&#8217;s <code>with</code> statement or C#&#8217;s <code>using</code>. JavaScript finally has it.</p><p><strong>Before:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">async function exportReport(reportId: string) {
  const connection = await db.connect();
  try {
    const cursor = await connection.query(`SELECT * FROM reports WHERE id = $1`, [reportId]);
    try {
      const file = await fs.open('./report.csv', 'w');
      try {
        for await (const row of cursor) {
          await file.write(formatCsvRow(row));
        }
      } finally {
        await file.close();
      }
    } finally {
      await cursor.close();
    }
  } finally {
    await connection.release();
  }
}</code></pre></div><p><strong>After:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">async function exportReport(reportId: string) {
  await using connection = await db.connect();
  await using cursor = await connection.query(`SELECT * FROM reports WHERE id = $1`, [reportId]);
  await using file = await fs.open('./report.csv', 'w');

  for await (const row of cursor) {
    await file.write(formatCsvRow(row));
  }
  // connection, cursor, and file are all released automatically
}</code></pre></div><p>The nested try/finally pyramid is gone. Each resource cleans itself up when the block exits, whether it completes normally or throws.</p><p>For this to work, the resource needs a <code>[Symbol.asyncDispose]()</code> method (or <code>[Symbol.dispose]()</code> for synchronous resources).</p><p>Node.js built-ins like file handles already support it.</p><p>For your own classes, it&#8217;s straightforward:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">class DatabaseConnection {
  async [Symbol.asyncDispose]() {
    await this.release();
  }
}</code></pre></div><p>V8 and Node.js 22+ ship it. Browser support is still catching up: Chrome has it, Firefox and Safari are behind. </p><p>TypeScript supports it in 5.2+.</p><p>If you&#8217;re writing server-side code, start using this today. For client-side, wait a bit longer.</p><div><hr></div><h2><strong>7. </strong><code>Promise.try()</code><strong>, Safe Function Wrapping</strong></h2><p>You have a function. It might be sync. It might be async. You want to call it and always get a Promise back, with errors caught either way.</p><p><strong>Before:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">function runTask(task: () =&gt; unknown): Promise&lt;unknown&gt; {
  try {
    const result = task();
    return Promise.resolve(result);
  } catch (err) {
    return Promise.reject(err);
  }
}</code></pre></div><p>Or the shorter-but-subtle version:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// This doesn't catch synchronous throws from task()
const result = Promise.resolve().then(() =&gt; task());</code></pre></div><p><strong>After:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">const result = Promise.try(task);</code></pre></div><p>One line. Catches sync throws. Wraps sync return values. Passes through Promises. Does the right thing every time.</p><p>This shows up anywhere you accept a callback that could be sync or async, like plugin systems, middleware chains, test runners, task queues.</p><p>It&#8217;s the <code>Promise.withResolvers</code> of error handling: a small API that eliminates a whole class of subtle bugs.</p><p>Supported in Chrome 128+, Firefox 132+, Safari 18.2+, Node.js 22+. TypeScript 5.7+.</p><div><hr></div><h2><strong>8. </strong><code>JSON</code><strong> modules and </strong><code>import</code><strong> attributes</strong></h2><p>Import attributes (the <code>with</code> syntax) let you specify how an import should be interpreted:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">import config from './config.json' with { type: 'json' };
import styles from './styles.css' with { type: 'css' };</code></pre></div><p>This has been available in bundlers for a while, but now it&#8217;s part of the language spec, and runtimes have caught up.</p><p>Chrome, Edge, Firefox, and Safari all support <code>with { type: 'json' }</code> as of April 2025. Node.js 22+ supports it too.</p><p>The <code>type</code> attribute isn&#8217;t an optional decoration but a security mechanism.</p><p>The runtime validates the MIME type before processing the file. If someone swaps your JSON endpoint for executable code, the import fails instead of running it.</p><p>One caveat: JSON modules only expose a default export. The entire JSON object comes in as <code>default</code>. No named exports.</p><p>If you&#8217;re importing JSON configs, fixtures, or static data, drop the <code>fs.readFileSync</code> / <code>require()</code> and use this.</p><p>TypeScript supports the syntax in 5.3+.</p><div><hr></div><h2>Other Good To Know Features</h2><p>Three more features made it into the spec.</p><p>They&#8217;re niche enough that most developers won&#8217;t use them directly, but worth knowing they exist:</p><ul><li><p><code>Error.isError()</code>: returns <code>true</code> if the value is an Error, even across realms. If you&#8217;ve ever had <code>instanceof Error</code> return <code>false</code> because the error came from a different iframe or Node.js <code>vm</code> context, this fixes it.</p></li><li><p><strong>Regex pattern modifiers</strong> (<code>(?i:HELLO)</code>): toggle flags like <code>i</code>, <code>m</code>, <code>s</code> for specific parts of a regex instead of the whole pattern. Handy when one section of your regex needs case-insensitive matching but the rest doesn&#8217;t.</p></li><li><p><strong>Duplicate named capture groups</strong>: you can now reuse the same group name in different regex alternatives: <code>/(?&lt;id&gt;\d+)|(?&lt;id&gt;[a-f]+)/v</code>. Previously, this was a syntax error, even though only one alternative can match at a time.</p></li></ul><div><hr></div><h2><strong>&#128204; TL;DR</strong></h2><ul><li><p><strong>Set methods</strong> replace the utility functions you&#8217;ve been copy-pasting for years/</p></li><li><p><code>Promise.withResolvers()</code> externalizes resolve/reject, so no more dangling <code>let</code> declarations when bridging callbacks to promises.</p></li><li><p><strong>Iterator helpers</strong> process data lazily without spreading into arrays first.</p></li><li><p><code>RegExp.escape()</code> safely escapes user input for dynamic regex patterns. Small API, eliminates a whole class of bugs.</p></li><li><p><code>using</code><strong> / </strong><code>await using</code> auto-cleans resources (file handles, DB connections) when they go out of scope. The biggest quality-of-life feature in the spec.</p></li><li><p><code>Promise.try()</code> wraps any function (sync or async) and guarantees a Promise back with errors caught.</p></li><li><p><strong>Import attributes</strong> (<code>with { type: 'json' }</code>) are now Baseline across all browsers and Node.js 22+.</p></li><li><p><strong>Float16Array</strong> is the only niche one. ML/graphics use cases only.</p></li><li><p><strong>Minimum setup</strong>: TypeScript 5.6+, Node.js 22+. Most features are Baseline in browsers already.</p></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/es2025-javascript-typescript-eight-features-you-should-actually-use-production-codebase?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/es2025-javascript-typescript-eight-features-you-should-actually-use-production-codebase?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[Vertical Slice Architecture in Node.js: One Folder Per Use Case]]></title><description><![CDATA[Why organizing by domain module isn't enough and what to do instead. (8 min)]]></description><link>https://thetshaped.dev/p/vertical-slice-architecture-in-nodejs-typescript-one-folder-per-use-case</link><guid isPermaLink="false">https://thetshaped.dev/p/vertical-slice-architecture-in-nodejs-typescript-one-folder-per-use-case</guid><pubDate>Sat, 11 Apr 2026 05:07:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e656df62-293a-44d7-977d-03c5c427bd13_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><p>Your project structure shouldn&#8217;t scream &#8220;Express&#8221; or &#8220;Fastify&#8221;. It should scream what the app <strong>does</strong>.</p><p>We explored this principle in <a href="https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react">Screaming Architecture &amp; Colocation</a>.</p><p>Vertical Slice Architecture takes it to its logical conclusion: each <em>use case</em> gets its own folder containing <em>everything</em>: handler, validation, types, tests. There is no jumping between 5 directories to understand one operation.</p><ul><li><p><em><a href="https://open.substack.com/pub/petarivanovv9/p/vertical-slice-architecture-in-nodejs-typescript-one-folder-per-use-case?r=643nm&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><h2>The Problem with Layered Structure</h2><p>You&#8217;ve seen this layout a thousand times:</p><pre><code><code>src/
&#9500;&#9472;&#9472; controllers/
&#9474;   &#9500;&#9472;&#9472; orderController.ts
&#9474;   &#9500;&#9472;&#9472; userController.ts
&#9474;   &#9492;&#9472;&#9472; productController.ts
&#9500;&#9472;&#9472; services/
&#9474;   &#9500;&#9472;&#9472; orderService.ts
&#9474;   &#9500;&#9472;&#9472; userService.ts
&#9474;   &#9492;&#9472;&#9472; productService.ts
&#9500;&#9472;&#9472; models/
&#9474;   &#9500;&#9472;&#9472; order.ts
&#9474;   &#9500;&#9472;&#9472; user.ts
&#9474;   &#9492;&#9472;&#9472; product.ts
&#9500;&#9472;&#9472; validators/
&#9474;   &#9500;&#9472;&#9472; orderValidator.ts
&#9474;   &#9492;&#9472;&#9472; userValidator.ts
&#9492;&#9472;&#9472; tests/
    &#9500;&#9472;&#9472; orderController.test.ts
    &#9492;&#9472;&#9472; orderService.test.ts
</code></code></pre><p>Want to understand how &#8220;create order&#8221; works? Open 5 folders.</p><p>Want to add a new feature? Touch 5 directories. </p><p>Want to delete a feature? Good luck finding all the pieces.</p><p>The layered structure is organized by <em>technical concern</em>. It answers &#8220;where are all my controllers?&#8221; but not &#8220;where is the order creation feature?&#8221;.</p><p>Low cohesion. High cognitive overhead. Every change is a scavenger hunt.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ORcj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ORcj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 424w, https://substackcdn.com/image/fetch/$s_!ORcj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 848w, https://substackcdn.com/image/fetch/$s_!ORcj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 1272w, https://substackcdn.com/image/fetch/$s_!ORcj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ORcj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png" width="1456" height="948" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:948,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:389517,&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://thetshaped.dev/i/193244611?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.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_!ORcj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 424w, https://substackcdn.com/image/fetch/$s_!ORcj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 848w, https://substackcdn.com/image/fetch/$s_!ORcj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.png 1272w, https://substackcdn.com/image/fetch/$s_!ORcj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb678d8d7-ef40-4715-b06f-67c81dd45cfa_1770x1152.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><div><hr></div><h2><strong><a href="https://cline.gg/thetshaped">The tax you pay to run multiple agents. Cline Kanban - Sponsor</a></strong></h2><p>If you&#8217;ve spent any time with coding agents, you know the feeling. You start the morning with a clean plan. Spin up a few agents. One is refactoring the auth module. Another is writing tests. A third is scaffolding a new API endpoint. You&#8217;re flying.</p><p>Then, around 10:30 AM, you look up and realize you have 20 terminal windows open. One agent is blocked waiting for a decision you forgot to make. Another finished 40 minutes ago, and you never noticed. A third went sideways three commits back. You&#8217;re no longer flying. You&#8217;re drowning.</p><p>You&#8217;ve shifted from human as driver to human as director. When running coding agents in parallel, the bottleneck isn&#8217;t just context. It&#8217;s your own attention trying to manage 10 agents across 10 terminals. You&#8217;re losing your mind to terminal chaos.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://cline.gg/thetshaped" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fUlB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fUlB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:&quot;https://cline.gg/thetshaped&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!fUlB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!fUlB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43bc8775-026c-4290-8fe1-4a80f660e6cf_1600x900.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>Meet <a href="https://cline.gg/thetshaped">Cline Kanban</a>, a CLI-agnostic visual orchestration layer that makes multi-agent workflows usable across providers. Multiple agents, one UI. It&#8217;s the air traffic controller for the agents you&#8217;re already running, regardless of where they live. </p><ul><li><p><strong>Interoperable</strong>: Claude Code and Codex compatible, with more coming soon.</p></li><li><p><strong>Full Visibility</strong>: Confidently run multiple agents and work through your backlog faster.</p></li><li><p><strong>Smart Triage</strong>: See which agents are blocked or in review and jump in to unblock them.</p></li><li><p><strong>Chain Tasks</strong>: Set dependencies so Agent B won&#8217;t start until Agent A is complete.</p></li><li><p><strong>Familiar UI</strong>: Everything in a single Kanban view.</p></li></ul><p>Stop tracking agents and start directing them. Get a meaningful edge with the beta release.</p><p><strong>Install Cline Kanban Today</strong>:  npm i -g cline</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://cline.gg/thetshaped&quot;,&quot;text&quot;:&quot;Get Started Today&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://cline.gg/thetshaped"><span>Get Started Today</span></a></p><div><hr></div><h2>What Is Vertical Slice Architecture?</h2><p>Vertical Slice Architecture, popularized by Jimmy Bogard, flips the axis of organization.</p><blockquote><p>Instead of grouping by layer, you <strong>group by </strong><em><strong>use case</strong></em>.</p></blockquote><p>If you read the <a href="https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react">screaming architecture post</a>, you might be thinking: &#8220;Didn&#8217;t we already do this?&#8221;. Well, not quite. </p><p>Screaming architecture organized by <em>domain module</em> &#8212; <code>patients/</code>, <code>orders/</code>, but it still used layers <em>within</em> each module (controller, service, repository).</p><p>Vertical slices go further. Each folder is a single <em>use case</em>, not a domain module. <code>create-order</code> and <code>cancel-order</code> are separate slices, not methods on an <code>OrderService</code>.</p><p><strong>Core principle</strong>:</p><blockquote><p><strong>maximize cohesion </strong><em><strong>within</strong></em><strong> a slice, minimize coupling </strong><em><strong>between</strong></em><strong> slices.</strong></p></blockquote><p>Each slice is one operation, fully self-contained. Adding a new feature means adding a new folder, not modifying shared structures across the codebase.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IZxx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IZxx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 424w, https://substackcdn.com/image/fetch/$s_!IZxx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 848w, https://substackcdn.com/image/fetch/$s_!IZxx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 1272w, https://substackcdn.com/image/fetch/$s_!IZxx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IZxx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png" width="1456" height="884" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:884,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:260490,&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://thetshaped.dev/i/193244611?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.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_!IZxx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 424w, https://substackcdn.com/image/fetch/$s_!IZxx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 848w, https://substackcdn.com/image/fetch/$s_!IZxx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.png 1272w, https://substackcdn.com/image/fetch/$s_!IZxx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3182addf-28a9-4a37-aefa-21a97418f49d_1684x1022.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>Here&#8217;s the same app, restructured:</p><pre><code><code>src/
&#9500;&#9472;&#9472; features/
&#9474;   &#9500;&#9472;&#9472; create-order/
&#9474;   &#9474;   &#9500;&#9472;&#9472; handler.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; create-order.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; validation.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; types.ts
&#9474;   &#9474;   &#9492;&#9472;&#9472; create-order.test.ts
&#9474;   &#9500;&#9472;&#9472; cancel-order/
&#9474;   &#9474;   &#9500;&#9472;&#9472; handler.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; cancel-order.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; validation.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; types.ts
&#9474;   &#9474;   &#9492;&#9472;&#9472; cancel-order.test.ts
&#9474;   &#9500;&#9472;&#9472; get-user-profile/
&#9474;   &#9474;   &#9500;&#9472;&#9472; handler.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; types.ts
&#9474;   &#9474;   &#9492;&#9472;&#9472; get-user-profile.test.ts
&#9474;   &#9492;&#9472;&#9472; list-products/
&#9474;       &#9500;&#9472;&#9472; handler.ts
&#9474;       &#9500;&#9472;&#9472; types.ts
&#9474;       &#9492;&#9472;&#9472; list-products.test.ts
&#9492;&#9472;&#9472; shared/
    &#9500;&#9472;&#9472; db.ts
    &#9500;&#9472;&#9472; auth.ts
    &#9492;&#9472;&#9472; errors.ts
</code></code></pre><p>Everything you need to understand &#8220;create order&#8221; is in one place. Everything you need to delete is in one folder.</p><div><hr></div><h2>Anatomy of a Slice</h2><p>Let&#8217;s build a real slice. Here&#8217;s &#8220;create order&#8221; in Express with Zod validation.</p><p>A slice typically has two layers: the <strong>handler</strong> (HTTP concerns) and the <strong>use case</strong> (business logic). They live in the same folder &#8212; not in separate <code>controllers/</code> and <code>services/</code> directories across the project. The <code>types.ts</code> and <code>validation.ts</code> files are standard Zod schemas and TypeScript interfaces &#8212; nothing surprising. The interesting part is the split between use case and handler.</p><p><code>features/create-order/create-order.ts</code> &#8212; the use case. Pure business logic, no Express types.</p><pre><code><code>import { CreateOrderInput, CreateOrderResult } from "./types";
import { db } from "../../shared/db";

export async function createOrder(
  input: CreateOrderInput,
): Promise&lt;CreateOrderResult&gt; {
  const products = await db.products.findMany({
    where: { id: { in: input.items.map((i) =&gt; i.productId) } },
  });

  // some business logic here, ex: calculations, etc.

  const order = await db.orders.create({...});

  return { ... };
}</code></code></pre><p><code>features/create-order/handler.ts</code> &#8212; the HTTP layer. Parses the request, calls the use case, and sends the response.</p><pre><code><code>import { Request, Response } from "express";
import { createOrderSchema } from "./validation";
import { createOrder } from "./create-order";

export async function createOrderHandler(
  req: Request,
  res: Response,
): Promise&lt;void&gt; {
  const input = createOrderSchema.parse(req.body);
  const result = await createOrder(input);
  res.status(201).json(result);
}</code></code></pre><p>Three lines. Parse, execute, respond. If the handler grows beyond this, something is leaking across layers.</p><p>The split isn&#8217;t a ceremony; it&#8217;s practical. The use case function takes typed input and returns typed output. You can unit-test business logic without touching <code>Request</code> or <code>Response</code>.</p><p>Note: You&#8217;ll notice <code>create-order.ts</code> imports <code>db</code> directly from <code>shared/</code>. If you need test isolation without hitting the database, pass <code>db</code> as a parameter instead. We&#8217;ve covered the dependency injection pattern in a previous post: <a href="https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you">here</a>.</p><div><hr></div><h2>Wiring Slices Together</h2><p>Slices need to connect to routes. Here&#8217;s a simple composition root:</p><pre><code><code>// src/app.ts
import express from "express";
import { createOrderHandler } from "./features/create-order/handler";
import { cancelOrderHandler } from "./features/cancel-order/handler";
import { getUserProfileHandler } from "./features/get-user-profile/handler";
import { listProductsHandler } from "./features/list-products/handler";

const app = express();
app.use(express.json());

// Routes &#8212; flat and explicit
app.post("/api/orders", createOrderHandler);
app.post("/api/orders/:id/cancel", cancelOrderHandler);
app.get("/api/users/:id/profile", getUserProfileHandler);
app.get("/api/products", listProductsHandler);

export default app;</code></code></pre><div><hr></div><h2>Cross-Cutting Concerns</h2><p>Auth, logging, error handling &#8212; where do they live? Exactly where they&#8217;ve always lived: the <strong>middleware</strong>.</p><pre><code><code>// Scope middleware to groups
app.use("/api/orders", authMiddleware, ordersRouter);
app.use("/api/products", listProductsHandler); // public

// Global error handler
app.use(errorHandler);</code></code></pre><p>Slices don&#8217;t need to know about authentication. The middleware layer handles it.</p><p>Errors inside a slice? <code>createOrderSchema.parse()</code> throws a <code>ZodError</code>, which bubbles up to Express&#8217;s error middleware and becomes a 400. Business errors work the same way. The idea is simple: slices throw, middleware translates.</p><p>For cross-cutting <em>business</em> concerns like audit logging, event publishing, those belong in <code>shared/</code> as utilities that a slice calls explicitly. Each order slice calls <code>auditLog.record()</code> directly. A few extra lines, but it&#8217;s visible. No hidden magic.</p><div><hr></div><h2>Shared Logic Between Slices</h2><p>What happens when two slices need the same business rule?</p><p>Extract it to <code>shared/</code>:</p><pre><code><code>src/
&#9500;&#9472;&#9472; features/
&#9474;   &#9500;&#9472;&#9472; create-order/
&#9474;   &#9492;&#9472;&#9472; cancel-order/
&#9492;&#9472;&#9472; shared/
    &#9500;&#9472;&#9472; db.ts
    &#9500;&#9472;&#9472; pricing.ts      &#8592; shared pricing logic
    &#9492;&#9472;&#9472; errors.ts</code></code></pre><p><strong>The rule</strong>: slices import from <code>shared/</code>. Slices <em>never</em> import from other slices. Enforce this with <code>eslint-plugin-boundaries</code> or Nx module boundaries. We covered the tooling in <a href="https://thetshaped.dev/i/190265218/enforcing-boundaries">Screaming Architecture &amp; Colocation</a>. Structure without enforcement is just a suggestion.</p><p>This keeps each slice independent. If you delete &#8220;cancel order&#8221;, nothing else breaks. If you need to change pricing logic, it&#8217;s in one place &#8212; <code>shared/pricing.ts</code> &#8212; not scattered across multiple slices.</p><p>Keep <code>shared/</code> small. The moment it grows into a mini-framework, you&#8217;ve recreated the layered architecture inside a different folder.</p><p>But when do you extract vs. duplicate?</p><p>Simple rule of thumb: if two slices need the same logic <em>and</em> that logic would need to change in sync (same business rule, same source of truth), extract it to <code>shared/</code>. If two slices happen to look similar but could diverge independently, let them duplicate. <strong>Premature extraction creates coupling. Duplication between independent slices is cheap.</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_!Dhe-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dhe-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 424w, https://substackcdn.com/image/fetch/$s_!Dhe-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 848w, https://substackcdn.com/image/fetch/$s_!Dhe-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 1272w, https://substackcdn.com/image/fetch/$s_!Dhe-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dhe-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png" width="1456" height="824" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:824,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:213907,&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://thetshaped.dev/i/193244611?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.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_!Dhe-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 424w, https://substackcdn.com/image/fetch/$s_!Dhe-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 848w, https://substackcdn.com/image/fetch/$s_!Dhe-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.png 1272w, https://substackcdn.com/image/fetch/$s_!Dhe-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bfd8bbb-5be7-4fbe-bccc-dc817ac44cf7_1732x980.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>Data Access</h3><p>The DB client (<code>db.ts</code>) lives in <code>shared/</code>. But each slice owns its queries: <code>create-order</code> writes its own <code>db.orders.create()</code>, <code>list-products</code> writes its own <code>db.products.findMany()</code>. You can see exactly what data a use case touches by reading one file.</p><p>For transactions that span multiple tables, keep them in the slice that orchestrates the operation. The slice that creates an order and writes order items can wrap both in a single <code>db.$transaction()</code> call. If a transaction truly spans multiple <em>use cases</em>, that&#8217;s a sign you might need a new slice that represents the combined operation.</p><h3>When Slices Need to Talk</h3><p>What happens when creating an order that needs to trigger a notification?</p><p>Two options: <strong>domain events</strong> (create-order emits <code>OrderCreated</code>, other slices subscribe via a lightweight emitter in <code>shared/</code>) or a <strong>shared orchestrator</strong> (a workflow function in <code>shared/</code> that calls use cases in sequence). Either way, slices don&#8217;t import each other&#8217;s internals. They communicate through <code>shared/</code> infrastructure.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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>Tradeoffs</h2><p>This architecture is not a silver bullet. As with everything in programming, it has pros and cons.</p><p><strong>What you gain:</strong></p><ul><li><p>Features are self-contained &#8212; easy to find, easy to understand, easy to delete</p></li><li><p>Adding features = adding folders, not modifying existing files</p></li><li><p>Tests live next to the code they test</p></li><li><p>New team members can orient quickly (&#8221;find the feature folder, everything&#8217;s there&#8221;)</p></li><li><p>Merge conflicts drop dramatically when teams work on separate features</p></li></ul><p><strong>What you trade:</strong></p><ul><li><p>Some duplication between slices (mitigated by <code>shared/</code>)</p></li><li><p>No single view of &#8220;all validation&#8221; or &#8220;all database queries&#8221; across the app</p></li><li><p>Requires discipline to keep slices independent (the temptation to import from other slices is real)</p></li><li><p>Unfamiliar to developers coming from traditional MVC backgrounds</p></li></ul><p>The duplication tradeoff is the most common objection.</p><p>But here&#8217;s the thing: <strong>a little duplication between </strong><em><strong>independent</strong></em><strong> slices is far easier to manage than tight coupling between </strong><em><strong>shared</strong></em><strong> layers</strong>.</p><p>When you change shared validation logic, you need to verify that it doesn&#8217;t break 15 other features. When you change validation inside a single slice, the blast radius is exactly one feature.</p><div><hr></div><h2><strong>When to Use (and When Not To)</strong></h2><p><strong>Use vertical slices when:</strong></p><ul><li><p>Your app has many distinct features or use cases</p></li><li><p>Multiple developers or teams work on separate features</p></li><li><p>You&#8217;re building an API with 15+ endpoints</p></li><li><p>You want features that are easy to add <em>and</em> easy to remove</p></li></ul><p><strong>Keep the simpler structure when:</strong></p><ul><li><p>Your app has fewer than 10 routes</p></li><li><p>You&#8217;re building a library, not an application</p></li><li><p>Heavy cross-cutting logic dominates (e.g., every request does the same 10 processing steps)</p></li><li><p>You&#8217;re prototyping and the domain isn&#8217;t clear yet</p></li></ul><div><hr></div><h2><strong>&#128204; </strong>TL;DR</h2><ul><li><p>Vertical Slice Architecture organizes code by <strong>use case</strong>, not by technical layer &#8212; one folder per operation, not per concern</p></li><li><p>Each slice contains its handler, business logic, validation, types, and tests &#8212; everything in one place</p></li><li><p>The split between <strong>handler</strong> (HTTP) and <strong>use case</strong> (business logic) keeps slices testable without framework dependencies</p></li><li><p>Slices import from <code>shared/</code> but <strong>never from each other</strong> &#8212; enforce this with linting rules</p></li><li><p>Keep <code>shared/</code> small: extract only when two slices share logic that must change in sync. Otherwise, let them duplicate</p></li><li><p>Cross-cutting concerns (auth, errors) stay in middleware. Cross-cutting business logic goes in <code>shared/</code> as explicit calls</p></li><li><p>Migrate incrementally: one use case at a time. Old layers shrink naturally until you delete them</p></li><li><p>Best suited for apps with many distinct features, multiple teams, or 15+ endpoints. Skip it for small apps or early prototypes</p></li></ul><div><hr></div><h2>Next Steps</h2><p>Some of you may not like the idea of grouping all the files related to a feature in a single folder.</p><p>However, there&#8217;s a lot of value in grouping by features in general. And you don&#8217;t need to restructure everything at once.</p><p>We covered the broader migration strategy in <a href="https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react">Screaming Architecture &amp; Colocation</a>. The VSA version is very similar - pick one use case and extract, create the feature folder, inline the service layer, move the tests, do the routing, and repeat.</p><p>Start with something isolated. Once the pattern clicks, the rest goes faster.</p><p>Thanks for reading, and stay awesome!</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/vertical-slice-architecture-in-nodejs-typescript-one-folder-per-use-case?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/vertical-slice-architecture-in-nodejs-typescript-one-folder-per-use-case?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[Dependency Injection in Node.js & TypeScript. The Part Nobody Teaches You]]></title><description><![CDATA[Learn the hidden costs about importing everything directly and the structural change you need to make. (8 min)]]></description><link>https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you</link><guid isPermaLink="false">https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Sun, 29 Mar 2026 12:19:37 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8d012d0b-328c-46d9-b752-ca354941c93c_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post outlines a common Node.js pattern and how to solve it.</em></p><ul><li><p><em><a href="https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><p>In the Java/C# world, DI containers are a religion.</p><p>In Node.js, most developers just <code>import</code> modules directly, until testing becomes a nightmare and swapping implementations means rewriting half the app.</p><p>You don&#8217;t need dependency injection containers like <a href="https://github.com/inversify/InversifyJS">InversifyJS</a> or <a href="https://github.com/microsoft/tsyringe">tsyringe</a>.</p><p>Here&#8217;s how to do dependency injection with plain TypeScript, and why it&#8217;ll make your code instantly more testable.</p><div><hr></div><h2>Dependency Injection vs. Dependency Inversion</h2><p>These terms get used interchangeably. But they're not the same.</p><p><strong>Dependency Injection</strong> (DI) is a technique: instead of a class/function creating its own dependencies, you pass them in from the outside.</p><p><strong>Dependency Inversion</strong> is a principle (the &#8220;D&#8221; in SOLID): high-level modules shouldn&#8217;t depend on low-level modules. Both should depend on abstractions.</p><p>Dependency Injection is how you implement Dependency Inversion.</p><p>But you can do DI without inverting anything. This is the place where most Node.js developers stop.</p><pre><code>// Direct dependency &#8212; no injection
import { db } from './database';

export async function getUser(id: string) {
  return db.query('SELECT * FROM users WHERE id = $1', [id]);
}</code></pre><p>This works. But you can&#8217;t test <code>getUser</code> without a real database.</p><p>You can&#8217;t swap PostgreSQL for an in-memory store.</p><p>And if <code>database.ts</code> has side effects on import, every test file that touches <code>getUser</code> pays that cost.</p><div><hr></div><h2>The Node.js Anti-Pattern: Import Everything Directly</h2><p>Here&#8217;s what most Express apps look like:</p><pre><code>// userService.ts
import { knex } from &#8216;../lib/database&#8217;;
import { sendEmail } from &#8216;../lib/email&#8217;;
import { logger } from &#8216;../lib/logger&#8217;;

export async function createUser(data: CreateUserInput) {
  const [user] = await knex(&#8217;users&#8217;).insert(data).returning(&#8217;*&#8217;);
  await sendEmail(user.email, &#8216;Welcome!&#8217;);
  logger.info(`User created: ${user.id}`);
  return user;
}</code></pre><p>There are three hardcoded dependencies. And to test this function, you need:</p><ul><li><p>A running database (or mock Knex globally)</p></li><li><p>An email service (or mock the module)</p></li><li><p>A logger (or suppress output)</p></li></ul><p>Module mocking (<code>jest.mock</code>, <code>vi.mock</code>) is the usual escape hatch, but it&#8217;s brittle because we&#8217;re mocking import paths, not the actual contracts.</p><p>For example, if you rename a file, your mocks break silently.</p><p><strong>Module mocking is a code smell.</strong></p><p>It tells you your code has hidden dependencies that should be explicit.</p><div><hr></div><h2>What Dependency Injection Actually Solves</h2><p>Before we continue further, let&#8217;s be clear about what we&#8217;re fixing:</p><ul><li><p><strong>Testability.</strong> When a module imports its dependencies directly, you&#8217;re forced into module-level mocking (<code>jest.mock()</code>, <code>vi.mock()</code>) to test it. These mocks are fragile, magical, and break when you rename a file. With DI, you pass plain objects, and no mocking framework is needed.</p></li><li><p><strong>Swappability.</strong> Imagine you have to switch from Knex to Drizzle, or from SendGrid to AWS SES. When dependencies are injected, you swap the implementation in one place. When they&#8217;re imported, you touch every file.</p></li><li><p><strong>Explicit dependencies.</strong> A function&#8217;s signature should tell you what it needs. If <code>createUser</code> secretly depends on a database, an email client, and a logger, but its signature only shows <code>data: CreateUserDTO</code>, that&#8217;s a lie. DI makes dependencies visible.</p></li><li><p><strong>Separation of concerns.</strong> Your business logic shouldn&#8217;t know (or care) whether it&#8217;s talking to Postgres or SQLite, SendGrid or a local SMTP server. DI enforces that boundary naturally.</p></li></ul><p>Now, let&#8217;s see how to do dependency injection in Node.js without any frameworks.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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><strong>Step 1: Constructor Injection (Manual DI)</strong></h2><p>The simplest fix: <strong>accept dependencies as parameters</strong>.</p><pre><code>// userService.ts
interface UserRepository {
  create(data: CreateUserInput): Promise&lt;User&gt;;
}

interface EmailService {
  send(to: string, subject: string): Promise&lt;void&gt;;
}

interface Logger {
  info(message: string): void;
}

export function createUserService(
  repo: UserRepository,
  email: EmailService,
  logger: Logger
) {
  return {
    async createUser(data: CreateUserInput) {
      const user = await repo.create(data);
      await email.send(user.email, &#8216;Welcome!&#8217;);
      logger.info(`User created: ${user.id}`);
      return user;
    },
  };
}</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H_M7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H_M7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 424w, https://substackcdn.com/image/fetch/$s_!H_M7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 848w, https://substackcdn.com/image/fetch/$s_!H_M7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 1272w, https://substackcdn.com/image/fetch/$s_!H_M7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H_M7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png" width="1456" height="561" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:561,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:178393,&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://thetshaped.dev/i/191737097?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.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_!H_M7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 424w, https://substackcdn.com/image/fetch/$s_!H_M7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 848w, https://substackcdn.com/image/fetch/$s_!H_M7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.png 1272w, https://substackcdn.com/image/fetch/$s_!H_M7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4664d57-86d7-484e-9f6d-cdb4dcdab229_1932x744.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><strong>Before and After DI: How You Use the Code</strong></h3><p>The real difference isn&#8217;t just how the service is <em><strong>defined</strong></em>, but how it&#8217;s <em><strong>consumed</strong></em>.</p><p><strong>Before DI, we use direct imports (hidden dependencies):</strong></p><pre><code>// Somewhere in your route handler or controller
import { createUser } from &#8216;./userService&#8217;;

// Just call it. What does it need? Who knows.
// Knex? Email service? Logger? You can&#8217;t tell from here.
const user = await createUser({ email: &#8216;alice@example.com&#8217;, name: &#8216;Alice&#8217; });</code></pre><p>Dependencies are invisible.</p><p>The function looks simple, but it&#8217;s secretly reaching into the module graph for a database client, an email service, and a logger.</p><p>You only discover this when something breaks or when you try to test it.</p><p><strong>After DI, we use Factory + DI (explicit dependencies):</strong></p><pre><code>// In your composition root or setup code
import { createUserService } from &#8216;./userService&#8217;;
import { createUserRepo } from &#8216;./repos/userRepo&#8217;;
import { createEmailService } from &#8216;./infra/email&#8217;;
import { createLogger } from &#8216;./infra/logger&#8217;;

// Dependencies are explicit at creation time
const userService = createUserService(
  createUserRepo(knex),
  createEmailService({ apiKey: process.env.SENDGRID_KEY! }),
  createLogger({ level: &#8216;info&#8217; })
);

// Now use it &#8212; the service is fully configured
const user = await userService.createUser({ email: &#8216;alice@example.com&#8217;, name: &#8216;Alice&#8217; });</code></pre><p>Yes, the setup is more verbose. But now you can see every dependency. The function signature tells the truth.</p><p>When you read the composition root, you know exactly what each service needs, no grepping through imports, no surprises.</p><div><hr></div><h2><strong>Step 2: The Composition Root</strong> </h2><p>If every service takes its dependencies as arguments, where do you actually wire everything together?</p><p>At the <strong>composition root</strong>, the entry point of your application. This is the one place that knows about all the concrete implementations.</p><pre><code>// composition-root.ts
import Knex from &#8216;knex&#8217;;
import { createKnexDatabase } from &#8216;./infra/knexDatabase&#8217;;
import { createUserService } from &#8216;./services/userService&#8217;;
import { createOrderService } from &#8216;./services/orderService&#8217;;
import { createEmailService } from &#8216;./infra/email&#8217;;
import { createLogger } from &#8216;./infra/logger&#8217;;

export function createApp() {
  // Infrastructure
  const knex = Knex({
    client: &#8216;pg&#8217;,
    connection: process.env.DATABASE_URL,
  });
  const db = createKnexDatabase(knex);
  const email = createEmailService({ apiKey: process.env.SENDGRID_KEY! });
  const logger = createLogger({ level: &#8216;info&#8217; });

  // Repositories
  const userRepo = createUserRepo(db);
  const orderRepo = createOrderRepo(db);

  // Services
  const userService = createUserService(userRepo, email, logger);
  const orderService = createOrderService(orderRepo, userService, logger);

  return { userService, orderService, knex };
}</code></pre><pre><code>// server.ts
import express from &#8216;express&#8217;;
import { createApp } from &#8216;./composition-root&#8217;;

const app = express();
const { userService, orderService } = createApp();

app.post(&#8217;/users&#8217;, async (req, res) =&gt; {
  const user = await userService.createUser(req.body);
  res.status(201).json(user);
});</code></pre><p>Everything flows downward from one place. No global singletons. No magical auto-wiring. Just functions calling functions.</p><div><hr></div><h2><strong>When to Reach for a Container?</strong></h2><p>Manual DI works beautifully for small-to-medium apps.</p><p>But when you have 20-30+ services with complex dependency graphs, the composition root becomes hard to read and follow.</p><p>I&#8217;ve personally used <a href="https://github.com/microsoft/tsyringe">tsyringe</a>. It&#8217;s a lightweight container, easy to use and configure.</p><p><a href="https://github.com/microsoft/tsyringe">tsyringe</a> uses decorators and <code>reflect-metadata</code> to inspect constructor parameters and auto-wire dependencies.</p><p>It supports singleton, transient, and scoped lifecycles, with strong TypeScript support.</p><p>To be honest, I didn&#8217;t have any trouble with it.</p><p>Here is a simple example:</p><pre><code>import &#8216;reflect-metadata&#8217;;
import { container, injectable, inject, singleton } from &#8216;tsyringe&#8217;;
import Knex from &#8216;knex&#8217;;

@singleton()
class KnexDatabase implements Database {
  private knex = Knex({ client: &#8216;pg&#8217;, connection: process.env.DATABASE_URL });

  users = {
    create: async (data: CreateUserInput) =&gt; {
      const [user] = await this.knex(&#8217;users&#8217;).insert(data).returning(&#8217;*&#8217;);
      return user;
    },
    findById: async (id: string) =&gt; {
      return this.knex(&#8217;users&#8217;).where({ id }).first() ?? null;
    },
  };
}

container.register(&#8217;Database&#8217;, { useClass: KnexDatabase });

@injectable()
class UserService {
  constructor(@inject(&#8217;Database&#8217;) private db: Database) {}

  async createUser(data: CreateUserInput) {
    return this.db.users.create(data);
  }
}

// Resolve with all dependencies auto-wired
const userService = container.resolve(UserService);</code></pre><p>If you&#8217;re not sure whether you need a container, start simple without an additional framework.</p><p>You can easily add it later if needed.</p><div><hr></div><h2><strong>The Testing Payoff</strong></h2><p>Here&#8217;s why all this matters. Let&#8217;s compare full test files side by side.</p><h3><strong>Before: Testing with Module Mocking</strong></h3><pre><code>import { describe, it, expect, vi, beforeEach } from &#8216;vitest&#8217;;

// Mock every dependency by file path &#8212; get any path wrong and it silently breaks
vi.mock(&#8217;../lib/database&#8217;, () =&gt; ({
  knex: vi.fn().mockReturnValue({
    insert: vi.fn().mockReturnValue({
      returning: vi.fn().mockResolvedValue([{ id: &#8216;1&#8217;, email: &#8216;test@example.com&#8217; }]),
    }),
  }),
}));

vi.mock(&#8217;../lib/email&#8217;, () =&gt; ({
  sendEmail: vi.fn(),
}));

vi.mock(&#8217;../lib/logger&#8217;, () =&gt; ({
  logger: {
    info: vi.fn(),
  },
}));

// Now import the function AFTER the mocks (order matters!)
import { createUser } from &#8216;./userService&#8217;;
import { knex } from &#8216;../lib/database&#8217;;
import { sendEmail } from &#8216;../lib/email&#8217;;

describe(&#8217;createUser&#8217;, () =&gt; {
  beforeEach(() =&gt; {
    vi.clearAllMocks();
  });

  it(&#8217;creates a user and sends a welcome email&#8217;, async () =&gt; {
    const user = await createUser({ email: &#8216;test@example.com&#8217;, name: &#8216;Test&#8217; });

    expect(user.id).toBe(&#8217;1&#8217;);
    expect(sendEmail).toHaveBeenCalledWith(&#8217;test@example.com&#8217;, &#8216;Welcome!&#8217;);
  });
});</code></pre><p>Problems everywhere:</p><ul><li><p><strong>Path-coupled</strong>: rename <code>../lib/database</code> to <code>../db/database</code> and the mock breaks silently &#8212; the test passes but uses the real module</p></li><li><p><strong>Import order matters</strong>: <code>vi.mock</code> calls are hoisted, but if you get it wrong, debugging is miserable</p></li><li><p><strong>Type-unsafe</strong>: you&#8217;re casting to <code>any</code> because the mock system doesn&#8217;t know your interfaces</p></li><li><p><strong>Framework-locked</strong>: switch from Vitest to Node&#8217;s built-in test runner? Rewrite every mock</p></li></ul><h3><strong>After: Testing with DI</strong></h3><pre><code>import { describe, it, expect } from &#8216;vitest&#8217;;
import { createUserService } from &#8216;./userService&#8217;;

describe(&#8217;createUser&#8217;, () =&gt; {
  it(&#8217;creates a user and sends a welcome email&#8217;, async () =&gt; {
    // Plain objects that satisfy the interface &#8212; no mock framework needed
    const fakeRepo = {
      create: async (data: any) =&gt; ({ id: &#8216;1&#8217;, email: data.email }),
    };
    const fakeEmail = {
      send: async () =&gt; {},
    };
    const fakeLogger = {
      info: () =&gt; {},
    };

    // Track calls manually if needed (or use vi.fn() &#8212; your choice, not a requirement)
    const emailCalls: any[] = [];
    fakeEmail.send = async (to: string, subject: string) =&gt; {
      emailCalls.push({ to, subject });
    };

    const service = createUserService(fakeRepo, fakeEmail, fakeLogger);
    const user = await service.createUser({ email: &#8216;test@example.com&#8217;, name: &#8216;Test&#8217; });

    expect(user.id).toBe(&#8217;1&#8217;);
    expect(emailCalls).toEqual([{ to: &#8216;test@example.com&#8217;, subject: &#8216;Welcome!&#8217; }]);
  });

  it(&#8217;logs user creation&#8217;, async () =&gt; {
    const logs: string[] = [];
    const service = createUserService(
      { create: async (data: any) =&gt; ({ id: &#8216;42&#8217;, email: data.email }) },
      { send: async () =&gt; {} },
      { info: (msg: string) =&gt; logs.push(msg) }
    );

    await service.createUser({ email: &#8216;test@example.com&#8217;, name: &#8216;Test&#8217; });

    expect(logs).toEqual([&#8217;User created: 42&#8217;]);
  });
});</code></pre><p>The difference:</p><ul><li><p><strong>No mocking framework required</strong>: plain objects that match the interface</p></li><li><p><strong>Type-safe</strong>: TypeScript checks your fakes against the real interfaces</p></li><li><p><strong>No import order tricks</strong>: just functions and objects</p></li><li><p><strong>Portable</strong>: works with Vitest, Jest, Node&#8217;s test runner, or even a plain script</p></li><li><p><strong>Each test is self-contained</strong>: no shared mutable mock state leaks between tests</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vQvD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vQvD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 424w, https://substackcdn.com/image/fetch/$s_!vQvD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 848w, https://substackcdn.com/image/fetch/$s_!vQvD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 1272w, https://substackcdn.com/image/fetch/$s_!vQvD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vQvD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png" width="1456" height="859" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:859,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:251097,&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://thetshaped.dev/i/191737097?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.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_!vQvD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 424w, https://substackcdn.com/image/fetch/$s_!vQvD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 848w, https://substackcdn.com/image/fetch/$s_!vQvD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.png 1272w, https://substackcdn.com/image/fetch/$s_!vQvD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75616c64-f8fd-43a4-b22f-6e5bb4e4c8e3_1658x978.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><div><hr></div><h2><strong>&#128204; Key Takeaways</strong></h2><ol><li><p><strong>Dependency Injection isn&#8217;t a framework feature</strong> &#8212; it&#8217;s passing arguments to functions. You already know how to do it.</p></li><li><p><strong>Module mocking is a smell.</strong> If you need <code>vi.mock()</code> to test something, remember that something has hidden dependencies.</p></li><li><p><strong>Start with manual DI.</strong> Factory functions + a composition root covers 90% of Node.js apps.</p></li><li><p><strong>Graduate to a container (tsyringe) when your dependency graph gets complex.</strong> Not because it&#8217;s &#8220;proper&#8221;, but because it saves maintenance.</p></li><li><p><strong>The real value is testability.</strong> DI makes unit testing trivial, integration testing focused, and your architecture honest about its dependencies.</p></li></ol><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/dependency-injection-in-nodejs-and-typescript-dependency-inversion-part-no-body-teaches-you?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[Screaming Architecture & Colocation: Let Your Project Structure Tell the Story]]></title><description><![CDATA[Learn why you should organize your code by what your app actually does, not by technical roles. (5 min)]]></description><link>https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react</link><guid isPermaLink="false">https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react</guid><pubDate>Sat, 14 Mar 2026 07:19:34 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/01fd2aa6-0feb-4fb1-ac03-572fd4a7d02a_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post outlines the importance of applying Screaming Architecture and Collocation in both your back-end and front-end projects, and how this helps you and your teammates.</em></p><ul><li><p><em><a href="https://open.substack.com/pub/petarivanovv9/p/screaming-architecture-and-colocation-nodejs-typescript-react?utm_campaign=post-expanded-share&amp;utm_medium=web">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><p>Open most Node.js projects, and you see this:</p><pre><code><code>src/
&#9500;&#9472;&#9472; controllers/
&#9500;&#9472;&#9472; services/
&#9500;&#9472;&#9472; models/
&#9500;&#9472;&#9472; middleware/
&#9500;&#9472;&#9472; utils/
&#9492;&#9472;&#9472; routes/</code></code></pre><p>What does this app do?</p><p>You see that it&#8217;s an Express app. But that&#8217;s all the structure tells you.</p><p>Is it an e-commerce platform? A healthcare system? A social network?</p><p>You&#8217;d have to open files and read code to find out.</p><p>That&#8217;s the problem.</p><div><hr></div><h2>What Is Screaming Architecture?</h2><p>Uncle Bob coined the term:</p><blockquote><p><strong>Your project structure should </strong><em><strong>scream</strong></em><strong> what the application does, not what framework it uses.</strong></p></blockquote><p>For example, a healthcare app should look like this:</p><pre><code><code>src/
&#9500;&#9472;&#9472; patients/
&#9500;&#9472;&#9472; appointments/
&#9500;&#9472;&#9472; prescriptions/
&#9500;&#9472;&#9472; billing/
&#9492;&#9472;&#9472; shared/</code></code></pre><p>You open the folder and immediately know: this is a healthcare system.</p><p>The domain is front and center.</p><p>Express, REST, GraphQL, Prisma, React, those are implementation details, tucked inside each feature.</p><p>And this is not just about aesthetics.</p><p>When <strong>folders map to business capabilities</strong>, you get:</p><ul><li><p><strong>Discoverability</strong>: New developers find code faster.</p></li><li><p><strong>Ownership</strong>: Teams own features, not layers.</p></li><li><p><strong>Change isolation</strong>: Modifying &#8220;appointments&#8221; doesn&#8217;t require touching 5 different layer folders.</p></li><li><p><strong>Deletion</strong>: You can remove an entire feature by deleting one folder.</p></li><li><p><strong>Low/High Coupling</strong>: Low coupling between features and High coupling for a single feature.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ow4z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ow4z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Ow4z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Ow4z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Ow4z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ow4z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg" width="1718" height="948" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:948,&quot;width&quot;:1718,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:157616,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/190265218?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db9be8a-4158-4185-be3c-a33de4f2e135_2000x1490.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ow4z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Ow4z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Ow4z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Ow4z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15027ec9-b1f7-4d53-85a0-f47ea6052a93_1718x948.jpeg 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>Or we could also look at it in another way to see more clearly how a single feature maps across different technical layers:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CysD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CysD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 424w, https://substackcdn.com/image/fetch/$s_!CysD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 848w, https://substackcdn.com/image/fetch/$s_!CysD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 1272w, https://substackcdn.com/image/fetch/$s_!CysD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CysD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png" width="962" height="504" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:504,&quot;width&quot;:962,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:117607,&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://thetshaped.dev/i/190265218?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.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_!CysD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 424w, https://substackcdn.com/image/fetch/$s_!CysD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 848w, https://substackcdn.com/image/fetch/$s_!CysD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.png 1272w, https://substackcdn.com/image/fetch/$s_!CysD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b20ab5a-60aa-4213-a013-956fd44694ca_962x504.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><div><hr></div><h2>The Colocation Principle</h2><p>In the React world, we must strive to:</p><blockquote><p><strong>Keep things as close as possible to where they're used.</strong></p></blockquote><p>Consider the following hierarchy:</p><ol><li><p>If only one component uses it &#8594; put it in that component&#8217;s file</p></li><li><p>If only components in one folder use it &#8594; put it in that folder</p></li><li><p>If multiple folders use it &#8594; move it up to the nearest shared parent</p></li><li><p>If the whole app uses it &#8594; put it in <code>shared/</code> or <code>lib/</code></p></li></ol><p>This is the same idea as screaming architecture, applied at a granular level.</p><p>Don't prematurely extract.</p><p>Don't create <code>utils/</code> and <code>helpers/</code> folders that become junk drawers.</p><div><hr></div><h2>Combining Both: Feature-First Structure</h2><p>Here&#8217;s what a feature-first Node.js project looks like when you combine screaming architecture with colocation:</p><pre><code><code>src/
&#9500;&#9472;&#9472; patients/
&#9474;   &#9500;&#9472;&#9472; patient.controller.ts
&#9474;   &#9500;&#9472;&#9472; patient.service.ts
&#9474;   &#9500;&#9472;&#9472; patient.repository.ts
&#9474;   &#9500;&#9472;&#9472; patient.types.ts
&#9474;   &#9500;&#9472;&#9472; patient.validation.ts
&#9474;   &#9500;&#9472;&#9472; patient.routes.ts
&#9474;   &#9492;&#9472;&#9472; __tests__/
&#9474;       &#9500;&#9472;&#9472; patient.service.test.ts
&#9474;       &#9492;&#9472;&#9472; patient.controller.test.ts
&#9500;&#9472;&#9472; appointments/
&#9474;   &#9500;&#9472;&#9472; appointment.controller.ts
&#9474;   &#9500;&#9472;&#9472; appointment.service.ts
&#9474;   &#9500;&#9472;&#9472; appointment.repository.ts
&#9474;   &#9500;&#9472;&#9472; appointment.types.ts
&#9474;   &#9500;&#9472;&#9472; appointment.validation.ts
&#9474;   &#9500;&#9472;&#9472; appointment.routes.ts
&#9474;   &#9492;&#9472;&#9472; __tests__/
&#9474;       &#9492;&#9472;&#9472; appointment.service.test.ts
&#9500;&#9472;&#9472; shared/
&#9474;   &#9500;&#9472;&#9472; middleware/
&#9474;   &#9474;   &#9500;&#9472;&#9472; auth.middleware.ts
&#9474;   &#9474;   &#9492;&#9472;&#9472; error-handler.ts
&#9474;   &#9500;&#9472;&#9472; database/
&#9474;   &#9474;   &#9492;&#9472;&#9472; prisma.ts
&#9474;   &#9492;&#9472;&#9472; types/
&#9474;       &#9492;&#9472;&#9472; common.ts
&#9500;&#9472;&#9472; app.ts
&#9492;&#9472;&#9472; server.ts
</code></code></pre><p>Every feature is self-contained.</p><p>Tests live next to the code they test.</p><p>Shared infrastructure sits in <code>shared/</code>, but only things that are genuinely shared across features.</p><div><hr></div><h2><strong>The Same Principle in React</strong></h2><pre><code><code>src/
&#9500;&#9472;&#9472; features/
&#9474;   &#9500;&#9472;&#9472; patients/
&#9474;   &#9474;   &#9500;&#9472;&#9472; PatientList.tsx
&#9474;   &#9474;   &#9500;&#9472;&#9472; PatientDetail.tsx
&#9474;   &#9474;   &#9500;&#9472;&#9472; usePatients.ts
&#9474;   &#9474;   &#9500;&#9472;&#9472; patient.types.ts
&#9474;   &#9474;   &#9492;&#9472;&#9472; patient.api.ts
&#9474;   &#9500;&#9472;&#9472; appointments/
&#9474;   &#9474;   &#9500;&#9472;&#9472; AppointmentCalendar.tsx
&#9474;   &#9474;   &#9500;&#9472;&#9472; BookAppointment.tsx
&#9474;   &#9474;   &#9500;&#9472;&#9472; useAppointments.ts
&#9474;   &#9474;   &#9492;&#9472;&#9472; appointment.api.ts
&#9500;&#9472;&#9472; shared/
&#9474;   &#9500;&#9472;&#9472; components/
&#9474;   &#9474;   &#9500;&#9472;&#9472; Button.tsx
&#9474;   &#9474;   &#9492;&#9472;&#9472; Modal.tsx
&#9474;   &#9500;&#9472;&#9472; hooks/
&#9474;   &#9474;   &#9492;&#9472;&#9472; useAuth.ts
&#9474;   &#9492;&#9472;&#9472; lib/
&#9474;       &#9492;&#9472;&#9472; api-client.ts
&#9500;&#9472;&#9472; App.tsx
&#9492;&#9472;&#9472; main.tsx
</code></code></pre><p>Same idea.</p><p>Features own their components, hooks, types, and API calls.</p><p><code>shared/</code> contains only genuinely reusable pieces.</p><div><hr></div><h2>When Layers Still Make Sense</h2><p>Layers aren&#8217;t always wrong. They work when:</p><ul><li><p><strong>Your app is small</strong> (&lt; 10 files). Feature folders are overhead for a simple CRUD API.</p></li><li><p><strong>You&#8217;re building a library</strong>. Internal structure matters less than the public API.</p></li><li><p><strong>Your team is one person</strong>. You already know where everything is.</p></li></ul><p>The pragmatic hybrid: <strong>features at the top level, layers within each feature.</strong></p><p>Each feature has its own controller, service, repository, but they&#8217;re colocated, not scattered.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, Software Architecture, and Career Development delivered straight to your inbox:</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>Enforcing Boundaries</h2><p>Structure without enforcement is just a suggestion.</p><p>Here's how to make it stick:</p><h3>ESLint (with <code>eslint-plugin-boundaries</code>)</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">// .eslintrc.js
module.exports = {
  plugins: ['boundaries'],
  settings: {
    'boundaries/elements': [
      { type: 'patients', pattern: 'src/patients/*' },
      { type: 'appointments', pattern: 'src/appointments/*' },
      { type: 'shared', pattern: 'src/shared/*' },
    ],
  },
  rules: {
    'boundaries/element-types': [2, {
      default: 'disallow',
      rules: [
        { from: 'patients', allow: ['shared'] },
        { from: 'appointments', allow: ['shared', 'patients'] },
      ],
    }],
  },
};</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mR-g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mR-g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 424w, https://substackcdn.com/image/fetch/$s_!mR-g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 848w, https://substackcdn.com/image/fetch/$s_!mR-g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 1272w, https://substackcdn.com/image/fetch/$s_!mR-g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mR-g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png" width="1456" height="1106" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1106,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:329283,&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://thetshaped.dev/i/190265218?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.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_!mR-g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 424w, https://substackcdn.com/image/fetch/$s_!mR-g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 848w, https://substackcdn.com/image/fetch/$s_!mR-g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.png 1272w, https://substackcdn.com/image/fetch/$s_!mR-g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bee52f0-3652-488c-aea3-54179d52e97b_1986x1508.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>TypeScript Project References</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// src/shared/tsconfig.json &#8212; every referenced project needs composite: true
{
  "compilerOptions": {
    "composite": true,
    "rootDir": ".",
    "outDir": "../../dist/shared"
  }
}</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">// src/patients/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "rootDir": ".",
    "outDir": "../../dist/patients"
  },
  "references": [
    { "path": "../shared" }
  ]
}</code></pre></div><p>Each feature is a TypeScript project.</p><p>It can only reference what's listed in <code>references</code>.</p><p>The compiler enforces boundaries at build time.</p><div><hr></div><h2>&#128204; Key Takeaways</h2><ol><li><p><strong>Your folder structure is documentation.</strong> It should tell a new developer what the app does in 5 seconds.</p></li><li><p><strong>Organize by feature, not by layer.</strong> Controllers, services, and models for the same feature belong together.</p></li><li><p><strong>Colocate aggressively.</strong> Tests, types, and utilities live next to the code that uses them. Move things to <code>shared/</code> only when two or more features need them.</p></li><li><p><strong>Migrate incrementally.</strong> One feature at a time, one PR at a time. No big-bang restructures.</p></li><li><p><strong>Enforce with tooling.</strong> ESLint boundaries, TypeScript project references, or Nx module boundaries. Structure without enforcement decays.</p></li></ol><div class="pullquote"><p><strong>The best architecture is invisible. When a developer opens your project and immediately knows where to find what they need, without reading a README or asking a teammate, your structure is doing its job.</strong></p></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/screaming-architecture-and-colocation-nodejs-typescript-react?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p style="text-align: center;"><em><strong>Press the Like button if you found this post helpful</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[4 Disciplines That Separate Effective Engineers From Busy Ones]]></title><description><![CDATA[Learn about the daily habits that help engineers be more effective. (7 min)]]></description><link>https://thetshaped.dev/p/four-disciplines-that-separate-effective-software-engineers-from-busy-engineers</link><guid isPermaLink="false">https://thetshaped.dev/p/four-disciplines-that-separate-effective-software-engineers-from-busy-engineers</guid><pubDate>Tue, 24 Feb 2026 11:19:19 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7db15d0a-e497-4d86-bc0b-872f4b740762_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post outlines my personal experience working with numerous engineers across various companies and distilling what habits an effective engineer has.</em></p><p><em>Those engineers ship less, talk more, think further ahead, and treat AI like a power tool, not a replacement for judgment.</em></p><ul><li><p><em><a href="https://thetshaped.dev/p/four-disciplines-that-separate-effective-software-engineers-from-busy-engineers">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><p>Imagine spending six weeks building a sleek, real-time notification system that nobody actually requested.</p><p>You nailed down the &#8220;right architecture&#8221;, covered the codebase with tests, and perfected the documentation.</p><p>Then comes the week before launch. Your PM demos the masterpiece, and suddenly part of your customers refuse to use it while the other asks why a certain bug still exists.</p><p>Stories like this project remind me of the difference between being <em>efficient</em> and being <em>effective</em>.</p><blockquote><p><strong>Efficient engineers do things right.</strong></p><p><strong>Effective engineers do the right things.</strong></p></blockquote><p>After 8+ years of shipping software, hiring engineers, and watching teams succeed and fail, I&#8217;ve distilled what makes engineers genuinely effective into four disciplines.</p><p>And none of them is about writing clever code.</p><div><hr></div><h2><strong><a href="https://brightdata.com/ai/mcp-server?utm_source=brand&amp;utm_campaign=brnd-mkt_newsletter_petar">BrightData: Connect Your AI To The Internet&#8217;s Data - Sponsor</a></strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://brightdata.com/ai/mcp-server?utm_source=brand&amp;utm_campaign=brnd-mkt_newsletter_petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GKHx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!GKHx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!GKHx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!GKHx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GKHx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png" width="1200" height="630" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:630,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:266997,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://brightdata.com/ai/mcp-server?utm_source=brand&amp;utm_campaign=brnd-mkt_newsletter_petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/185405137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!GKHx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!GKHx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!GKHx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!GKHx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0755e22-597b-425f-a9b9-131d60c57a5d_1200x630.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><a href="https://brightdata.com/ai/mcp-server?utm_source=brand&amp;utm_campaign=brnd-mkt_newsletter_petar">Bright Data</a>&#8217;s Web MCP solves web access for LLMs and AI agents, allowing them to effectively search, extract, and navigate the web without getting blocked. It helps to:</p><ul><li><p>Search the web in real-time</p></li><li><p>Extract data from any website</p></li><li><p>Navigate and interact with pages</p></li><li><p>Bypass blocks and restrictions</p></li></ul><p>It comes with a generous free tier - 5,000 MCP requests every month - for free!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://brightdata.com/ai/mcp-server?utm_source=brand&amp;utm_campaign=brnd-mkt_newsletter_petar&quot;,&quot;text&quot;:&quot;Try For Free&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://brightdata.com/ai/mcp-server?utm_source=brand&amp;utm_campaign=brnd-mkt_newsletter_petar"><span>Try For Free</span></a></p><div><hr></div><h1>1. Solve the Right Problems; Not Just Any Problem</h1><p><em>Traits: Care about the user. Understand team strategy. Prioritize ruthlessly.</em></p><p>The most expensive line of code is the one that solves the wrong problem.</p><p>I&#8217;ve seen teams spending time into plubming, like managing a custom-built deployment pipeline, instead of leveraging  $50/month SaaS.</p><p>Here is the uncomfortable part: most engineers aren&#8217;t trained to say no.</p><p>We&#8217;re rewarded for building. Promotions come from shipping. Saying &#8220;we shouldn&#8217;t build this&#8221; doesn&#8217;t show up in a pull request.</p><p>But caring about users, I mean actually caring, not only claiming that on a performance review, means understanding their real problems deeply enough to know which solutions are worth pursuing and which are engineering vanity projects.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Adpn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Adpn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 424w, https://substackcdn.com/image/fetch/$s_!Adpn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 848w, https://substackcdn.com/image/fetch/$s_!Adpn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 1272w, https://substackcdn.com/image/fetch/$s_!Adpn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Adpn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png" width="480" height="273.6448598130841" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:366,&quot;width&quot;:642,&quot;resizeWidth&quot;:480,&quot;bytes&quot;:327310,&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://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.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_!Adpn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 424w, https://substackcdn.com/image/fetch/$s_!Adpn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 848w, https://substackcdn.com/image/fetch/$s_!Adpn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.png 1272w, https://substackcdn.com/image/fetch/$s_!Adpn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586cab84-1626-42f9-87bc-c5a013cae14e_642x366.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>And you can&#8217;t make that judgment in a vacuum.</p><p>You need to understand your <strong>team&#8217;s strategy</strong>:</p><ul><li><p>What are we trying to accomplish this quarter?</p></li><li><p>How does my work connect to revenue, retention, or reliability?</p></li></ul><p>Engineers who can answer those questions prioritize themselves.</p><p>Engineers who can&#8217;t are always waiting to be told what to do next.</p><p>So next time, before writing any line of code, force yourself through these three questions:</p><ul><li><p><strong>Who suffers if this doesn&#8217;t ship?</strong> If the answer is &#8220;nobody, really,&#8221; put it in the icebox.</p></li><li><p><strong>What&#8217;s the cheapest version that tests the hypothesis?</strong> A spreadsheet, a Figma prototype, or a hardcoded endpoint can often answer the question a six-week feature build was supposed to answer.</p></li><li><p><strong>What am I not doing by doing this?</strong> Opportunity cost is invisible until you&#8217;ve missed a deadline on the thing that actually mattered.</p></li></ul><p>Of course, we can&#8217;t do some of these things by ourselves. That&#8217;s why we have Product Managers who are the point of contact to the end users and our organization.</p><p><strong>Our job as Effective Engineers is to advocate for users, do extensive user research, and prioritize user needs.</strong></p><div><hr></div><h1>2. Keep It Simple; Leave It Better</h1><p><em>Traits: Simplicity over cleverness. Quality as a discipline. The Boy Scout Rule.</em></p><p>I&#8217;ve reviewed pull requests where the author used three levels of abstraction to avoid repeating four lines of code.</p><p>The DRY principle is good. But taken to its extreme, it produces code that&#8217;s &#8220;elegant&#8221; but unreadable to everyone except the person who wrote it, and often to them too, three months later.</p><p>Simplicity isn&#8217;t the absence of thought. It&#8217;s the result of deep thought.</p><p>It means you&#8217;ve understood the problem well enough to solve it without over-engineering.</p><p>The engineers I respect most write code that a new team member can read on their first day and say, &#8220;Okay, I see what this does&#8221;.</p><p>But simplicity alone isn&#8217;t enough.</p><p>The effective engineers also leave things better than they found them.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L9cW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L9cW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 424w, https://substackcdn.com/image/fetch/$s_!L9cW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 848w, https://substackcdn.com/image/fetch/$s_!L9cW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 1272w, https://substackcdn.com/image/fetch/$s_!L9cW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L9cW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png" width="470" height="174.22413793103448" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:258,&quot;width&quot;:696,&quot;resizeWidth&quot;:470,&quot;bytes&quot;:337172,&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://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.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_!L9cW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 424w, https://substackcdn.com/image/fetch/$s_!L9cW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 848w, https://substackcdn.com/image/fetch/$s_!L9cW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 1272w, https://substackcdn.com/image/fetch/$s_!L9cW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F595a344b-ac8d-4525-9a87-61bf97c678da_696x258.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Every PR is an opportunity: fix a flaky test, update a stale README, delete dead code, or rename a confusing variable.</p><p>None of these show up in a sprint demo.</p><p>All of them compound into a codebase that&#8217;s a joy to work with versus one that slowly rots.</p><p>So the next time you write and ship code, try to:</p><ul><li><p><strong>Set a complexity budget.</strong> If a solution requires more than one new abstraction, pressure-test whether that abstraction earns its keep. Often it doesn&#8217;t.</p></li><li><p><strong>Timebox polish.</strong> I allocate roughly 10-15% of every feature&#8217;s time for cleanup, not gold-plating, but genuine improvement to the code I touched and the code around it.</p></li><li><p><strong>Measure quality that matters.</strong> Track things like time-to-first-meaningful-PR-review for new hires, or incident rate per deploy. These tell you more about codebase health than test coverage percentages.</p></li></ul><p>You have to be comfortable with invisible contributions.</p><p>The payoff comes in months, not days: fewer incidents, faster onboarding, less time debugging code nobody understands.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, Software Architecture, and Career Development delivered straight to your inbox:</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><h1>3. Earn Trust; Communicate Relentlessly</h1><p><em>Traits: Build trust and social capital. Communicate effectively. Operate with autonomy.</em></p><p>Early in my career, I thought trust was a soft-skills thing, something you got for free by being &#8220;nice&#8221;.</p><p>That&#8217;s not how it works.</p><p>Trust is an engineering asset.</p><p>It&#8217;s the reason one engineer can get a risky refactor approved in a single meeting while another spends two sprints writing a design doc that still gets rejected.</p><p>Think about it mechanically: engineers who&#8217;ve built trust get more autonomy.</p><p>More autonomy means they can take bigger swings.</p><p>Bigger swings, when they land, build <em>more</em> trust. It compounds like interest.</p><p>And the inverse is just as powerful: one blown deadline or one surprise production incident you didn&#8217;t communicate about can set you back months of accumulated credibility.</p><p>Communication is the engine that drives all of this.</p><p>Not &#8220;being good at presentations&#8221;, I mean the boring, daily discipline of keeping people informed. Status updates nobody asked for. A Slack message before you merge something risky. Flagging a blocker on Day 1 instead of Day 5.</p><p>The engineers who do this consistently become the ones everyone wants on their project.</p><p>Here are a few things you could try:</p><ul><li><p><strong>Estimate honestly, then pad 20%.</strong> On one project, I started adding explicit &#8220;risk buffers&#8221; to my estimates, and my on-time delivery rate went from roughly 60% to over 85% in two quarters.</p></li><li><p><strong>Communicate bad news early.</strong> If a project is slipping, saying so on Day 3 builds trust. Saying so on Day 13 destroys it. I&#8217;ve never seen anyone punished for early transparency. I&#8217;ve seen plenty punished for late surprises.</p></li><li><p><strong>Review others&#8217; code generously.</strong> Fast, thoughtful code reviews are one of the highest-leverage trust-building activities in engineering. They signal &#8220;I respect your time and your work&#8221;. They also build social capital, the kind of relationship equity that means people answer your Slack messages in minutes instead of hours.</p></li><li><p><strong>Invest in relationships outside your team.</strong> Grab coffee with the infrastructure team. Understand what the data team is struggling with. Cross-team relationships pay dividends when you need a favor, a quick answer, or buy-in on a proposal.</p></li></ul><p>Building trust slowly means you won't be the hero on Day 1. You might watch a louder, faster colleague get more visibility early on. The patience required is real.</p><p>And there's an uncomfortable truth: trust is context-dependent.</p><p>Switching teams or companies resets the meter. You have to be willing to re-invest every time.</p><div><hr></div><h1>4. Think Long-Term; Adapt Constantly</h1><p><em>Traits: Second-order thinking. Comfort with new challenges. Wielding AI as a force multiplier.</em></p><p>Junior engineers think about whether their code works. Mid-level engineers think about whether their code is maintainable. Senior engineers think about what their code <em>causes</em>, downstream, six months from now, in systems they don't own.</p><p>And here's the thing that's changed in the last two years:</p><blockquote><p>Long-term thinking now includes your relationship with AI tooling.</p></blockquote><p>The engineers who treat GitHub Copilot, Claude, or Cursor as magic black boxes are building on sand.</p><p>The ones who understand what these tools are good at (boilerplate, scaffolding, routine refactors), what they're bad at (nuanced architecture decisions, security edge cases, understanding your specific business context), and how to verify their output, are the engineers who are genuinely 2-3x more productive.</p><p>But only because they bring the judgment the AI lacks.</p><blockquote><p><strong>Treat AI-generated code like a pull request from a confident but context-blind junior.</strong></p><p>Review every line. Question every assumption. The speed is real, but so are the subtle bugs.</p></blockquote><p>Being comfortable with new challenges has always mattered. Now it's existential.</p><p>The landscape shifts every six months.</p><p>The engineers who thrive aren't the ones who memorize every new framework.</p><p>They're the ones who've <strong>built strong enough fundamentals that they can pick up any tool quickly and evaluate it critically</strong>.</p><p>Second-order thinking is slow.</p><p>Learning new tools takes time away from shipping.</p><p>There's a real risk of analysis paralysis, and an equally real risk of chasing every new AI tool instead of mastering the one you have.</p><p>The discipline is knowing when the blast radius is large enough to warrant the extra thought, and when to just ship.</p><div><hr></div><p>You can learn a new framework in a weekend.</p><p>You can learn a new AI tool in an afternoon.</p><p>These four disciplines take years. Start now.</p><p>See you next time! &#128588;</p><p><em>PS:</em> My friend Marko Denic has recently launched his new FREE e-book: <a href="https://dailytips.dev/ebook/">The Technical Decision Framework</a>. It&#8217;s about a framework for the choices that shape your codebase.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, Software Architecture, and Career Development delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/intent/follow?screen_name=petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EvJY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/four-disciplines-that-separate-effective-software-engineers-from-busy-engineers?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/four-disciplines-that-separate-effective-software-engineers-from-busy-engineers?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UzWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif" width="48" height="57.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:500,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:7028,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188785536?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UzWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 424w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 848w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!UzWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39609b45-f68c-4557-8772-8e2a45182842_500x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Press the Like button if you found this post helpful</strong></p></div>]]></content:encoded></item><item><title><![CDATA[Database Design Doesn't Start With Table. It Starts With Consequences]]></title><description><![CDATA[Here's what most backend engineers get wrong about schema design and how to fix it before you hit production. (6 min)]]></description><link>https://thetshaped.dev/p/database-design-foundations-backend-engineers-mistakes-and-lessons</link><guid isPermaLink="false">https://thetshaped.dev/p/database-design-foundations-backend-engineers-mistakes-and-lessons</guid><pubDate>Tue, 17 Feb 2026 05:19:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b499f478-3f17-4fa8-8307-6a1eb1a2600c_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post is an introduction to database design, a foundational concept for backend engineers, highlighting its importance and how to get it right before it&#8217;s too late.</em></p><ul><li><p><em><a href="https://open.substack.com/pub/petarivanovv9/p/database-design-foundations-backend-engineers-mistakes-and-lessons?r=643nm&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true">Share this post</a> &amp; I&#8217;ll send you some rewards for the referrals.</em></p></li></ul><div><hr></div><p>Imagine a team launches a new product. Traffic grows. Everything&#8217;s fine. </p><p>Then one day, a query takes 8 seconds instead of 80ms. Engineers start adding indexes. Caching layers. Read replicas.</p><p>None of it helps enough.<br><br>The problem wasn't performance. It was bad database design. And by the time they realized it, they had 200 million rows in production and a Slack channel dedicated to database incidents.</p><blockquote><p>Database decisions are long-term bets. </p><p>Get them wrong early, and you'll spend years firefighting.</p><p>Get them right, and your system scales quietly while you build features.</p></blockquote><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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>Your Schema Will Outlive Your Code. Plan Accordingly.</h2><p>A careless column type. A missing foreign key constraint. An unnecessary denormalization because &#8220;it might be faster&#8221;.<br><br>These choices feel small when you're building v1. But databases are permanent in ways code isn't.</p><p>You can refactor a service in a weekend. </p><p>A schema migration on a table with 500 million rows in PostgreSQL?</p><p>That's a multi-month project involving table locks, replica lag monitoring, and very careful coordination with the ops team, who definitely don't want to hear from you at 2 AM.</p><p>The teams that win long-term <strong>treat table design with the same respect they give code architecture</strong>. Maybe more, because you can't just roll back a schema change when 50 million user records depend on it.</p><div><hr></div><h2>Start With Reality, Not With Tables.</h2><p>Most engineers rush straight to <code>CREATE TABLE</code> before understanding what they're actually modeling.<br><br>Don't do this.<br><br><strong>Spend real time mapping the business domain</strong>.</p><p>What entities exist in the real world? What relationships matter to the business? What constraints does reality enforce that your database should mirror?</p><p>If you&#8217;re building a job board, understand that a job posting isn&#8217;t just a row. It has a lifecycle: draft, published, filled, and expired. It belongs to a company. It attracts applications. Each application connects a candidate to a posting.<br><br>The <strong>database should enforce what the domain requires</strong>.</p><p>If your schema allows states that can't exist in reality, eventually someone will put your data into one of those states.</p><div><hr></div><h2>Normalization Is Your Friend (Until It Isn&#8217;t)</h2><p>Normalization means organizing data to eliminate redundancy and dependency issues.</p><p>Third normal form (3NF) is the target - every column depends on the primary key, the whole key, and nothing but the key.</p><p>In practice, this means that a user's data is in one table, addresses in another, and orders in a third. Then, we join them when needed.</p><p>This prevents update anomalies. We change a user&#8217;s email once, not in seventeen places. We can also safely delete an order without losing customer data.</p><p>But <strong>over-normalization can destroy read performance</strong>.</p><p>If your application shows &#8220;user profile with last 10 orders&#8221; on every page load, and that requires five joins across normalized tables, you&#8217;re paying a cost.</p><p>A good rule of thumb is:</p><blockquote><p>Let query patterns guide your final design.</p><p>Start normalized.</p><p>Denormalize deliberately when you have real performance data.</p></blockquote><p>To mitigate the above-mentioned problem, we might want to add a materialized view that flattens this query and then refresh it on writing.</p><p>Or we can do something else, depending on the business case and needs.</p><p><strong>Denormalization is a tool. Use it when the tradeoff is clear.</strong></p><div><hr></div><h2>Indexes: The Contract You Make With Future You</h2><p>An index is a data structure that makes lookups fast by avoiding full table scans.</p><p>Without an index on <code>users.email</code>, a query like <code>WHERE email = 'user@example.com'</code> checks every row. With an index, it jumps directly to the match.</p><p>But indexes aren&#8217;t free.</p><p>Every index slows down writes. The database must update the index on every INSERT, UPDATE, or DELETE. Indexes consume disk space. And poorly chosen indexes bloat over time, requiring maintenance.</p><p><strong>The strategy I follow:</strong></p><ul><li><p>Index foreign keys and columns used in WHERE, JOIN, and ORDER BY clauses</p></li><li><p>Avoid indexing columns with low cardinality (e.g., boolean flags)</p></li><li><p>Use composite indexes when queries filter on multiple columns together</p></li><li><p>Monitor and rebuild indexes periodically to prevent fragmentation</p></li></ul><p>Hint: Use <strong>pg_stat_user_indexes</strong> to monitor index usage in PostgreSQL.</p><blockquote><p>Index deliberately.</p><p>Measure the impact using E<code>PLAIN ANALYZE</code>.</p><p>Remove what doesn't serve you.</p></blockquote><div><hr></div><h2>Constraints Are The Best Documentation You&#8217;ll Ever Write</h2><p>Foreign keys. <code>NOT NULL</code>. <code>UNIQUE</code>. <code>CHECK</code> constraints.</p><p>These aren&#8217;t optional guardrails. They&#8217;re how you encode business rules into the database itself.</p><p>A foreign key constraint ensures referential integrity. If <code>orders.user_id</code> references <code>users.id</code>, you can&#8217;t have an orphaned order pointing to a deleted user.</p><p>A NOT NULL constraint guarantees a value exists. No defensive null checks in application code.</p><p>A CHECK constraint validates data at write time. Age must be positive. Status must be one of five valid values.</p><p>This matters because <strong>constraints catch bugs before they corrupt data</strong>.</p><p>Constraints add minor write overhead, maybe 1-2%, or sometimes less. But they give you guaranteed correctness.</p><p>If your database allows invalid data, eventually you&#8217;ll have invalid data.</p><div><hr></div><h2>Performance Is A Design Choice, Not a Tuning Exercise</h2><p>I&#8217;ve seen teams spend weeks chasing query plans, adding caches, and tuning connection pools.</p><p>Most of the time, the real problem is the schema.</p><p>A single redesign could fix the issue forever: moving a frequently-joined column into the main table, splitting a bloated table into hot and cold storage, adding a covering index, and partitioning by time range.</p><p>Here's what makes database design genuinely hard: you don't know the full business context at the start. Requirements evolve. Query patterns change.</p><p>The answer isn&#8217;t perfection upfront. It&#8217;s about designing for change.</p><p><strong>Keep things simple. Use clear naming conventions. Avoid premature optimization. And critically, don't be afraid to migrate the schema when you learn something new about your domain or your access patterns.</strong></p><p>A well-designed schema can handle 10x growth with minor adjustments. A poorly designed one requires rewrites.</p><div><hr></div><h2>What I Wish Someone Had Told Me</h2><p>If I could give my younger self advice, I'd say this:<br><br><strong>Practice designing schemas for real systems.</strong> Pick LinkedIn, Twitter, or Airbnb. Map the entities. Draw the relationships. Think through the queries. Do it on paper before you touch a database.</p><p><strong>Learn SQL deeply.</strong> Not just <code>SELECT</code> and <code>JOIN</code>. Window functions. CTEs. Query plans. Execution order. Understand what the database does with your query.<br><br><strong>Start simple, but extensible.</strong> Don't build for scale you don't have. But leave room to grow. Design your schema so that adding columns or splitting tables doesn't require a full rewrite.<br><br><strong>Measure everything.</strong> You can't optimize what you don't measure. Track query times. Index usage. Table sizes. Slow query logs.<br><br>The best engineers I know treat database design like architecture. They think through the consequences of their decisions. They plan for failure modes. They build systems that last, not just systems that work.<br><br>And they're never ashamed to run a migration when they learn something new.<br><br><strong>Because databases don't forget your mistakes, but they do forgive your improvements.</strong></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get practical tips on React.js, Node.js, and Software Architecture delivered straight to your inbox:</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 class="pullquote"><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cmMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cmMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png" width="248" height="207.7" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:800,&quot;resizeWidth&quot;:248,&quot;bytes&quot;:257716,&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://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ebf3ac-ad2f-415d-9e32-111e959c8e4e_800x800.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_!cmMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 424w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 848w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1272w, https://substackcdn.com/image/fetch/$s_!cmMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aea932b-6248-4324-9ec7-68d0bfed782e_800x670.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Follow me on <a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong> | <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong> |<strong> <a href="https://www.threads.net/@petarivanovv9">Threads</a></strong></p></div><p>Thank you for supporting this newsletter.</p><p>Consider sharing this post with your friends and get rewards.</p><p>You are the best! &#128591;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://open.substack.com/pub/petarivanovv9/p/database-design-foundations-backend-engineers-mistakes-and-lessons?r=643nm&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:&quot;https://open.substack.com/pub/petarivanovv9/p/database-design-foundations-backend-engineers-mistakes-and-lessons?r=643nm&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/188025481?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EvJY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EvJY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa356e02d-1b11-4eca-81ea-3db29a595cb9_800x500.jpeg 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/p/database-design-foundations-backend-engineers-mistakes-and-lessons?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/p/database-design-foundations-backend-engineers-mistakes-and-lessons?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="pullquote"><p><strong>Press the Like button if you found this post helpful</strong></p></div>]]></content:encoded></item><item><title><![CDATA[Invite Your Friends & Earn Rewards 🎁]]></title><description><![CDATA[Announcing the T-Shaped Dev Referral Program! &#127881;]]></description><link>https://thetshaped.dev/p/invite-your-friends-and-earn-rewards</link><guid isPermaLink="false">https://thetshaped.dev/p/invite-your-friends-and-earn-rewards</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 27 Jan 2026 13:01:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Em8X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Thank you for reading The T-Shaped Dev &#8212; your support allows me to keep doing this work.</p><p>If you enjoy The T-Shaped Dev, it would mean the world to me if you invited friends to subscribe and read with us. If you refer friends, you will receive benefits that give you special access to The T-Shaped Dev.</p><p><strong>How to participate </strong></p><p><strong>1. Share The T-Shaped Dev. </strong>When you use the referral link below, or the &#8220;Share&#8221; button on any post, you'll get credit for any new subscribers. Simply send the link in a text, email, or share it on social media with friends.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/leaderboard?&amp;utm_source=post&quot;,&quot;text&quot;:&quot;Refer a friend&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://thetshaped.dev/leaderboard?&amp;utm_source=post"><span>Refer a friend</span></a></p><p>2.<strong> Earn benefits.</strong> When more friends use your referral link to subscribe (free or paid), you&#8217;ll receive special benefits.</p><ul><li><p>Get <strong>Pull Request Checklist</strong> for <strong>1 referrals</strong></p></li><li><p>Get <strong>Brag List (Work Log) Template</strong> for <strong>2 referrals</strong></p></li><li><p>Get <strong>Technical Design Document Template</strong> for <strong>3 referrals</strong></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Em8X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Em8X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 424w, https://substackcdn.com/image/fetch/$s_!Em8X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 848w, https://substackcdn.com/image/fetch/$s_!Em8X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 1272w, https://substackcdn.com/image/fetch/$s_!Em8X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Em8X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90566,&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://thetshaped.dev/i/185955792?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.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_!Em8X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 424w, https://substackcdn.com/image/fetch/$s_!Em8X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 848w, https://substackcdn.com/image/fetch/$s_!Em8X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.png 1272w, https://substackcdn.com/image/fetch/$s_!Em8X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18c44996-187d-412e-ada7-8f2ea52f974a_800x500.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>Refer just 3 people &amp; I'll send you some rewards. &#127873;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/leaderboard?&amp;utm_source=post&quot;,&quot;text&quot;:&quot;Refer a friend&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://thetshaped.dev/leaderboard?&amp;utm_source=post"><span>Refer a friend</span></a></p>]]></content:encoded></item><item><title><![CDATA[How to 10x Your Code Quality With Three AI Tools]]></title><description><![CDATA[Learn how to build software smartly with Advisor, Generator & Reviewer AI Agents (5 min)]]></description><link>https://thetshaped.dev/p/how-to-10x-your-code-quality-with-three-ai-tools-advisors-generators-reviewers</link><guid isPermaLink="false">https://thetshaped.dev/p/how-to-10x-your-code-quality-with-three-ai-tools-advisors-generators-reviewers</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Sat, 17 Jan 2026 07:19:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a6989583-b9ce-4568-859d-3a82ca0ee348_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 29,500+ engineers to receive one practical tip on JS, React, NodeJS, Software Design, and Architecture every 1-2 weeks.</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><p>Imagine you&#8217;re using one AI tool for everything - designing, planning, coding, reviewing, etc.</p><p>After a while, you start to see some pitfalls in the LLMs output.</p><p>While many LLMs are doing okay for general-purpose tasks, they tend to fall short when it comes to highly specialized tasks.</p><p>That&#8217;s why it is important to use different types of AI agents, each optimized for a different task.</p><p>For example, let&#8217;s say you have a UI problem. You would ask for help from the Front-End guy, not the Back-End guy, even though the Back-End guy has some knowledge of the front-end too.</p><p>We should apply the same logic and approach to using LLMs as well.</p><blockquote><p><strong>Use the right agent for the right task so we can craft better software</strong>.</p></blockquote><p>In the previous article, we covered the <a href="https://thetshaped.dev/p/the-systematic-ai-code-review-workflow-plan-generate-validate">systematic AI code review workflow: Plan, Generate, Validate</a>.</p><p>Now, let&#8217;s map the right tools to each phase:</p><ul><li><p>Plan &#8594; use Advisors (think through decisions)</p></li><li><p>Generate &#8594; use Generators (write code fast)</p></li><li><p>Validate &#8594; use Reviewers (catch issues automatically)</p></li></ul><p>Each phase needs a different type of AI agent. Let&#8217;s understand what makes each one specialized and what traps to avoid when using.</p><div><hr></div><h2>The Three Types of AI Agents</h2><p>Each AI agent is trained and optimized for specific tasks.</p><p>Using a generator for security review is like using a hammer to tighten a screw.</p><p>It&#8217;s technically possible, but we would use the wrong tool for the job.</p><p>Here is the breakdown:</p><ul><li><p><strong>Advisors</strong> (<a href="https://claude.ai/">Claude</a>, <a href="https://chat.openai.com/">ChatGPT</a>)</p><ul><li><p><em>Purpose</em>: understanding and decision making</p></li><li><p><em>Optimized for</em>: explaining concepts, evaluating trade-offs, designing, researching, refactoring strategy</p></li><li><p><em>Blind to</em>: your specific codebase, real-time feedback, automated integration</p></li></ul></li><li><p><strong>Generators</strong> (<a href="https://cursor.com/">Cursor</a>, <a href="https://copilot.microsoft.com/">Copilot</a>)</p><ul><li><p><em>Purpose</em>: fast code implementation</p></li><li><p><em>Optimized for</em>: speed, autocomplete, pattern matching</p></li><li><p><em>Blind to</em>: security vulnerabilities, architectural implications, edge cases</p></li></ul></li><li><p><strong>Reviewers</strong> (<a href="https://coderabbit.link/dev">CodeRabbit</a> and similar)</p><ul><li><p><em>Purpose</em>: quality assurance and bug detection</p></li><li><p><em>Optimized for</em>: security, bugs, performance, consistency</p></li><li><p><em>Blind to</em>: design decisions, why code exists, future requirements</p></li></ul></li></ul><p>If you&#8217;re wondering when to use each, use these questions to navigate your judgment:</p><ul><li><p>Need to make a design decision? &#8594; use Advisor</p></li><li><p>Need to write code fast? &#8594; use Generator</p></li><li><p>Need to validate code quality? &#8594; use Reviewer</p></li></ul><blockquote><p><strong>Your role is to select the tool, knowing which agent to use and when.<br>You have to validate, reason, and do problem-solving.</strong></p></blockquote><p>Now, let&#8217;s dig deeper into each AI agent.</p><p><em><strong>Note</strong>: Some IDEs, like Cursor, have different modes built in, like Agent, Plan, Debug, Ask, so you could use one IDE, switch the mode, and have a different type of AI agent. However, you still have to know how to use each of those tools.</em></p><div><hr></div><h2>The Advisor: When Decisions Matter</h2><p>Advisors don&#8217;t write your code or review it automatically.</p><p>They help you think through problems, break down complex tasks into an executable plan, understand trade-offs, and make better decisions before you start implementing a specific approach.</p><p>Advisors excel at explaining the &#8220;why&#8221; behind code, not just what it does, but the reasoning and trade-offs that led to that implementation.</p><p>&#9989; With Advisors, you should <strong>prefer</strong>:</p><ul><li><p>Using before making major architectural decisions</p></li><li><p>Understanding existing and/or unfamiliar code</p></li><li><p>Exploring different approaches and strategies and their trade-offs</p></li><li><p>Providing context about your project, current choices, and structure</p></li><li><p>Learning new patterns and concepts</p></li></ul><p>&#9940; With Advisors, you should <strong>avoid</strong>:</p><ul><li><p>Writing code (generators are faster)</p></li><li><p>Using them for bug detection (reviewers are better)</p></li><li><p>Expecting it to know your codebase or internal team&#8217;s dynamics</p></li><li><p>Following advice blindly without understanding</p></li></ul><p>So,</p><blockquote><p><strong>Advisors help you make better decisions.</strong></p></blockquote><p>Use them before you start coding, not after.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Join 29,500+ engineers to receive one practical tip on JS, React, NodeJS, Software Design, and Architecture every 1-2 weeks.</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>The Generator: When Speed Matters</h2><p>The Generators excel at writing code quickly.</p><p>They&#8217;re autocomplete on steroids, trained on millions of code examples to predict what you&#8217;re trying to write.</p><p><strong>&#9989; </strong>With Generators, you should <strong>prefer</strong>:</p><ul><li><p>Using for daily coding, boilerplate, CRUD operations, etc</p></li><li><p>Scaffolding tests</p></li><li><p>Writing type definitions and interfaces</p></li><li><p>Writing code to follow existing patterns and conventions</p></li><li><p>Iterating on suggestions and do not always accept the first try</p></li></ul><p>&#9940; With Generators, you should <strong>avoid</strong>:</p><ul><li><p>Trusting it for security-critical code without review</p></li><li><p>Assuming it validates business logic</p></li><li><p>Assuming it writes proper type definitions of your domain models</p></li><li><p>Using it to make architectural decisions</p></li><li><p>Skipping review because &#8220;AI wrote it&#8221;</p></li></ul><p>So,</p><blockquote><p><strong>Generators are for speed.<br>Always validate the output with a review and your reasoning.</strong></p></blockquote><p>Use them after you have a concrete plan in mind.</p><div><hr></div><h2>The Reviewer: When Quality Matters</h2><p>Reviewers are specialized for finding issues in existing code.</p><p>An example of a Reviewer is <a href="https://coderabbit.link/dev">CodeRabbit</a>.</p><p>They don&#8217;t generate. They analyze, detect patterns and conventions, and flag problems.</p><p><strong>&#9989; </strong>With Reviewers like <a href="https://coderabbit.link/dev">CodeRabbit</a>, you should <strong>prefer</strong>:</p><ul><li><p>Using on every PR before merging</p></li><li><p>Addressing security and bug findings immediately</p></li><li><p>Using suggestions as learning opportunities (you could ask Advisors to help)</p></li><li><p>Configuring rules and guidelines for your specific tech stack and codebase</p></li></ul><p>&#9940; With Reviewers like <a href="https://coderabbit.link/dev">CodeRabbit</a>, you should <strong>avoid</strong>:</p><ul><li><p>Skipping review because the code &#8220;looks fine&#8221;</p></li><li><p>Dismissing warnings or applying suggestions without understanding them</p></li><li><p>Using it to write new code (wrong tool)</p></li><li><p>Expecting it to validate business logic</p></li></ul><p>So,</p><blockquote><p><strong>Reviewers help us catch things which generators miss.</strong></p><p>They act as our QA and Security guy.</p></blockquote><p>Use them while or after you generate code. Then you fix and repeat.</p><div><hr></div><p>Now that we understand each agent&#8217;s specialty.</p><p>Here is how to use them together effectively:</p><ul><li><p>Making a decision? &#8594; Advisor (understand trade-offs first, make a plan)</p></li><li><p>Writing code? &#8594; Generator (fast implementation)</p></li><li><p>Code written? &#8594; Reviewer (catch issues automatically)</p></li><li><p>Issues found? &#8594; Generator (quick fixes) &#8594; Reviewer (validate)</p></li></ul><p>And remember:</p><blockquote><p><strong>&#9888;&#65039; Your role is to select the tool and always validate and understand the output!</strong></p></blockquote><div><hr></div><h2>When Agents Disagree</h2><p>Sometimes, different agents might suggest conflicting approaches.</p><p>Here is how I resolve them:</p><ul><li><p><strong>For architecture</strong>, I weigh the Advisor&#8217;s opinion carefully, but also consider the current context, business needs, and constraints.</p></li><li><p><strong>For implementation details</strong>, I follow the generated code from the Generator because it knows the codebase best and the already established patterns.</p></li><li><p><strong>For security issues</strong>, I trust the Reviewer&#8217;s suggestions (like <a href="https://coderabbit.link/dev">CodeRabbit</a>) because security is non-negotiable.</p></li></ul><p>In the end, the final decision is yours because you know all the specific domain and business context, needs, and constraints.</p><p>AI shouldn&#8217;t be your excuse for making wrong and unjustified decisions.</p><p>You are the Software Engineer who navigates and drives the AI, not the other way around.</p><p><strong>You&#8217;re the final decision maker!</strong></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Join 29,500+ engineers to receive one practical tip on JS, React, NodeJS, Software Design, and Architecture every 1-2 weeks.</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><strong>&#128204; TL;DR</strong></h2><ul><li><p>Using one AI tool for everything means missing what other specialized tools catch.</p></li><li><p>Prefer to use a different AI agent, each optimized for different tasks</p></li><li><p>We have generally three types of AI agents: advisors (Claude/ChatGPT), generators (Cursor/Copilot), and reviewers (<a href="https://coderabbit.link/dev">CodeRabbit</a>).</p></li><li><p>Match the tool to the tasks, advisors for decisions, generators for speed, reviewers for safety.</p></li></ul><p>So try out these three agent types in your daily coding workflow and let me know how you found them.</p><p>I promise this way of working will improve your code.</p><p>Hope this was helpful.</p><p>See you next time! &#128588;</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 29.5K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[The Systematic AI Code Review Workflow: Plan, Generate, Validate]]></title><description><![CDATA[A practical guide to maintain quality at AI speed (6 min)]]></description><link>https://thetshaped.dev/p/the-systematic-ai-code-review-workflow-plan-generate-validate</link><guid isPermaLink="false">https://thetshaped.dev/p/the-systematic-ai-code-review-workflow-plan-generate-validate</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Sat, 27 Dec 2025 12:07:14 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ef00d78f-b0d4-4d54-a72a-b40080ef322a_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 29,300+ engineers to receive one practical tip on JS, React, NodeJS, Software Design, and Architecture every 1-2 weeks.</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><p>Once upon a time, a developer spent an afternoon building a user registration API with AI assistance.</p><p>API endpoints, proper validation, clean error handling&#8212;everything compiled perfectly and worked flawlessly in staging.</p><p>The PR was approved and merged into production.</p><p>Hours later, the security team sent an urgent Slack message.</p><p>The newly introduced endpoint was vulnerable to SQL injection through unvalidated query parameters.</p><p>One line of code. One blind spot.</p><p>One security vulnerability that an automated review would have caught instantly.</p><p>That&#8217;s the current reality of AI and Vibe coding without a systematic workflow:</p><blockquote><p><strong>It&#8217;s not a productivity, it&#8217;s a technical debt at AI speed.</strong></p></blockquote><p>To mitigate this, we need a new system to handle the massive code generation facilitated by AI.</p><p>In today&#8217;s article, I&#8217;ll share a systematic AI code review workflow to adapt to the new AI and Vibe coding era. </p><div><hr></div><h2>Why You Need a Loop</h2><p>Most developers follow this pattern:</p><ol><li><p>Generate code with AI</p></li><li><p>Push to production</p></li><li><p>Hope for the best</p></li></ol><p>The problem with this approach is that AI optimizes for &#8220;working&#8221;, not &#8220;correct&#8221; code.</p><p>It writes code that compiles and runs, but might have security vulnerabilities, performance issues, edge case failures, and inconsistent error handling.</p><p><em>Imagine the following scenario:</em> You ask your LLM to generate an Express API endpoint for user registration. The code works perfectly:</p><pre><code>app.post(&#8217;/api/register&#8217;, async (req, res) =&gt; {
  const { email, password, username } = req.body;
  
  const user = await db.query(
    `INSERT INTO users (email, password, username) VALUES (&#8217;${email}&#8217;, &#8216;${password}&#8217;, &#8216;${username}&#8217;) RETURNING *`
  );
  
  res.json({ success: true, user });
});</code></pre><p>However, there are a few major problems. SQL injection vulnerability. No password hashing. No input validation. No error handling, etc. You get the point.</p><p>The main point is that the code &#8220;works&#8221;, but it&#8217;s a security nightmare.</p><p>This is where the <strong>three-phase loop</strong> comes in:</p><pre><code>Plan &#8594; Generate &#8594; Review &#8594; Ship
         &#8593;            &#8595;
         &#9492;&#9472;&#9472; Fix &#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></pre><p>The key principle is:</p><blockquote><p>Separate generation from validation.</p></blockquote><p>You might use:</p><ul><li><p><strong>Generation AI</strong>, like <a href="https://cursor.com/">Cursor</a>, <a href="https://claude.ai/">Claude</a>, or <a href="https://copilot.microsoft.com/">Copilot</a>, optimizes for speed and functionality.</p></li><li><p><strong>Review AI</strong>, like <a href="https://coderabbit.link/dev">CodeRabbit</a>, optimizes for security, performance, and quality.</p></li><li><p><strong>You</strong> act as an orchestrator of both.</p></li></ul><p>This way, each phase catches different types of issues.</p><p>Let&#8217;s dive in.</p><div><hr></div><h2>Phase 1: Plan Before You Generate</h2><p>Good AI output starts with good input.</p><p>Planning before you generate any code creates better results.</p><p>Why planning matters:</p><ul><li><p>clear specs = better AI output</p></li><li><p>prevents &#8220;works but unmaintainable&#8221; code</p></li><li><p>creates a checklist for validation</p></li><li><p>saves hours of debugging later</p></li></ul><p>You might use <a href="https://cursor.com/docs/agent/planning">Cursor Plan mode</a>, or any other LLM like Claude or ChatGPT, to come up with a detailed action plan.</p><p>I personally try to fill out the following template before moving to the code generation:</p><pre><code>Feature: [Name]
Purpose: [One sentence]
Inputs: [List with types and validation rules]
Outputs: [Success and error cases]
Edge cases: [What could go wrong?]
Security considerations: [What must be protected?]</code></pre><p><em>Feel free to edit it based on your current context, problem, and task.</em></p><p>This approach helps me be more confident that I&#8217;ve outlined all the important requirements and considerations before moving to the next phase.</p><p>If we follow the example from above related to the user registration endpoint for an Express API, we might prompt the following:</p><pre><code><strong>I need</strong> a user registration endpoint for an Express API. <strong>Users provide</strong> email, password, and username. <strong>Help me design</strong> the endpoint <strong>that handles</strong> validation errors, duplicate emails, and weak passwords. <strong>What else should I consider for</strong> security, validation, and error handling?</code></pre><p>Based on the given output, summarize the findings into the above-mentioned template, so you can share it in the prompt in a structured format when starting to generate code.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable Software Engineering and Full-Stack JavaScript-related tips straight into your inbox every two weeks.</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>Phase 2: Generate With Context</h2><p>Once you&#8217;ve gone through the planning and have a structured and summarized plan, you&#8217;re ready to generate.</p><p>Since you already defined a plan, you can create focused and high-quality prompts.</p><p><strong>Generation best practices</strong>:</p><ul><li><p>Generate one endpoint, component, or feature at a time. Don&#8217;t generate the entire service. The smaller and more focused the task, the better the outcome.</p></li><li><p>Use separate prompts/chats per task. Maintain the context window. Keep it as small as possible. This also reduces the costs.</p></li><li><p>Copy relevant sections from your plan directly into the prompt.</p></li><li><p>Iterate 2-3 times rather than expecting perfection on the first try.</p></li><li><p>Specify your exact tech stack, code style, and structure. Provide examples from the codebase if relevant.</p></li></ul><blockquote><p><strong>AI generation is a conversation, not a one-shot command!</strong></p></blockquote><p>During the code generation phase, you want to <strong>manually check</strong>:</p><ul><li><p>Does it follow your tech stack conventions?</p></li><li><p>Are the types and interfaces correct?</p></li><li><p>Does it match your project structure?</p></li><li><p>Are dependencies the ones you actually use?</p></li></ul><p>If something looks off, create a new chat and refine your prompt with more specific guidance.</p><blockquote><p>In the LLM world, if the first prompt is not okay, it&#8217;s hard to change it later.<br>Better create a new chat with a clean context and an improved prompt.</p></blockquote><p>Coming back to the example from above related to the user registration endpoint for an Express API, we might prompt the following:</p><pre><code>Create an Express TypeScript POST endpoint at /api/register for user registration.

Requirements:
- Accept email (string), password (string), username (string) in request body
- Validate email format (RFC 5322)
- Validate password: minimum 8 characters with at least one number
- Validate username: 3-20 alphanumeric characters only
- Hash password with bcrypt (12 rounds) before storing
- Use parameterized database queries to prevent SQL injection
- Handle duplicate email (return 409 with generic message)
- Handle validation errors (return 400 with field-specific errors)
- Handle database errors gracefully
- Return 201 with user object (exclude password) on success

Use Zod for input validation and proper TypeScript types throughout.</code></pre><p>Even though we&#8217;ve outlined a detailed plan and have a solid code, we might still miss important stuff.</p><p>For example, &#8220;Are there any missed edge cases?&#8221;, &#8220;Performance implications?&#8221;, &#8220;Is the validation comprehensive enough?&#8221;, etc.</p><p>This is exactly why we need the review phase.</p><p>We want to get a higher confidence in what we ship and double-check that we haven&#8217;t missed important considerations.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable Software Design and Software Architecture tips straight into your inbox every two weeks.</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>Phase 3: Review and Validate</h2><p>We have a working code. Now, it&#8217;s time to validate it with a second AI perspective specialized for review.</p><p>Why bother reviewing AI-generated code?</p><ul><li><p>AI generators have blind spots. They optimize for &#8220;working&#8221;, not &#8220;correct&#8221; code.</p></li><li><p>Different AI models catch different issues and blind spots.</p></li><li><p>Automated reviews find problems in seconds.</p></li><li><p>Ensures consistency across your codebase.</p></li></ul><p>An example of such an AI code review tool is <a href="https://coderabbit.link/dev">CodeRabbit</a>.</p><p>What <a href="https://coderabbit.link/dev">CodeRabbit</a> catches:</p><ul><li><p><strong>Security</strong>: SQL injections, XSS vulnerabilities, exposed secrets, etc.</p></li><li><p><strong>Bugs</strong>: race conditions, incorrect error handling, etc.</p></li><li><p><strong>Performance</strong>: missing db indexes, N+1 queries, etc.</p></li><li><p><strong>Best practices</strong>: inconsistent error handling, missing type safety, etc.</p></li></ul><p>Put simply, <a href="https://coderabbit.link/dev">CodeRabbit</a> complements human reviewers, adding a lot of context based on your repo and general engineering practices.</p><div><hr></div><h2><strong>&#128204; TL;DR</strong></h2><p>This systematic AI code review workflow isn&#8217;t optional; it&#8217;s how you maintain quality at AI speed:</p><ul><li><p><strong>Plan</strong> before you generate (upfront thinking saves hours).</p></li><li><p><strong>Generate</strong> with context (good prompts = good code).</p></li><li><p><strong>Review</strong> with specialized AI (e.g., <a href="https://coderabbit.link/dev">CodeRabbit</a> catches what generators miss).</p></li></ul><p>Hope this was helpful.</p><p>See you next time! &#128588;</p><p>P.S. If you&#8217;re into Web Development, I recommend you subscribe to <a href="https://markodenic.tech/">Marko Denic</a>&#8217;s newsletter, which is full of many tips and tricks.</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 29.3K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[2-Tier to 3-Tier Architecture: Migration Journey With Modular Monolith and GraphQL]]></title><description><![CDATA[A real-world case study of migrating a two-tier architecture to a three-tier architecture. (5 min)]]></description><link>https://thetshaped.dev/p/two-tier-to-three-tier-architecture-migration-case-stuty-modular-monolith-graphql-api-software-architecture</link><guid isPermaLink="false">https://thetshaped.dev/p/two-tier-to-three-tier-architecture-migration-case-stuty-modular-monolith-graphql-api-software-architecture</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 18 Nov 2025 11:09:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/06cdc73c-e487-4e0d-b706-e24a2ebf3136_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 28,000+ engineers to receive one practical tip on JS, React, NodeJS, Software Design, and Architecture every week.</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><p>A while ago, I worked for a client who had a diverse portfolio of digital products.</p><p>They&#8217;ve struggled to develop new features, reuse business logic and functionality across products, and also scale the engineering team.</p><p>By digging deeper into the case, I&#8217;ve found they have:</p><ul><li><p>bad architecture, which doesn&#8217;t support their growth</p></li><li><p>years of accumulated technical debt</p></li></ul><p>The root cause turned out to be a 2-Tier Architecture that had outlived its purpose.</p><p>In today&#8217;s article, I&#8217;ll share how I tackled this challenge by migrating their system from a Two-Tier Architecture to a Three-Tier Architecture, introducing a scalable, robust GraphQL API.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5nt7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 424w, https://substackcdn.com/image/fetch/$s_!5nt7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 848w, https://substackcdn.com/image/fetch/$s_!5nt7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 1272w, https://substackcdn.com/image/fetch/$s_!5nt7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5nt7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp" width="469" height="305.5828125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:834,&quot;width&quot;:1280,&quot;resizeWidth&quot;:469,&quot;bytes&quot;:11044,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:&quot;http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/156653767?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5nt7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 424w, https://substackcdn.com/image/fetch/$s_!5nt7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 848w, https://substackcdn.com/image/fetch/$s_!5nt7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 1272w, https://substackcdn.com/image/fetch/$s_!5nt7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96ab1d82-5d53-4e65-a347-fd446e64aed0_1280x834.webp 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><a href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar">IcePanel</a> is a collaborative diagramming and modelling tool for designing software architecture. Create interactive, layered views for different stakeholders from a single source of truth.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar&quot;,&quot;text&quot;:&quot;Try for free&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar"><span>Try for free</span></a></p><div><hr></div><p>Before we dive into the actual migration journey, let&#8217;s ensure we understand what a 2-Tier and a 3-Tier architecture are.</p><h2>What is Two-Tier Architecture?</h2><p>2-Tier Architecture is a simple setup in which your application talks directly to a database.</p><p>You have a presentation layer (the front-end) and a data layer (the database).</p><p>That&#8217;s it. No middle layer.</p><p>Think of it like a simple website or app that sends requests directly to the database, retrieves the data, and displays it to users.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w_Ph!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 424w, https://substackcdn.com/image/fetch/$s_!w_Ph!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 848w, https://substackcdn.com/image/fetch/$s_!w_Ph!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 1272w, https://substackcdn.com/image/fetch/$s_!w_Ph!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w_Ph!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png" width="507" height="657.0803571428571" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1887,&quot;width&quot;:1456,&quot;resizeWidth&quot;:507,&quot;bytes&quot;:145028,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/156653767?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.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_!w_Ph!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 424w, https://substackcdn.com/image/fetch/$s_!w_Ph!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 848w, https://substackcdn.com/image/fetch/$s_!w_Ph!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.png 1272w, https://substackcdn.com/image/fetch/$s_!w_Ph!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717c6e12-81fb-4ce0-8a95-07b50a50d9ad_1600x2074.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><figcaption class="image-caption">Diagram created in <a href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar">IcePanel</a>.</figcaption></figure></div><div><hr></div><h2>What is Three-Tier Architecture?</h2><p>3-Tier Architecture adds an essential middle layer between your front-end and database. Now you have:</p><ol><li><p><strong>Presentation Layer</strong> - the front-end (what users see).</p></li><li><p><strong>Business Logic Layer</strong> - the API (where the magic happens).</p></li><li><p><strong>Data Layer</strong> - the database (where data lives).</p></li></ol><p>The middle layer handles all the business logic, security, and data processing.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AXbD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 424w, https://substackcdn.com/image/fetch/$s_!AXbD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 848w, https://substackcdn.com/image/fetch/$s_!AXbD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 1272w, https://substackcdn.com/image/fetch/$s_!AXbD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AXbD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png" width="553" height="716.6971153846154" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1887,&quot;width&quot;:1456,&quot;resizeWidth&quot;:553,&quot;bytes&quot;:159125,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/156653767?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.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_!AXbD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 424w, https://substackcdn.com/image/fetch/$s_!AXbD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 848w, https://substackcdn.com/image/fetch/$s_!AXbD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.png 1272w, https://substackcdn.com/image/fetch/$s_!AXbD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c97fd46-8bdd-40c1-9cee-41d6a72ae768_1600x2074.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><figcaption class="image-caption">Diagram created in <a href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar">IcePanel</a>. <a href="https://s.icepanel.io/VshUdhGpfKEaFf/w2Ys">Link</a> to the diagram.</figcaption></figure></div><p>The main difference between a 2-Tier and a 3-Tier architecture is the <strong>separation of concerns</strong>.</p><p>In a Two-Tier architecture, your front-end must know too much about your data, whereas in a Three-Tier architecture, the business logic layer acts as a smart middleman.</p><p>This smart middleman protects your data and enables the whole system to be more flexible.</p><div><hr></div><h2>The Starting Architecture (Two-Tier)</h2><p>Now, let me show you what the client&#8217;s system looked like before the migration.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5GPa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5GPa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 424w, https://substackcdn.com/image/fetch/$s_!5GPa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 848w, https://substackcdn.com/image/fetch/$s_!5GPa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 1272w, https://substackcdn.com/image/fetch/$s_!5GPa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5GPa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png" width="1456" height="1034" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1034,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:350343,&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://thetshaped.dev/i/156653767?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.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_!5GPa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 424w, https://substackcdn.com/image/fetch/$s_!5GPa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 848w, https://substackcdn.com/image/fetch/$s_!5GPa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.png 1272w, https://substackcdn.com/image/fetch/$s_!5GPa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa84adb46-8e32-401a-8986-e44a37fff31a_3296x2341.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><figcaption class="image-caption">Diagram created in <a href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar">IcePanel</a>.</figcaption></figure></div><p>They had three main services, all sharing one MySQL database:</p><ul><li><p><strong>Portal</strong> - The customer-facing web portal. The front-end was React, but the back-end was built with CakePHP 2 (an outdated PHP framework).</p></li><li><p><strong>Admin</strong> - The internal management web portal of the company. Everyone in the company used it to run the business, from operations to finance. Also built with CakePHP 2.</p></li><li><p><strong>API</strong> - A small REST API with just three methods for customers. Again, Cake PHP 2.</p></li></ul><p>All three services are connected directly to the same MySQL database.</p><p>The database was the integration point for everything.</p><p>This setup created several serious problems.</p><h3>The Top Technical Challenges</h3><ul><li><p><strong>Duplicated logic</strong> - The same business logic and rules were duplicated in multiple services.</p></li><li><p><strong>Database as an integration point</strong>&nbsp;- Having multiple services write to the same database is risky. There is no single source of truth for business logic and data validation. Also, it is very hard to update or migrate the database when having multiple clients.</p></li><li><p><strong>Technical debt</strong> - CakePHP 2 reached end of life. There was a need to modernize the tech stack by using well-adapted technologies.</p></li><li><p><strong>Hard to scale the engineering team</strong> - This was hard to find developers to work on front-end and back-end with the present technologies. There was a need to enable full-stack developers.</p></li><li><p><strong>Slow feature development</strong> - With the challenges mentioned above, feature development was slow, hindering the business's growth.</p></li></ul><div><hr></div><p>To address these challenges, we introduced a new middle layer&#8212;a GraphQL API.</p><h2>The Final Architecture (Three-Tier)</h2><p>The GraphQL API became the heart of the system.</p><p>It sits between all front-ends and the database.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qFgK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qFgK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 424w, https://substackcdn.com/image/fetch/$s_!qFgK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 848w, https://substackcdn.com/image/fetch/$s_!qFgK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 1272w, https://substackcdn.com/image/fetch/$s_!qFgK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qFgK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png" width="1456" height="948" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:948,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:377186,&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://thetshaped.dev/i/156653767?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.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_!qFgK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 424w, https://substackcdn.com/image/fetch/$s_!qFgK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 848w, https://substackcdn.com/image/fetch/$s_!qFgK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.png 1272w, https://substackcdn.com/image/fetch/$s_!qFgK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6aaf9b16-73ce-4bed-9e95-0ceb36b7b970_3632x2365.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><figcaption class="image-caption">Diagram created in <a href="http://icepanel.io/?utm_source=substack&amp;utm_campaign=petar">IcePanel</a>. <a href="https://s.icepanel.io/VshUdhGpfKEaFf/TjoF">Link</a> to the diagram.</figcaption></figure></div><h3>The Main Architectural Improvements</h3><p>The new architecture solved our major pain points:</p><ul><li><p><strong>Centralized business logic</strong> - All business-related logic lives in one place now. The GraphQL API is the single source of truth for all features.</p></li><li><p><strong>Single database owner</strong> - Only the GraphQL API can access the database. This makes the system safer and easier to refactor.</p></li><li><p><strong>Modern tech stack</strong> - We built the API using Node.js, a technology already used by the company. Apart from that, <a href="https://thetshaped.dev/p/graphql-intro-101-part-1">GraphQL</a> provides flexible, efficient data fetching to accommodate the needs of different API clients.</p></li><li><p><strong>Full-stack friendly</strong> - Having the same core technology, JavaScript, on the front-end and back-end, enabled the company to hire Full-Stack JavaScript developers.</p></li><li><p><strong>Ready for microservices</strong>&nbsp;- To ensure the system's future flexibility and the company&#8217;s growth, the API was designed as a <a href="https://thetshaped.dev/p/what-is-a-modular-monolith-benefits-and-microservices-challenges">Modular Monolith</a>, so that, when needed, internal modules could be extracted into separate services.</p></li></ul><h2>The Migration Approach</h2><p>We didn&#8217;t rebuild everything overnight.</p><p>This was too risky from both a business and an engineering perspective.</p><p>The business must continue operating while the groundwork is being done under the hood.</p><p>That&#8217;s why we took an iterative approach:</p><ul><li><p><strong>Phase 1: Build the GraphQL API</strong> - We created the new API layer, starting with the most critical business logic, shared across multiple services.</p></li><li><p><strong>Phase 2: Migrate Portal</strong> - The Portal front-end started using the GraphQL API. We moved features one by one and tested thoroughly.</p></li><li><p><strong>Phase 3: Update Admin</strong> - We upgraded Admin to a modern version of CakePHP. Then we gradually moved its logic to the GraphQL API, starting with shared functionality.</p></li><li><p><strong>Phase 4: Rewrite REST API</strong> - The customer-facing REST API had only three methods, so we rewrote it in Node.js to align with the new stack.</p></li><li><p><strong>Phase 5: Migrate Admin to React</strong>&nbsp;- We started migrating the Admin to React, instead of CakePHP, prioritizing newly incoming feature requests.</p></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JS, React, NodeJS, Software Design and Architecture tips straight into your inbox every week.</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><strong>&#128204; TL;DR</strong></h2><ul><li><p>2-Tier Architecture is when multiple clients or services directly communicate with the Database.</p></li><li><p>3-Tier Architecture is when multiple clients or services communicate with a middle layer, usually an API, which then communicates with the actual DB.</p></li><li><p>Having three clients communicating with a DB means duplicated business logic everywhere.</p></li><li><p>Having a middle layer, in this case a GraphQL API, means a single user communicates with the DB, removing duplicate business logic.</p></li><li><p>Centralizing business logic in the GraphQL API eliminated duplicate code, made onboarding new teammates easier, enabled quicker feature delivery, and created a system ready to scale into microservices when needed.</p></li></ul><p>Hope this was helpful.</p><p>See you next time! &#128588;</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 28.7K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[Conscious Debugging: 10 Effective Strategies That Actually Work 🐛]]></title><description><![CDATA[Learn how to find and fix bugs like a pro with these ten effective debugging strategies. (6 min)]]></description><link>https://thetshaped.dev/p/conscious-debugging-10-effective-debugging-strategies-debug-like-pro</link><guid isPermaLink="false">https://thetshaped.dev/p/conscious-debugging-10-effective-debugging-strategies-debug-like-pro</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Sat, 08 Nov 2025 05:19:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/52a28f14-9491-42d5-9b47-0fc902818396_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We&#8217;ve all been there - staring at a bug that makes absolutely no sense.</p><p>You&#8217;ve tried everything you can think of, but the issue persists&#8230;</p><p>Debugging doesn&#8217;t have to be this painful.</p><p>It&#8217;s a skill you can develop with the right strategies and tools.</p><p>It&#8217;s something you can learn and get better at.</p><blockquote><p><strong>Mastering debugging can save you time, energy, frustrations, and money as well as improve your code quality.</strong></p></blockquote><p>In today&#8217;s article, I&#8217;ll share ten practical debugging techniques I use daily that have saved me countless hours.</p><p>I&#8217;ll also show you some modern tools that could make these strategies even more effective.</p><div><hr></div><p>Being effective while debugging is crucial.</p><p>It&#8217;s really important to get it right so you find the root cause of the issue, fix it asap, and then make your customers happy.</p><p>Over the years, as a Software Engineer, I&#8217;ve found that good debugging is not only about the processes and systems you employ, but also about your mindset and tooling.</p><p>I&#8217;ve played around with various tools both at my daily job and side projects.</p><p>Recently, I tried out <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a>, a new session replay platform that captures both the front-end and back-end traces.</p><p>I believe we can make debugging much simpler with the help of <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a>, effective, and easier to do.</p><div><hr></div><h2>Part 1: Set Yourself Up For Success</h2><h3>1. Reproduce the Error Consistently</h3><p>You can&#8217;t fix what you can&#8217;t see.</p><p>The foundation of effective debugging is consistently reproducing the bug.</p><p>Start by writing step-by-step instructions that make the bug appear every time.</p><p>For example, map out how a user request flows through the whole system, so you build a clear mental model.</p><p>This is especially useful in the context of microservice architecture, where a single user request might hit several services.</p><p>Finding the bug in the ground schema is hard if you don&#8217;t have a good understanding of the flow.</p><p>Nowadays, there are tools that record session replays, so you can leverage them to see the flow from the front-end to the back-end instead of doing it manually.</p><p>An example of such a tool is <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a>, which captures full-stack session recordings.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://trymultiplayer.link/petar-ivanov" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PcjW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 424w, https://substackcdn.com/image/fetch/$s_!PcjW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 848w, https://substackcdn.com/image/fetch/$s_!PcjW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 1272w, https://substackcdn.com/image/fetch/$s_!PcjW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PcjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png" width="1024" height="604" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:604,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:266625,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://trymultiplayer.link/petar-ivanov&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/177173524?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.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_!PcjW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 424w, https://substackcdn.com/image/fetch/$s_!PcjW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 848w, https://substackcdn.com/image/fetch/$s_!PcjW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.png 1272w, https://substackcdn.com/image/fetch/$s_!PcjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba4b94f4-38af-441d-9b76-4decf7fa2867_1024x604.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>2. Reproduce the Error Quickly</h3><p>Once you know how to reproduce a bug, make it fast.</p><p>Configure your development environment to jump straight to the problematic area.</p><p>This helps to quickly test various hypotheses and solutions.</p><p>Every second you save between reproducing the bug and testing a fix compounds over the course of dozens of debugging iterations.</p><h3>3. Capture the Full Context</h3><p>Debugging an issue in a complex system &#8212;from front-end to back-end &#8212;is hard.</p><p>It requires acquiring as much information and context as needed.</p><p>Imagine a user reporting a problem&#8212;&#8220;the page crashed&#8221;&#8212;but you miss information like why they clicked, what data they had loaded, or the system's state.</p><p>So, before digging into the problem, try to collect as much context as possible&#8212;ask your product manager, write an email to a client, check recordings, logs, etc.</p><p>You might also consider using a tool like <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a>, which silently captures user sessions so you can collect all the context related to a single issue.</p><div><hr></div><h2>Part 2: Active Debugging Techniques</h2><h3>4. Isolate the Problem</h3><p>Large codebases make finding bugs like finding a needle in a haystack.</p><p>You need to narrow down the scope quickly.</p><p>Use a <strong>binary search approach</strong>: <strong>divide your code into working and non-working parts</strong>.</p><p>Comment out half of the suspicious code. Does the bug occur? If yes, the problem is in the other half. If no, it&#8217;s in the code you commented out.</p><p>You might also use breakpoints like a binary search to quickly jump to different points in your code.</p><p>Repeat this process until you&#8217;ve nailed the problematic area.</p><p>The main goal is to minimize the scope from &#8220;somewhere in this 1000-line file&#8221; to &#8220;somewhere in these 20 lines&#8221;.</p><h3>5. Use Your Debugger</h3><p>Debuggers are invaluable tools that provide real-time insights into your program&#8217;s execution.</p><p>You can set breakpoints, inspect variables, step through the code line by line, and examine the call stack.</p><p>The main benefit is that you can easily see the exact flow of your program and spot anomalies as they happen.</p><p>If you&#8217;re using tools for recording session replays, you could bring those recordings directly into your IDE.</p><p>I&#8217;ve personally tried <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a> and it worked like a charm.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://trymultiplayer.link/petar-ivanov" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2EcT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 424w, https://substackcdn.com/image/fetch/$s_!2EcT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 848w, https://substackcdn.com/image/fetch/$s_!2EcT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 1272w, https://substackcdn.com/image/fetch/$s_!2EcT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2EcT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png" width="1024" height="602" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:602,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:217639,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://trymultiplayer.link/petar-ivanov&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/177173524?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.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_!2EcT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 424w, https://substackcdn.com/image/fetch/$s_!2EcT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 848w, https://substackcdn.com/image/fetch/$s_!2EcT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.png 1272w, https://substackcdn.com/image/fetch/$s_!2EcT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7f3ac9-1799-4eab-9426-335b90e2c697_1024x602.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>6. Rubber Duck It</h3><p>Rubber duck debugging is simple but extremely powerful.</p><p>The main idea is that you explain your code line by line to an object (&#129414;), a colleague, or even yourself.</p><p>You describe what you expect to happen at each step.</p><p>The act of explaining forces you to slow down and verify your assumptions.</p><p>There is a big difference in how we think about the code when we read and when we speak loudly about it.</p><p>I&#8217;ve caught the bug many times in the middle of the explanation.</p><h3>7. Form And Test Hypotheses</h3><p>To achieve good results while debugging, you must adopt a more scientific, methodological approach and avoid any random changes.</p><p>Do the following</p><ul><li><p><strong>Form a hypothesis</strong> about the root cause (ex, &#8220;I think the API is returning null when the user has no preferences&#8230;&#8221;).</p></li><li><p><strong>Experiment</strong> to verify it (add logging, set breakpoints, etc).</p></li><li><p><strong>Observe</strong> the result (confirm or reject the hypothesis).</p></li><li><p><strong>Fix</strong> the code based on what you learned.</p></li><li><p><strong>Verify</strong> the fix actually solves the problem.</p></li><li><p><strong>Repeat</strong> the cycle again with a new hypothesis if needed.</p></li></ul><p>This systematic approach prevents you from going in circles and helps you build an understanding of your codebase.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JS, React, NodeJS, Software Design and Architecture tips straight into your inbox every week.</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>Part 3: When You&#8217;re Stuck</h2><h3>8. Document Your Progress</h3><p>When a bug is particularly hard, write down what you&#8217;ve tried.</p><p>Keep a running list of your experiments, hypothesis, and their results.</p><p>This prevents you from doing the same thing twice and expecting different results.</p><p>Documentation also makes it easier for others to help you.</p><p>You can easily ping a colleague, share your progress, and learnings so far.</p><p>You might also consider a tool like <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a> to annotate session replays with sketches and comments.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://trymultiplayer.link/petar-trial" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x9Uz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 424w, https://substackcdn.com/image/fetch/$s_!x9Uz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 848w, https://substackcdn.com/image/fetch/$s_!x9Uz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 1272w, https://substackcdn.com/image/fetch/$s_!x9Uz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x9Uz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png" width="1024" height="602" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:602,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:150511,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://trymultiplayer.link/petar-trial&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/177173524?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.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_!x9Uz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 424w, https://substackcdn.com/image/fetch/$s_!x9Uz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 848w, https://substackcdn.com/image/fetch/$s_!x9Uz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.png 1272w, https://substackcdn.com/image/fetch/$s_!x9Uz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34f042ff-60b3-4c79-91c9-48c39d453fa3_1024x602.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>9. Take Strategic Breaks</h3><p>This might sound counterintuitive, but stepping away from your laptop is sometimes the fastest way to solve a bug.</p><p>Taking a 15-minute walk allows your mind to rest and your subconscious to process the problem.</p><p>I can&#8217;t count how many times the solution to a difficult bug popped into my head while taking a walk, being at the toilet, or just making a drink.</p><p>There&#8217;s something about disengaging from the problem that allows your brain to make new connections.</p><h3>10. Leverage AI Smartly</h3><p>AI coding tools can be powerful debugging partners, especially if you give them the right information.</p><p>The right context is the key.</p><p>Try providing as much information about the bug as possible to your AI IDE and see how it could reason about it.</p><p>Of course, it&#8217;s not always correct, but you can quickly test and verify certain hypotheses.</p><p>Then, you could focus on the ones your AI coding tool hasn&#8217;t thought about.</p><p>It&#8217;s also helpful if you could share screenshots or session recordings to provide context.</p><p>I&#8217;ve personally tried <a href="https://trymultiplayer.link/petar-ivanov">Multiplayer&#8217;s</a> integration.</p><p>I&#8217;ve used it to feed my AI assistant with a full-stack session recording, so it can see the full context of a problem.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://trymultiplayer.link/petar-ivanov" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SBQS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 424w, https://substackcdn.com/image/fetch/$s_!SBQS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 848w, https://substackcdn.com/image/fetch/$s_!SBQS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 1272w, https://substackcdn.com/image/fetch/$s_!SBQS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SBQS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png" width="1023" height="604" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:604,&quot;width&quot;:1023,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:246176,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://trymultiplayer.link/petar-ivanov&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/177173524?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.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_!SBQS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 424w, https://substackcdn.com/image/fetch/$s_!SBQS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 848w, https://substackcdn.com/image/fetch/$s_!SBQS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.png 1272w, https://substackcdn.com/image/fetch/$s_!SBQS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03ff1cd-fc87-4271-b1c2-79789f8187ae_1023x604.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>After that, I wrote specific prompts and dug deeper into the problem.</p><blockquote><p><strong>AI is not a magic solution, but it&#8217;s a valuable debugging partner when given complete information.</strong></p></blockquote><div><hr></div><p><a href="https://trymultiplayer.link/petar-ivanov">Multiplayer</a> provides Full Stack Session Recordings.</p><p>Here&#8217;s how it helps with debugging and fixing bugs:</p><ul><li><p>Capture full-stack session recordings.</p></li><li><p>Annotate your replays with sketches and comments.</p></li><li><p>Bring full-stack session recordings directly into your IDE.</p></li><li><p>Give your AI coding tools all the context they need.</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://trymultiplayer.link/petar-trial&quot;,&quot;text&quot;:&quot;Access 1-month Free Trial&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://trymultiplayer.link/petar-trial"><span>Access 1-month Free Trial</span></a></p><div><hr></div><h2><strong>&#128204; TL;DR</strong></h2><ul><li><p>Reproduce the error consistently.</p></li><li><p>Set up your environment to quickly reproduce the bug.</p></li><li><p>Capture the full context and information.</p></li><li><p>Isolate the problem.</p></li><li><p>Use your debugger.</p></li><li><p>Rubber duck the problem.</p></li><li><p>Form and test hypotheses.</p></li><li><p>Document your progress.</p></li><li><p>Take strategic breaks.</p></li><li><p>Leverage AI smartly.</p></li></ul><p>Hope this was helpful.</p><p>See you next time!</p><p><strong>Today&#8217;s action step:</strong> Take a look at your debugging process and see how you can apply at least one of the mentioned techniques.</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 28.5K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[Functional Error Handling in Node.js With The Result Pattern]]></title><description><![CDATA[Learn how to improve your error handling in Node.js by using the Result Pattern. (5 Min)]]></description><link>https://thetshaped.dev/p/functional-error-handling-in-nodejs-with-the-result-pattern</link><guid isPermaLink="false">https://thetshaped.dev/p/functional-error-handling-in-nodejs-with-the-result-pattern</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 21 Oct 2025 10:19:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/cd22faee-c7fc-4590-9183-5163d2183c21_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Error handling is a crucial aspect for building robust applications.</p><p>In Node.js, error handling relies on try-catch blocks and exceptions.</p><p>While this is a common way in Node.js apps, it creates an unpredictable control flow and hidden failure points.</p><p>A few years ago, I discovered the Result Pattern approach for handling errors, and it completely changed the way I look at error handling in Node.js applications.</p><p>The Result Pattern approach <strong>makes errors explicit</strong>, type-safe, and part of your function signatures.</p><p>In today&#8217;s article, I&#8217;ll dig deeper into the error handling and how to use the Result Pattern to better manage it.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 28,000+ engineers to receive one practical tip on JS, React, NodeJS, Software Design and Architecture every week.</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>Problems With Using Exceptions For Flow Control</h2><p>Most Node.js applications rely on exceptions for error handling.</p><p>You throw errors when something goes wrong, and catch them somewhere up the call stack.</p><p>This favors the so-called <strong>fail-fast principle</strong> because you terminate the method execution immediately once you throw an exception.</p><p>With this approach, you make the caller responsible for handling the exception.</p><p>The problem is that the client of the method must know which exceptions to handle, which is not obvious from the method&#8217;s signature.</p><p>This makes exceptions invisible and creates an opportunity for bugs related to improper error handling of these exceptions.</p><p>Code becomes unpredictable since you&#8217;re not sure if the method throws an exception or not.</p><p>Here is a simplified example of creating an order:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fKwc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fKwc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 424w, https://substackcdn.com/image/fetch/$s_!fKwc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 848w, https://substackcdn.com/image/fetch/$s_!fKwc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 1272w, https://substackcdn.com/image/fetch/$s_!fKwc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fKwc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png" width="688" height="431.8901098901099" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:914,&quot;width&quot;:1456,&quot;resizeWidth&quot;:688,&quot;bytes&quot;:362417,&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://thetshaped.dev/i/176553465?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.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_!fKwc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 424w, https://substackcdn.com/image/fetch/$s_!fKwc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 848w, https://substackcdn.com/image/fetch/$s_!fKwc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.png 1272w, https://substackcdn.com/image/fetch/$s_!fKwc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5d44fc-770e-4873-9df2-d3eed7775c0a_2963x1859.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><div><hr></div><h2>Use Exceptions For Exceptional Situations</h2><blockquote><p><strong>A good rule of thumb is to use exceptions for unexpected errors and exceptional situations.</strong></p></blockquote><p>You basically have two types of errors:</p><ul><li><p>Errors you know how to handle</p></li><li><p>Errors you don&#8217;t know how to handle</p></li></ul><p>You can use exceptions for the errors you don&#8217;t know how to handle. And you should catch and handle them at the lowest level possible.</p><p>For the errors you know how to handle, you could use the <strong>Result Pattern</strong> and handle the errors in a more functional way.</p><blockquote><p>Make these types of errors explicit since you already know about them.</p></blockquote><p>This way is more explicit and clearly shows that the method can fail.</p><p>The drawback is that the caller of the method has to check whether the operation succeeded or failed.</p><div><hr></div><h2>Using The Result Pattern For Better Error-Handling</h2><p>The Result Pattern makes errors explicit and type-safe.</p><p>Instead of throwing exceptions, methods return a Result object that contains the success data or error information.</p><p>You can think of the Result as a container that holds one of two things:</p><ul><li><p><strong>Success</strong>: Your data is inside.</p></li><li><p><strong>Error </strong>(or Failure): Information about what went wrong. </p></li></ul><p>The key change here is that errors become values, not exceptions.</p><p>You can handle them like any other data in your program.</p><p>Here is an example of what the Result object might look 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_!xNuS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xNuS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 424w, https://substackcdn.com/image/fetch/$s_!xNuS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 848w, https://substackcdn.com/image/fetch/$s_!xNuS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 1272w, https://substackcdn.com/image/fetch/$s_!xNuS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xNuS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png" width="598" height="839.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2044,&quot;width&quot;:1456,&quot;resizeWidth&quot;:598,&quot;bytes&quot;:735509,&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://thetshaped.dev/i/176553465?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.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_!xNuS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 424w, https://substackcdn.com/image/fetch/$s_!xNuS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 848w, https://substackcdn.com/image/fetch/$s_!xNuS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.png 1272w, https://substackcdn.com/image/fetch/$s_!xNuS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b99bc-693c-4835-9da5-13b3b8fd0a8f_2820x3958.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><div><hr></div><h2>Applying the Result Pattern</h2><p>Now that we have the <strong>IResult</strong> interface and utility methods, we could refactor the above-mentioned example by switching from using exceptions to the Result Pattern.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MO8C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MO8C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 424w, https://substackcdn.com/image/fetch/$s_!MO8C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 848w, https://substackcdn.com/image/fetch/$s_!MO8C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 1272w, https://substackcdn.com/image/fetch/$s_!MO8C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MO8C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png" width="432" height="748.2857142857143" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2522,&quot;width&quot;:1456,&quot;resizeWidth&quot;:432,&quot;bytes&quot;:596313,&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://thetshaped.dev/i/176553465?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.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_!MO8C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 424w, https://substackcdn.com/image/fetch/$s_!MO8C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 848w, https://substackcdn.com/image/fetch/$s_!MO8C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.png 1272w, https://substackcdn.com/image/fetch/$s_!MO8C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07a6b51c-61bf-4f96-a377-f2c4b16bf2d6_1995x3455.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>You can notice a few things as improvements:</p><ul><li><p>No more throwing exceptions.</p></li><li><p>The return type of the method is explicit - using the <strong>IResult</strong> return type.</p></li><li><p>It is clear what errors the method can return.</p></li></ul><p>Another advantage of using the Result Pattern is that it simplifies the testing. It&#8217;s much easier to mock the Result object than to throw and handle exceptions.</p><p>As we said earlier, one drawback of the Result Pattern is its verbosity, as it might introduce more code compared to exceptions.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JS, React, NodeJS, Software Design and Architecture tips straight into your inbox every week.</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><strong>&#128204; TL;DR</strong></h2><ul><li><p>Exceptions are for exceptional situations.</p></li><li><p>Use exceptions for errors you don&#8217;t know how to handle.</p></li><li><p>Use the Result Pattern for errors you know how to handle, making the error handling more explicit and obvious.</p></li><li><p>The Result Pattern allows you to handle errors more elegantly in a functional way, express the intent that the method could fail, and encapsulate the error inside.</p></li></ul><p>So try out the Result Pattern and let me know how you found it.</p><p>I promise it will improve your code.</p><p>Hope this was helpful.</p><p>See you next time!</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 28K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[Own Your Onboarding: The First 90 Days That Define Your Career 🚀]]></title><description><![CDATA[A practical guide to shipping fast and making an impact from day one. (6 Min)]]></description><link>https://thetshaped.dev/p/own-your-onboarding-the-first-30-60-90-plan-new-company-hiring</link><guid isPermaLink="false">https://thetshaped.dev/p/own-your-onboarding-the-first-30-60-90-plan-new-company-hiring</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 07 Oct 2025 10:19:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a717e639-5861-472e-b3ca-d5ffbd05b6b5_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Starting a new job is challenging.</p><p>You&#8217;re changing your current environment, including your teammates, office, and so on.</p><p>You&#8217;re also not sure how it would impact your career.</p><p>So yes, it&#8217;s a bit nerve-racking.</p><p>Till now, I&#8217;ve changed more than four tech companies, ranging from startups to big tech unicorns.</p><p>I&#8217;ve seen different onboarding plans and ways to kick off your &#8220;first impression&#8221; in your new workplace.</p><p>One of the biggest lessons I&#8217;ve learned for myself is:</p><blockquote><p><strong>Don&#8217;t rely on your company&#8217;s onboarding plan. Create one for yourself!</strong></p></blockquote><p>Regardless of the company's size and seasonality, there are many flaws.</p><p>It&#8217;s hard to create the &#8220;complete&#8221; plan for every new joiner.</p><p>That&#8217;s why it&#8217;s crucial to <strong>take ownership of your onboarding plan</strong>.</p><p>The effort you put in now will pay dividends for months.</p><p>A strong start makes you appear to be someone who cares.</p><p>This sense of ownership shows professionalism.</p><p>In today&#8217;s article, I&#8217;ll share ten lessons I&#8217;ve learned in my career on how to successfully onboard in your new company.</p><p>I also shared and applied these lessons with all the people I managed to onboard as an Onboarding Buddy.</p><p>I saw the work, so that&#8217;s why I&#8217;m sharing these lessons with you.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 28,000+ engineers to receive one practical tip on JS, React, NodeJS, Software Design and Architecture every week.</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>Before Day 1: Set Yourself Up For Success</h2><p>If you have a long notice period, reach out to your future manager or team before you start.</p><blockquote><p><strong>Ask what you can do to prepare before your first working day.</strong></p></blockquote><p>When I did that at my last company, they sent me a Udemy course on microservices architecture - a core part of their tech stack.</p><p>On Day 1, I showed up already speaking &#8220;their language&#8221;.</p><p>This shows two things: <strong>you actually prepare</strong> and <strong>you signal you are proactive</strong>.</p><p>Also, start a <strong>work log or brag document</strong> from Day 1.</p><p>Write down what you&#8217;re working on, problems you solved, your wins, and impact.</p><p>This becomes invaluable for 1:1s, performance reviews, and promotion discussions.</p><p>You can read more about it <a href="https://thetshaped.dev/p/how-keeping-a-work-log-aka-brag-list-helps-you-get-promoted">here</a>:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;72cbc906-01a6-464e-b9b7-bd7d1148fbae&quot;,&quot;caption&quot;:&quot;Just arriving? Join 20,200+ engineers to receive one practical tip on React, Node, and Software Architecture every week.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How Keeping a Work Log (aka Brag List) Helps You Get Promoted? &#128200;&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:10269058,&quot;name&quot;:&quot;Petar Ivanov&quot;,&quot;bio&quot;:&quot;Senior Software Engineer | Practical React, Node, and Software Architecture Tips &#128293; | Author of &#8220;The Conscious React&#8221; book &#9883;&#65039;&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b236a7ab-735e-49d2-bbe8-98b1f901b169_500x500.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-03-09T14:57:45.825Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/949119de-ea8f-4505-9707-d9a40a2f3188_1456x1048.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://thetshaped.dev/p/how-keeping-a-work-log-aka-brag-list-helps-you-get-promoted&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:157248792,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:32,&quot;comment_count&quot;:7,&quot;publication_id&quot;:1508738,&quot;publication_name&quot;:&quot;The T-Shaped Dev&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!9lD-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f66bb7c-c96f-4c71-ba2d-d561152c83a2_600x600.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h2>Week 1-4: Learn Fast, Contribute Faster</h2><h3>Ship Code Early</h3><p>I truly believe in getting your hands dirty immediately.</p><blockquote><p><strong>Aim to ship something in the first week, even in the first few days.</strong></p></blockquote><p>You might fix a bug, add a small feature, improve something in the codebase, or even add a formatting or linting rule.</p><p>I&#8217;ve worked in both frontend and backend, so when I joined my last company, I looked for bugs I could fix in both areas.</p><p>In my first week, I managed to raise the bar high by making an impact by starting to deliver.</p><p>During my first retro, the team said like I&#8217;d been there for months, not days.</p><p>There&#8217;s usually a &#8220;capacity penalty&#8221; when someone new joins.</p><p>You reduce this penalty by contributing quickly.</p><p>Another tip here is to:</p><blockquote><p><strong>Maintain your focus while exploring the codebase.</strong></p></blockquote><p>Don&#8217;t try to understand the entire codebase from the beginning.</p><p>Pick one area and start from there.</p><h3>Start Reviewing Code Immediately</h3><p>You might not understand the business domain yet, but you can still add value.</p><p>You can still share tips and tricks on code reviews related to software design, architecture, and engineering practices, like readability, testing, etc.</p><p>This shows that <strong>you care</strong>.</p><p>You also build your&nbsp;<strong>credibility as an expert</strong>&nbsp;in a particular field.</p><p>As you learn more about the product, you can begin to question requirements and suggest more effective approaches.</p><h3>Ask Questions; Ask Even More</h3><blockquote><p><strong>Your questions reveal what you care about. Ask good ones!</strong></p></blockquote><p>For example:</p><ul><li><p>How do we make money?</p></li><li><p>How do we handle payments?</p></li><li><p>What are our team&#8217;s responsibilities?</p></li><li><p>etc.</p></li></ul><p>Ask your buddy, your mentor, your team, or people outside your team.</p><p>And try not to eat lunch alone.</p><p>I&#8217;m an introvert, so this was hard for me.</p><p>However, I tried to eat at least twice a week with people outside my team.</p><p>This way, I met more smart people, heard different perspectives, and learned about challenges across the company.</p><h3>Align on Expectations</h3><p>On your 1:1s with your manager, sit down and clarify your goals:</p><ul><li><p>What does success look like in my first month?</p></li><li><p>What about the next three months?</p></li><li><p>How to progress further in the career ladder?</p></li></ul><p>Get specific.</p><blockquote><p><strong>Vague goals lead to vague results.</strong></p></blockquote><p>A good starting point is to create your 30-60-90 plan in a document.</p><p>This document maps out a new hire&#8217;s expectations from the perspective of the onboarding Team within the first 90 days of his new role.</p><div><hr></div><h2><strong>&#127873; Notion Template: Work Log (aka Brag List) Template For Software Engineers</strong></h2><p>Use this template to create your own work log (brag list) and list of accomplishments.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://petarivanovv9.gumroad.com/l/eeerf" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3J0Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 424w, https://substackcdn.com/image/fetch/$s_!3J0Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 848w, https://substackcdn.com/image/fetch/$s_!3J0Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 1272w, https://substackcdn.com/image/fetch/$s_!3J0Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3J0Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:245895,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://petarivanovv9.gumroad.com/l/eeerf&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/175195823?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.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_!3J0Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 424w, https://substackcdn.com/image/fetch/$s_!3J0Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 848w, https://substackcdn.com/image/fetch/$s_!3J0Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.png 1272w, https://substackcdn.com/image/fetch/$s_!3J0Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b639d2b-568b-4800-bdbb-9da5c81cc506_1280x720.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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://petarivanovv9.gumroad.com/l/eeerf&quot;,&quot;text&quot;:&quot;I want this!&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://petarivanovv9.gumroad.com/l/eeerf"><span>I want this!</span></a></p><p>Paid subscribers, you can get it here:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/i/144355834/plan-template-for-software-engineers-in-notion&quot;,&quot;text&quot;:&quot;I want this FREE!&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://thetshaped.dev/i/144355834/plan-template-for-software-engineers-in-notion"><span>I want this FREE!</span></a></p><div><hr></div><h2>Month 2-3: Build Your Network and Increase Impact</h2><h3>Map The Organization</h3><p>This is especially helpful for Senior+ roles.</p><p>The main idea here is to get to know the different teams, their responsibilities, and their core domains.</p><p>Since you&#8217;re new to the company, you have the perfect excuse to message someone from this team and ask what they&#8217;re working on:</p><p><em>&#8220;Hi, I&#8217;m new here, and I heard about your team lately. I&#8217;d love to learn what you work on and how our teams might interact&#8230;&#8221;</em></p><p>This is incredibly easy as a new person, and gets much harder later. Use this window.</p><h3>Understand The Business, Not Just The Code</h3><p>Learning the tech stack is one challenge.</p><p>Understanding the business and product domain is another.</p><p><strong>The best engineers combine technical knowledge with business context.</strong></p><p>If you don&#8217;t understand the product well, you can&#8217;t build the right solution.</p><blockquote><p><strong>If the product doesn&#8217;t work, the code doesn&#8217;t matter.</strong></p></blockquote><p>Talk to product managers and more experienced engineers.</p><p>Try to understand the business.</p><p>And <strong>try to work on high-impact things</strong>.</p><p>This isn&#8217;t always possible&#8212;sometimes you have to fix boring bugs&#8212;but communicate with your manager about your impact.</p><h3>Use Your Fresh Perspective</h3><p>You see things that others have become blind to.</p><p>Something that doesn&#8217;t make sense to you probably doesn&#8217;t make sense at all.</p><p>Others just got used to it.</p><blockquote><p><strong>When you spot something that could be improved, document it.<br>Better yet, fix it yourself if you can.</strong></p></blockquote><p>Seek opportunities to make a positive impact.</p><p>Apply your fresh perspectives not only to the code, but also to the current processes, including onboarding.</p><h3>Accept The Entropy</h3><p>Accept that many things won&#8217;t make sense at first, especially if you&#8217;re going from a small to &#8594; big company.</p><p>This is completely normal.</p><p>Give it time. It gets clearer.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JS, React, NodeJS, Software Design and Architecture tips straight into your inbox every week.</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><strong>&#128204; TL;DR</strong></h2><ul><li><p>Reach out to your manager before you start. Ask for materials to prepare.</p></li><li><p>Start your brag document from day 1.</p></li><li><p>Contribute code in week 1.</p></li><li><p>Start code reviews immediately.</p></li><li><p>Ask questions.</p></li><li><p>Try to eat lunch with people from different teams.</p></li><li><p>Align on goals with your manager.</p></li><li><p>Map important teams.</p></li><li><p>Learn the business, not just the code.</p></li><li><p>Apply your fresh perspective.</p></li></ul><p>Hope this was helpful.</p><p>See you next time!</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 28K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[Ace Your Next JavaScript Interview: Promises, Async/Await, Event Loop (Part 4) ✨ ]]></title><description><![CDATA[Learn the deeper concepts in JavaScript, such as Promises, Async/Await, and Event-Loop (5 min)]]></description><link>https://thetshaped.dev/p/javascript-interview-questions-promises-async-await-event-loop-demystified</link><guid isPermaLink="false">https://thetshaped.dev/p/javascript-interview-questions-promises-async-await-event-loop-demystified</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Wed, 17 Sep 2025 11:19:26 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c1b51e40-122e-4a15-98e8-da802be52c92_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 27,700+ engineers to receive one practical tip on JavaScript, React, Node.js, and Software Architecture every week.</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><p>Some time ago, I had an interview, which I almost failed.</p><p>The interviewer asked me questions like Promises and Event Loop.</p><p>I knew what they were, but I failed to clearly elaborate and explain them.</p><blockquote><p><em>If you can&#8217;t explain it simply, do you understand it really well?</em></p></blockquote><p>After the interview, I understood that some knowledge was missing.</p><p>I decided to dig deeper into JavaScript and fill my understanding and knowledge gaps.</p><p>I read many books and articles and took many notes along the way.</p><p>Every time I have a JavaScript interview, I review my notes to refresh my knowledge and prepare.</p><p>In today&#8217;s article, I&#8217;ll delve deeper into asynchronous programming in JavaScript, covering Promises, Async/Await, and the Event Loop.</p><p>This is part 4 of the &#8220;<strong>Ace Your Next JavaScript Interview</strong>&#8221; series. </p><p>If you missed the previous articles, see the bottom of this post.</p><p>Let&#8217;s dive in!</p><div><hr></div><h2><strong><a href="https://coderabbit.link/WFceYHa">CodeRabbit: Free AI Code Reviews in CLI - Sponsor</a></strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://coderabbit.link/WFceYHa" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NFyN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 424w, https://substackcdn.com/image/fetch/$s_!NFyN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 848w, https://substackcdn.com/image/fetch/$s_!NFyN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 1272w, https://substackcdn.com/image/fetch/$s_!NFyN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NFyN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png" width="1374" height="744" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:744,&quot;width&quot;:1374,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:104221,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://coderabbit.link/WFceYHa&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/173012641?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.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_!NFyN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 424w, https://substackcdn.com/image/fetch/$s_!NFyN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 848w, https://substackcdn.com/image/fetch/$s_!NFyN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.png 1272w, https://substackcdn.com/image/fetch/$s_!NFyN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d9cfd4f-d9c5-417d-b74e-f98bfd44d13c_1374x744.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><a href="https://coderabbit.link/WFceYHa">CodeRabbit CLI</a> is an AI code review tool that runs directly in your terminal. It provides intelligent code analysis, catches issues early, and integrates seamlessly with AI coding agents like Claude Code, Codex CLI, Cursor CLI, and Gemini to ensure your code is production-ready before it ships.</p><ul><li><p>Enables pre-commit reviews of both staged and unstaged changes, creating a multi-layered review process.</p></li><li><p>Fits into existing Git workflows. Review uncommitted changes, staged files, specific commits, or entire branches without disrupting your current development process.</p></li><li><p>Reviews specific files, directories, uncommitted changes, staged changes, or entire commits based on your needs.</p></li><li><p>Supports programming languages including JavaScript, TypeScript, and more.</p></li><li><p>Offers free AI code reviews with rate limits so developers can experience senior-level reviews at no cost.</p></li><li><p>Flags hallucinations, code smells, security issues, and performance problems.</p></li><li><p>Supports guidelines for other AI generators, AST Grep rules, and path-based instructions.</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://coderabbit.link/WFceYHa&quot;,&quot;text&quot;:&quot;Get Started Today&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://coderabbit.link/WFceYHa"><span>Get Started Today</span></a></p><div><hr></div><h2>Promises</h2><p>A Promise is an object that allows us to take action when a future event happens.</p><p>It&#8217;s a placeholder for a value that will be available at some point in the future.</p><p>Imagine ordering food at a restaurant&#8212;you get a receipt (Promise) that represents your order, even though your meal is not ready yet.</p><p>Promises have three possible states:</p><ul><li><p><strong>pending</strong> - the operation is still in progress</p></li><li><p><strong>fulfilled</strong> - the operation completed successfully</p></li><li><p><strong>rejected</strong> - the operation failed</p></li></ul><p>Upon creation, the Promise takes a function that will be passed two arguments - a resolution callback and a rejection callback.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O2g2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O2g2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 424w, https://substackcdn.com/image/fetch/$s_!O2g2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 848w, https://substackcdn.com/image/fetch/$s_!O2g2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 1272w, https://substackcdn.com/image/fetch/$s_!O2g2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O2g2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png" width="437" height="247.3131868131868" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:824,&quot;width&quot;:1456,&quot;resizeWidth&quot;:437,&quot;bytes&quot;:240597,&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://thetshaped.dev/i/173012641?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.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_!O2g2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 424w, https://substackcdn.com/image/fetch/$s_!O2g2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 848w, https://substackcdn.com/image/fetch/$s_!O2g2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.png 1272w, https://substackcdn.com/image/fetch/$s_!O2g2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0a31be2-7209-42c9-ad51-51c38dab1ac8_2246x1271.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>Most of the time, you&#8217;ll be consuming Promises rather than creating them.</p><p>The <strong>then()</strong> method is available on the <strong>Promise</strong> object and will run with the value passed to the <strong>resolve()</strong> function.</p><p>The <strong>catch()</strong> method runs if the <strong>reject()</strong> function was called.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OPYS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OPYS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 424w, https://substackcdn.com/image/fetch/$s_!OPYS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 848w, https://substackcdn.com/image/fetch/$s_!OPYS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 1272w, https://substackcdn.com/image/fetch/$s_!OPYS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OPYS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png" width="430" height="211.16071428571428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:715,&quot;width&quot;:1456,&quot;resizeWidth&quot;:430,&quot;bytes&quot;:192080,&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://thetshaped.dev/i/173012641?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.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_!OPYS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 424w, https://substackcdn.com/image/fetch/$s_!OPYS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 848w, https://substackcdn.com/image/fetch/$s_!OPYS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 1272w, https://substackcdn.com/image/fetch/$s_!OPYS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1938f7b-376a-4b5a-b531-79590945b54a_2246x1103.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>One of the most powerful features of Promises is chaining.</p><p>If a <strong>then()</strong> handler returns another Promise, you can chain additional <strong>then()</strong> calls.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QOHw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QOHw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 424w, https://substackcdn.com/image/fetch/$s_!QOHw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 848w, https://substackcdn.com/image/fetch/$s_!QOHw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 1272w, https://substackcdn.com/image/fetch/$s_!QOHw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QOHw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png" width="469" height="294.41346153846155" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:914,&quot;width&quot;:1456,&quot;resizeWidth&quot;:469,&quot;bytes&quot;:290623,&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://thetshaped.dev/i/173012641?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.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_!QOHw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 424w, https://substackcdn.com/image/fetch/$s_!QOHw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 848w, https://substackcdn.com/image/fetch/$s_!QOHw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.png 1272w, https://substackcdn.com/image/fetch/$s_!QOHw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525e279d-a8fb-40cf-810a-258007becdfa_2425x1523.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><div><hr></div><h2>Async/Await</h2><p>While Promises are powerful, the syntax can become hard to read and follow with complex chains.</p><p>The async/await keywords provide a syntax sugar over the Promises that will make your code read as if it were synchronous.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8_bE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8_bE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 424w, https://substackcdn.com/image/fetch/$s_!8_bE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 848w, https://substackcdn.com/image/fetch/$s_!8_bE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 1272w, https://substackcdn.com/image/fetch/$s_!8_bE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8_bE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png" width="457" height="253.6098901098901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:808,&quot;width&quot;:1456,&quot;resizeWidth&quot;:457,&quot;bytes&quot;:226563,&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://thetshaped.dev/i/173012641?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.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_!8_bE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 424w, https://substackcdn.com/image/fetch/$s_!8_bE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 848w, https://substackcdn.com/image/fetch/$s_!8_bE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.png 1272w, https://substackcdn.com/image/fetch/$s_!8_bE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb92f70-1747-49c7-894a-129df782d472_2139x1187.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>There are a few key points about <strong>async/await</strong>:</p><ul><li><p>You can only use <strong>await</strong> inside functions marked with <strong>async</strong>.</p></li><li><p><strong>Async</strong> functions always return a <strong>Promise</strong>.</p></li><li><p>Use <strong>try/catch</strong> blocks for error handling instead of .<strong>catch()</strong>.</p></li><li><p>The code executed asynchronously despite looking synchronous.</p></li></ul><div><hr></div><h2>Event Loop</h2><p>Here is where things get really interesting.</p><p>JavaScript is single-threaded, meaning it can only do one thing at a time.</p><p>So how does it handle asynchronous operations without blocking the entire program?</p><p>The answer is its execution flow, which is based on an event loop.</p><p>On a high level, the engine runs an endless loop that checks if there are tasks waiting for it in a queue.</p><p>If there are, it executes them and continues to wait for more.</p><p>Any code that can&#8217;t run immediately is queued, and the execution continues until it exhausts the call stack.</p><pre><code>setTimeout(() =&gt; {
  console.log('Later');
}, 1000);

console.log('Now');

// Output:
// Now
// Later (after 1 second)</code></pre><p>Even with a zero timeout, the callback still runs after the synchronous code:</p><pre><code>setTimeout(() =&gt; {
  console.log('Later');
}, 0);

console.log('Now');

// Output:
// Now
// Later (after 1 second)</code></pre><p>The Event Loop manages two main areas:</p><ul><li><p><strong>Call Stack</strong> - where your currently executing code lives.</p></li><li><p><strong>Task Queue</strong> - where asynchronous callbacks wait to be executed.</p></li></ul><p>The Event Loop only processes the task queue when the call stack is empty.</p><pre><code>setTimeout(() =&gt; {
  console.log('Later');
}, 0);

// This loop keeps the call stack busy
for (let i = 0; i &lt; 100000; i++) {
  console.log(i);
}

// Output:
// 0
// 1
// 2
// ...
// 99999
// Later</code></pre><p>The loop keeps adding items to the call stack and the event loop never gets a chance to reach the task queue.</p><p>When asynchronous calls are queued using the same method, for example, <strong>setTimeout</strong>, their execution order follows the order in which they were added.</p><pre><code>setTimeout(() =&gt; {
  console.log('Later');
}, 0);

setTimeout(() =&gt; {
  console.log('Even Later');
}, 0)

// Output:
// Later
// Even Later</code></pre><p>But if we queue a <strong>Promise</strong> and a call to <strong>setTimeout</strong>, the <strong>Promise</strong> will be the first to run.</p><pre><code>setTimeout(() =&gt; {
  console.log('Later');
}, 0);

Promise.resolve().then(() =&gt; {
  console.log('Also Later');
});

// Output:
// Also Later
// Later</code></pre><p>This is because promises and timeouts are put on two separate queues that have different priorities:</p><ul><li><p><strong>Macrotask Queue</strong> (aka task queue) - <strong>setTimeout</strong>, <strong>setInterval</strong>, DOM events, etc.</p></li><li><p><strong>Microtask Queue</strong> (aka jobs queue) - <strong>Promise callbacks</strong>, <strong>queueMicrotask()</strong>, etc.</p></li></ul><p>The event loop prioritizes the execution of pending microtasks.</p><p>Then the event loop will handle the next pending macrotask.</p><p>Immediately after every macrotask runs, the event loop will run all pending microtasks before continuing with the macrotasks again.</p><p>Here is a nice visualization I found on the Internet:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UQ3Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 424w, https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 848w, https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 1272w, https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif" width="880" height="495" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/de275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:495,&quot;width&quot;:880,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1504612,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/173012641?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 424w, https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 848w, https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 1272w, https://substackcdn.com/image/fetch/$s_!UQ3Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde275867-d25c-4dd3-8725-3e5e86b305c9_880x495.gif 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>Let&#8217;s see one final code example to check your understanding:</p><pre><code>console.log("start");

setTimeout(() =&gt; console.log("timeout"), 0);

Promise.resolve().then(() =&gt; console.log("Promise.resolve"));

new Promise((resolve, reject) =&gt; {
    resolve();
    console.log("executor");
}).then(() =&gt; console.log("promise"));

console.log("synchronous");</code></pre><p>To see the answer, see the comments.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JavaScript, React, Node.js, and Software Architecture tips straight into your inbox every week.</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><strong>&#128204; TL;DR</strong></h2><ul><li><p>Promises give you a clean way to handle future values and chain async operations.</p></li><li><p>Async/Await is a syntax sugar over Promises, giving you a simple mental model and making your code more readable.</p></li><li><p>The Event Loop is a fundamental aspect of async programming in JavaScript.</p></li><li><p>Event Loop handles async operations efficiently in JavaScript.</p></li></ul><p>Hope this was helpful.</p><p>See you next time!</p><div><hr></div><h2>Ace Your Next JavaScript Interview Series</h2><ol><li><p><a href="https://thetshaped.dev/p/ace-your-next-javascript-interview-scope-hoisting-closures-simplified">Scope, Hoisting, and Closures</a></p></li><li><p><a href="https://thetshaped.dev/p/ace-your-next-javascript-interview-values-references-coercion-equality">Values, References, Coercion, and Equality</a></p></li><li><p><a href="https://thetshaped.dev/p/ace-your-next-javascript-interview-this-new-keywords-prototypes-classes">this, new, Prototypes, and Classes</a></p></li></ol><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 27.7K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[What Is a Modular Monolith And Why You Should Care? 🔥]]></title><description><![CDATA[Learn more about modular monoliths, their benefits, and the challenges with microservices. (6 min)]]></description><link>https://thetshaped.dev/p/what-is-a-modular-monolith-benefits-and-microservices-challenges</link><guid isPermaLink="false">https://thetshaped.dev/p/what-is-a-modular-monolith-benefits-and-microservices-challenges</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 09 Sep 2025 11:19:26 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/660ed777-9159-415d-9d85-0732ae775fc4_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 27,700+ engineers to receive one practical tip on JavaScript, React, Node.js, and Software Architecture every week.</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><p>Over the last few years, I have managed to work with various software architectures, ranging from monoliths to microservices and their variations.</p><p>Each architecture had its own set of unique challenges, problems, and advantages.</p><p>And there is one architecture that really stood out&#8212;the <strong>Modular Monolith architecture</strong>.</p><p>Modular monoliths blend the simplicity and robustness of traditional monolithic applications with the flexibility and scalability of microservices.</p><p>I&#8217;d say that modular monoliths bring the best of both worlds.</p><p>The modular monolith architecture allows you to work in a unified codebase with clearly defined boundaries and independent modules.</p><p>This way, you can have high development velocity without the complexity of distributed systems.</p><p>In today&#8217;s article, I&#8217;ll share more about modular monolith architecture and why you should know about it.</p><div><hr></div><h2><strong><a href="https://coderabbit.link/petar">CodeRabbit: Free AI Code Reviews in VS Code - Sponsor</a></strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://coderabbit.link/petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_jzt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 424w, https://substackcdn.com/image/fetch/$s_!_jzt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 848w, https://substackcdn.com/image/fetch/$s_!_jzt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 1272w, https://substackcdn.com/image/fetch/$s_!_jzt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_jzt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp" width="1456" height="741" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:741,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83074,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/173005271?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_jzt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 424w, https://substackcdn.com/image/fetch/$s_!_jzt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 848w, https://substackcdn.com/image/fetch/$s_!_jzt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 1272w, https://substackcdn.com/image/fetch/$s_!_jzt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cd9ea71-0439-48ac-9acc-d658528484d5_1456x741.webp 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><a href="https://coderabbit.link/petar">CodeRabbit</a> brings real-time, AI-powered code reviews straight into VS Code, Cursor, and Windsurf. It lets you:</p><ul><li><p>Get contextual feedback on every commit, not just at the PR stage</p></li><li><p>Catch bugs, security flaws, and performance issues as you code</p></li><li><p>Apply AI-driven suggestions instantly to implement code changes</p></li><li><p>Do code reviews in your IDE for free and in your PR for a paid subscription</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;text&quot;:&quot;Install in VS Code for FREE&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://coderabbit.link/petar"><span>Install in VS Code for FREE</span></a></p><div><hr></div><h2>What is a Modular Monolith?</h2><p>A modular monolith is a single deployable application that&#8217;s internally organized into well-defined and loosely-coupled modules.</p><p>The modules are split into logical boundaries, grouping related functionality together.</p><p>These modules communicate through well-defined, public APIs, events, or messages, instead of directly calling each other&#8217;s functionality.</p><p>These approaches promote modularity and separation of concerns, and improve the cohesion of the system.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!izZn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!izZn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 424w, https://substackcdn.com/image/fetch/$s_!izZn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 848w, https://substackcdn.com/image/fetch/$s_!izZn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 1272w, https://substackcdn.com/image/fetch/$s_!izZn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!izZn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png" width="1456" height="739" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:739,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:396697,&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://thetshaped.dev/i/173005271?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.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_!izZn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 424w, https://substackcdn.com/image/fetch/$s_!izZn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 848w, https://substackcdn.com/image/fetch/$s_!izZn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.png 1272w, https://substackcdn.com/image/fetch/$s_!izZn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57ac305b-7f87-4678-89e7-2fb3c4e997f2_2052x1042.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>You can think of modular monoliths as a microservices architecture packaged into one deployment unit.</p><p>This way, you get the organizational benefits of the service boundaries without the distributed system overhead.</p><p>Even if you want to scale one of the modules due to high traffic or other factors, you can easily extract the module and deploy it independently.</p><p>Modular monoliths give you this kind of flexibility.</p><div><hr></div><h2>What is a Modular Architecture?</h2><p>To design a modular monolith, we must understand what a modular architecture is.</p><p>The <strong>core principles</strong> of modular architecture include:</p><ul><li><p><strong>Separations of Concerns</strong> - Each module is independent, handling a specific business domain or business capability.</p></li><li><p><strong>Loose Coupling</strong> - Modules depend on interfaces, not implementations.</p></li><li><p><strong>High Cohesion</strong> - Related functionality stays together within modules.</p></li><li><p><strong>Explicit Interfaces</strong> - Clear contracts define how modules interact.</p></li></ul><p>This means that <strong>each module</strong>:</p><ul><li><p>Must be independent.</p></li><li><p>Must provide the required functionality.</p></li><li><p>Must expose a well-defined interface to other modules.</p></li></ul><p>The end goal is not to have 100% independent modules because this would mean that modules are not integrated together.</p><p>The main idea is to have <strong>loosely coupled modules</strong> and <strong>keep the number of dependencies low</strong>.</p><p>We can use a few techniques to keep the modules independent, like data isolation and linting rules, for example.</p><p>If we see that two modules communicate too much with each other, you might have incorrectly defined boundaries.</p><p>Then, you could consider merging the two modules together.</p><p>Remember:</p><blockquote><p><strong>A module is a grouping of related functionalities together that are accessed through a well-defined interface.</strong></p></blockquote><p>And once you have a modular architecture, you can easily extract modules into separate services.</p><div><hr></div><h2>Start With a Modular Monolith</h2><p>In recent years, developers have favored the microservices architecture.</p><p>Yes, it provides many benefits like better scalability, clear service boundaries, independence, and much more.</p><p>But, it does come with a big cost - complexity.</p><p>I&#8217;d say that most teams and companies would be better off starting with a monolith application.</p><p>As <a href="https://martinfowler.com/bliki/MonolithFirst.html">Martin Fowler</a> says:</p><blockquote><p><strong>You shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile.</strong></p></blockquote><p>And even better, consider starting with a modular monolith.</p><p>When you&#8217;re building a new system, you&#8217;re making countless architectural decisions with incomplete information.</p><p>You don&#8217;t fully understand your users patterns, scaling needs, domain boundaries, etc.</p><p>Starting with microservices in these early days will lock you into these often incorrect assumptions.</p><p>Even big players like Shopify and Google bet on modular monoliths.</p><p>You can read this paper from Google about &#8220;<a href="https://dl.acm.org/doi/pdf/10.1145/3593856.3595909">Towards Modern Development of Cloud Applications</a>&#8221;.</p><p>In this paper, Goggle identifies five <strong>main challenges with microservices</strong>:</p><ul><li><p><strong>Performance</strong> - Sending data between services over the network slows everything down, especially when you split your app into too many pieces.</p></li><li><p><strong>Correctness</strong> - Most big failures happen when different versions of services try to talk to each other and mess up.</p></li><li><p><strong>Management</strong> - Have to manage multiple different applications, each with its release schedule.</p></li><li><p><strong>Frozen APIs</strong> - Once you create an API between services, it&#8217;s really hard to change it without breaking everything else.</p></li><li><p><strong>Development Velocity</strong> - When you need to make changes across multiple services, you can&#8217;t just deploy them all at once - you have to coordinate carefully.</p></li></ul><p>As you see, the cost of starting with microservices is high.</p><p>So starting with a modular monolith sounds compelling.</p><p>I also recommend reading about the <a href="https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing">fallacies of distributed computing</a> if you&#8217;re unfamiliar with them.</p><p>Remember:</p><blockquote><p><strong>You can easily migrate from a modular monolith architecture to a microservices architecture because each module is well defined, isolated, and separated.</strong></p></blockquote><div><hr></div><h2>Benefits of a Modular Monolith</h2><p>Modular monoliths have multiple benefits.</p><p>Here are the ones I consider the most important:</p><ul><li><p><strong>Simplified deployment</strong> - You build, test, and deploy one application instead of multiple services across different environments.</p></li><li><p><strong>Improved performance</strong> - Communication between modules happens through fast in-memory calls, instead of slow network requests.</p></li><li><p><strong>Enhanced development velocity</strong> - You have a single codebase to manage which simplifies the debugging and the overall development process.</p></li><li><p><strong>Easier transaction management</strong> - Managing transactions in a distributed systems is very challenging. With modular monoliths you use a single database and transactions are much simpler.</p></li><li><p><strong>Lower operational complexity</strong> - Modular monoliths reduce the operational overhead that comes with managing and deploying a distributed microservice system.</p></li><li><p><strong>Easier transition to microservices</strong> - Well-defined module boundaries make it straightforward to extract individual services and use microservices.</p></li></ul><div><hr></div><h2>Monolith vs. Modular Monolith vs. Microservices</h2><p>The biggest difference between modular monoliths and microservices is how they&#8217;re deployed.</p><p>Microservices use physical boundaries between services, while modular monoliths use logical boundaries.</p><p>With microservices, you have a clear strategy for modularity and structuring bounded contexts.</p><p>But, you can achieve this without building a distributed system.</p><p>The main problem is when people try to enforce code boundaries using microservices.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZJpO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZJpO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 424w, https://substackcdn.com/image/fetch/$s_!ZJpO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 848w, https://substackcdn.com/image/fetch/$s_!ZJpO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 1272w, https://substackcdn.com/image/fetch/$s_!ZJpO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZJpO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png" width="1456" height="824" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:824,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:432632,&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://thetshaped.dev/i/173005271?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.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_!ZJpO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 424w, https://substackcdn.com/image/fetch/$s_!ZJpO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 848w, https://substackcdn.com/image/fetch/$s_!ZJpO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.png 1272w, https://substackcdn.com/image/fetch/$s_!ZJpO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac4bc53c-0ea5-46f2-8206-3248b72a6d3f_3260x1844.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>Instead, you can build a modular monolith to get almost the same benefits.</p><p>Modular monoliths give you high cohesion, low coupling, data encapsulation, focus on business functionalities, and more.</p><p>Microservices also give you independent deployments, independent scalability, and the ability to use a different tech stack per service.</p><p>You can think of the difference as a well-organized apartment (modular monolith) vs. a neighborhood of separate houses (microservices) - both have clear boundaries, but one is much simpler to maintain.</p><blockquote><p><strong>Choose microservices for the benefits, not because your monolithic codebase is a mess.</strong> <br>&#8212; <a href="https://x.com/simonbrown">Simon Brown</a></p></blockquote><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JavaScript, React, Node.js, and Software Architecture tips straight into your inbox every week.</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><strong>&#128204; TL;DR</strong></h2><ul><li><p>Modular monoliths offer a compelling way to structure applications.</p></li><li><p>Modular monoliths offer most of the benefits of microservices without the complexity of distributed systems.</p></li><li><p>Modular monoliths offer a smooth way to transition to microservices if needed.</p></li><li><p>The main difference between microservices and modular monoliths is how they are deployed.</p></li></ul><p>Hope this was helpful.</p><p>See you next week!</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 27.7K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[Code Review Guidelines ✅]]></title><description><![CDATA[What Authors and Reviewers Should Actually Do? (5 min)]]></description><link>https://thetshaped.dev/p/code-review-guidelines-for-authors-and-reviewers-quality-code-reviews</link><guid isPermaLink="false">https://thetshaped.dev/p/code-review-guidelines-for-authors-and-reviewers-quality-code-reviews</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 02 Sep 2025 11:19:21 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/162d978b-6e6a-4dfe-94ef-1c9872b3644d_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 27,595+ engineers to receive one practical tip on JavaScript, React, Node, and Software Architecture every week.</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><p>Code review is a process that allows others to review your code changes.</p><p>The person who submits the code changes is referred to as the &#8220;Author&#8221;, while those reviewing the changes are referred to as &#8220;Reviewers&#8221;.</p><p>The primary <strong>purpose</strong> of code reviews is to:</p><blockquote><p>Enhance the <strong>quality of the released solution</strong>&nbsp;and improve <strong>collaboration</strong> and <strong>knowledge transfer</strong> within the team.</p></blockquote><p>However, doing code reviews right is not an easy task.</p><p>There are many&nbsp;<strong>problems</strong>&nbsp;related to&nbsp;<strong>code reviews</strong>, like wasted human effort and time, wrong focus &#8594; wrong results, communication breakdown, criticism, decreased developer productivity, and team velocity.</p><p>In today&#8217;s article, I&#8217;d like to share several code review guidelines, both for Authors and Reviewers, that I've seen working in teams and companies.</p><p>Let&#8217;s dive in!</p><div><hr></div><h2>The Hidden Cost of Broken Code Reviews</h2><ol><li><p><strong>Reviews Become Time Sinks</strong></p></li></ol><ul><li><p>The average PR takes 2-4 days from submission to merge.</p></li><li><p>Teams spend 8-12 hours per week on code reviews instead of building features.</p></li></ul><ol start="2"><li><p><strong>Wrong Focus &#8594; Wrong Results</strong></p></li></ol><ul><li><p>Developers spend 50% of review time on formatting, naming conventions, and style preferences.</p></li><li><p>Meanwhile, logic bugs, security vulnerabilities, and performance issues slide past because reviewers are mentally exhausted from nitpicking.</p></li></ul><ol start="3"><li><p><strong>Communication Breakdown</strong></p></li></ol><ul><li><p>Authors write vague PR descriptions.</p></li><li><p>Reviewers give unclear feedback and/or criticize the author.</p></li><li><p>Nobody knows if an issue is critical or optional.</p></li><li><p>Simple fixes turn into multi-day discussions.</p></li><li><p>The cost isn&#8217;t just velocity&#8212;it&#8217;s team morale, code quality, and customer trust when bugs reach production. </p></li></ul><div><hr></div><p>Code reviews are expensive since there are many people involved in this activity.</p><p>That&#8217;s why I&#8217;m happy to partner with <strong><a href="https://coderabbit.link/petar">CodeRabbit</a></strong> on this newsletter.</p><p>With the help of&nbsp;<a href="https://coderabbit.link/petar">CodeRabbit</a>, I believe we can make them cheaper by automating the process, fixing the obvious problems, and focusing on the right things.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;text&quot;:&quot;Try CodeRabbit&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://coderabbit.link/petar"><span>Try CodeRabbit</span></a></p><div><hr></div><h2>Best Practices for Authors:</h2><ul><li><p><strong>Review your own code changes and PR first</strong> before sharing with others.</p><ul><li><p>Remove debug statements and commented code.</p></li><li><p>Check for obvious bugs or typos.</p></li><li><p>Consider using <a href="https://coderabbit.link/petar">CodeRabbit</a> for giving instant feedback.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://coderabbit.link/petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RLFG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 424w, https://substackcdn.com/image/fetch/$s_!RLFG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 848w, https://substackcdn.com/image/fetch/$s_!RLFG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 1272w, https://substackcdn.com/image/fetch/$s_!RLFG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RLFG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp" width="1456" height="741" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:741,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83074,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/172230453?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RLFG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 424w, https://substackcdn.com/image/fetch/$s_!RLFG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 848w, https://substackcdn.com/image/fetch/$s_!RLFG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 1272w, https://substackcdn.com/image/fetch/$s_!RLFG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7744e25-84b1-41ba-b58c-e6f028d70429_1456x741.webp 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></li></ul></li><li><p><strong>Ensure consistent naming and formatting.</strong></p><ul><li><p>Especially if your company follows a style guide.</p></li></ul></li><li><p><strong>Test your code changes.</strong></p><ul><li><p>Both manually and with automated tests.</p></li></ul></li><li><p><strong>Know what each new line does.</strong></p><ul><li><p>This is very crucial in the era of vibe coding.</p></li></ul></li><li><p><strong>Automate the easy stuff.</strong></p><ul><li><p>Add formatters, linters, and rules to prevent nitpicking.</p></li><li><p>Consider using <a href="https://coderabbit.link/petar">CodeRabbit</a> for finding potential issues.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://coderabbit.link/petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mUm7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 424w, https://substackcdn.com/image/fetch/$s_!mUm7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 848w, https://substackcdn.com/image/fetch/$s_!mUm7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 1272w, https://substackcdn.com/image/fetch/$s_!mUm7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mUm7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp" width="540" height="409.0796703296703" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1103,&quot;width&quot;:1456,&quot;resizeWidth&quot;:540,&quot;bytes&quot;:112896,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/172230453?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mUm7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 424w, https://substackcdn.com/image/fetch/$s_!mUm7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 848w, https://substackcdn.com/image/fetch/$s_!mUm7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 1272w, https://substackcdn.com/image/fetch/$s_!mUm7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff458a44e-50a1-4ce3-ad47-24a1e9972385_1456x1103.webp 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></li></ul></li></ul><ul><li><p><strong>Keep your code changes and PR small.</strong></p><ul><li><p>Research shows that review quality drops dramatically with the increasing number of files, lines, and changes. Ex: 400+ lines.</p></li><li><p>If your feature needs more code, <strong>break it into logical steps</strong> that can be reviewed independently.</p></li></ul></li><li><p><strong>Write a clear PR description. </strong>Try to answer the questions:</p><ul><li><p><strong>What</strong> - &#8220;Add rate limiting to login endpoint...&#8221;</p></li><li><p><strong>Why</strong> - &#8220;Prevent brute force attacks&#8230;&#8221;</p></li><li><p><strong>How</strong> - &#8220;Implement rate limiting algorithms, block IPs&#8230;&#8221;</p></li><li><p><strong>Testing</strong> - &#8220;Tested with 100 concurrent requests and verified&#8230;&#8221;</p></li><li><p>For visual changes, include relevant <strong>screenshots and/or videos</strong> that showcase the changes.</p></li><li><p>For bug fixes, outline the <strong>Before and After behaviors</strong>, and how you fixed them.</p></li><li><p>Consider using <a href="https://coderabbit.link/petar">CodeRabbit</a> for generating a summary of the changes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qJyW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJyW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 424w, https://substackcdn.com/image/fetch/$s_!qJyW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 848w, https://substackcdn.com/image/fetch/$s_!qJyW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 1272w, https://substackcdn.com/image/fetch/$s_!qJyW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJyW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp" width="562" height="464.7307692307692" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1204,&quot;width&quot;:1456,&quot;resizeWidth&quot;:562,&quot;bytes&quot;:94848,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/172230453?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qJyW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 424w, https://substackcdn.com/image/fetch/$s_!qJyW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 848w, https://substackcdn.com/image/fetch/$s_!qJyW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 1272w, https://substackcdn.com/image/fetch/$s_!qJyW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cb6ed6f-d8e7-42fd-90f5-918f5888f80d_1456x1204.webp 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></li></ul></li><li><p><strong>Document the non-obvious changes.</strong></p><ul><li><p>Try to answer questions with the code itself.</p></li></ul></li><li><p><strong>Respond graciously to critiques.</strong></p><ul><li><p>Remember, it&#8217;s not about you, it&#8217;s about the code.</p></li></ul></li><li><p><strong>If you&#8217;re confused, ask clarifying questions.</strong></p><ul><li><p>Don&#8217;t guess, ask questions instead.</p></li><li><p>Ex:&nbsp;<em>"When you say 'this could be cleaner, ' do you mean splitting this function or renaming the variables?"</em></p></li></ul></li><li><p><strong>Be patient when your reviewer is wrong.</strong></p><ul><li><p>Reviewers might be wrong due to a lack of context or experience, so try to provide it and help them understand your perspective.</p></li></ul></li><li><p><strong>Minimize the lag between rounds of review.</strong></p><ul><li><p>Acknowledge feedback within 4 hours, even if you can&#8217;t fix everything immediately.</p></li><li><p>Quick responses show respect for your reviewer&#8217;s time.</p></li></ul></li><li><p><strong>Consider doing a pair programming session with the reviewer if needed.</strong></p><ul><li><p>Peer code reviews work as a two-way transfer of knowledge when conducted carefully.</p></li><li><p>Both the reviewer and the author can learn new things, either for the project or in general.</p></li></ul></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable Software Engineering and JavaScript-related tips straight into your inbox every week.</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>Best Practices for Reviewers:</h2><ul><li><p><strong>Review PRs within 24 hours of submission.</strong></p><ul><li><p>This not only unblocks the author to merge their code but also speeds up the development process.</p></li></ul></li><li><p><strong>Prioritize your review using this framework:</strong></p><ul><li><p><strong>Correctness:</strong> Does the code work as intended?</p></li><li><p><strong>Organization:</strong> Is it well-structured, maintainable, and follows the style guides?</p></li><li><p><strong>Readability:</strong> Can the team and future me understand and modify this later?</p></li><li><p><strong>Reliability:</strong> Is the solution fault-tolerant?</p></li><li><p><strong>Scalability:</strong> Can the solution grow to accommodate higher future load?</p></li><li><p><strong>Edge cases:</strong> What could go wrong in production?</p></li></ul></li><li><p><strong>Prioritize your feedback:</strong></p><ul><li><p><strong>Critical (must fix)</strong>&nbsp;- logic errors and bugs; security vulnerabilities; breaking changes; performance bottlenecks.</p></li><li><p><strong>Important (should fix)</strong> - poor code organization; missing error handling; inadequate tests.</p></li><li><p><strong>Suggestions (optional)</strong> - alternative implementations; style improvements; minor optimizations.</p></li></ul></li><li><p><strong>Don&#8217;t make it personal! Review the code, not the author.</strong></p></li><li><p><strong>Learn to give better feedback. Ask, don&#8217;t tell!</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.linkedin.com/posts/petarivanovv9_if-you-want-to-learn-how-to-do-better-code-activity-7366427956782542848-Wr_q" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fMA0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 424w, https://substackcdn.com/image/fetch/$s_!fMA0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 848w, https://substackcdn.com/image/fetch/$s_!fMA0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 1272w, https://substackcdn.com/image/fetch/$s_!fMA0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fMA0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png" width="444" height="589.6256684491979" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1490,&quot;width&quot;:1122,&quot;resizeWidth&quot;:444,&quot;bytes&quot;:1030504,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.linkedin.com/posts/petarivanovv9_if-you-want-to-learn-how-to-do-better-code-activity-7366427956782542848-Wr_q&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/172230453?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.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_!fMA0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 424w, https://substackcdn.com/image/fetch/$s_!fMA0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 848w, https://substackcdn.com/image/fetch/$s_!fMA0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.png 1272w, https://substackcdn.com/image/fetch/$s_!fMA0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a0129a-3f83-4b24-8a8c-a8b58c406487_1122x1490.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><ul><li><p>When you add a comment, have a strong WHY and a suggestion.</p></li><li><p>Mark more comments as NIT and don&#8217;t block PRs.</p></li></ul></li><li><p><strong>Praise the good things.</strong></p><ul><li><p>Engineers, and people in general, tend to criticize when doing any kind of review, while forgetting to mention any good.</p></li><li><p>For the reviewer to be able to learn from the author, he should pay attention to the clever code as well, and it is a good habit to notice it.</p></li></ul></li><li><p><strong>Consider doing a pair programming session with the reviewer if needed.</strong></p><ul><li><p>Sometimes, it&#8217;s better to sit together and resolve all issues instead of going through multiple rounds of reviews.</p></li></ul></li><li><p><strong>When critical issues are resolved and code is &#8220;good enough&#8221;</strong> &#8594; <strong>Approve it</strong>.</p></li><li><p><strong>Code review is part of your job.</strong></p><ul><li><p>If you're not doing code reviews regularly, you are letting your teammates down.</p></li></ul></li></ul><div><hr></div><p><strong><a href="https://coderabbit.link/petar">CodeRabbit</a></strong> is an AI code review tool to reduce developer workload.</p><p>Here&#8217;s how it helps with code review flow:</p><ul><li><p>Do routine checks and reduce the time spent on reviews from days to minutes. Thus, improving developer velocity.</p></li><li><p>Do consistent reviews without getting tired or biased. Thus, it reduces the risk of missing important issues due to human mistakes.</p></li><li><p>Provide mentorship to junior engineers through detailed feedback.</p></li></ul><p>Put simply, <a href="https://coderabbit.link/petar">CodeRabbit</a> complements human reviewers. It serves 1+ million repositories and has reviewed over 10 million pull requests. And it remains the most installed app on GitHub and GitLab.</p><div><hr></div><h2>&#128204; TL;DR</h2><ul><li><p><strong><a href="https://thetshaped.dev/i/172230453/best-practices-for-authors">Guidelines for Authors:</a></strong></p><ul><li><p>Review your own code changes and PR first.</p></li><li><p>Ensure consistent naming and formatting.</p></li><li><p>Test your code changes.</p></li><li><p>Know what each new line does.</p></li><li><p>Automate the easy stuff.</p></li><li><p>Keep your code changes and PR small.</p></li><li><p>Write a clear PR description.</p></li><li><p>Document the non-obvious changes.</p></li><li><p>Respond graciously to critiques.</p></li><li><p>If you&#8217;re confused, ask clarifying questions.</p></li><li><p>Be patient when your reviewer is wrong.</p></li><li><p>Minimize the lag between rounds of review.</p></li></ul></li><li><p><strong><a href="https://thetshaped.dev/i/172230453/best-practices-for-reviewers">Guidelines for Reviewers:</a></strong></p><ul><li><p>Review PRs within 24 hours of submission.</p></li><li><p>Prioritize your review using a framework and quality attributes.</p></li><li><p>Prioritize your feedback.</p></li><li><p>Don&#8217;t make it personal! Review the code, not the author.</p></li><li><p>Learn to give better feedback. Ask, don&#8217;t tell!</p></li><li><p>Praise the good things.</p></li><li><p>When critical issues are resolved and code is &#8220;good enough&#8221; &#8594; Approve it.</p></li><li><p>Core reviews are part of your job.</p></li></ul></li></ul><p>Hope this was helpful.</p><p>See you next week!</p><p><strong>Today&#8217;s action step:</strong> Take a look at your code review process and highlight areas for improvement. Try to follow or incorporate one of the mentioned tips in your daily routine.</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 27.5K+ subscribers this week &#128591;</em></p>]]></content:encoded></item><item><title><![CDATA[Clean Code: 8 Tips to Write Clean Functions 🔥]]></title><description><![CDATA[Learn about eight practical tips on writing clean functions. (5 min)]]></description><link>https://thetshaped.dev/p/clean-code-8-practical-tips-to-write-clean-functions</link><guid isPermaLink="false">https://thetshaped.dev/p/clean-code-8-practical-tips-to-write-clean-functions</guid><dc:creator><![CDATA[Petar Ivanov]]></dc:creator><pubDate>Tue, 26 Aug 2025 11:19:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/2ec4ef91-d637-4f28-b186-0ec93dc6b382_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Just arriving? Join 27,471+ engineers to receive one practical tip on JavaScript, React, Node, and Software Architecture every week.</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><p><strong>Clean Code</strong> is code that is easy to read, maintain, test, and understand.</p><p><strong>Clean Functions</strong> are the foundation of <strong>Clean Code</strong>.</p><p>Master clean functions and you&#8217;ll naturally write better software.</p><p>In today&#8217;s article, I&#8217;ll share 8 practical tips for writing clean functions that I follow daily in my projects and work.</p><p>Let&#8217;s dive in!</p><div><hr></div><h2><a href="https://coderabbit.link/petar">Cut Code Review Time &amp; Bugs in Half - Sponsor</a></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://coderabbit.link/petar" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eJXF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!eJXF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!eJXF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!eJXF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eJXF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:199568,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eJXF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!eJXF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!eJXF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!eJXF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4ded051-9bf0-4732-8b76-f1bb9151bcda_1600x800.jpeg 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><a href="https://coderabbit.link/petar">CodeRabbit</a> is your AI-powered code review co-pilot.</p><p>It provides instant, contextual feedback on every PR, along with one-click fix suggestions. It has reviewed over 10 million PRs and is used in 1 million repositories.</p><p>Besides, it&#8217;s free to use for open-source repos; 70K+ open-source projects already use it.</p><p><a href="https://coderabbit.link/petar">CodeRabbit</a> lets you instantly spot:</p><ul><li><p>Logic &amp; syntax bugs</p></li><li><p>Security issues (XSS, SQL injection, CSRF)</p></li><li><p>Concurrency problems (deadlocks, race conditions)</p></li><li><p>Code smells &amp; readability concerns</p></li><li><p>Best practice violations (SOLID, DRY, KISS)</p></li><li><p>Weak test coverage &amp; performance bottlenecks</p></li></ul><p>Write clean, secure, and performant code with <a href="https://coderabbit.link/petar">CodeRabbit</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://coderabbit.link/petar&quot;,&quot;text&quot;:&quot;Try CodeRabbit Now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://coderabbit.link/petar"><span>Try CodeRabbit Now</span></a></p><div><hr></div><h2>#1: Keep Your Functions Small And Focused</h2><p>Functions that do multiple things are hard to follow, understand, test, debug, and even reuse.</p><p>When something breaks, it&#8217;s very hard to pinpoint the exact part that failed.</p><p>When requirements change, and they do change regularly, you risk breaking the whole function and unrelated functionality.</p><p>In the <a href="https://www.goodreads.com/book/show/3735293-clean-code">Clean Code</a> book, Uncle Bob says:</p><blockquote><p><em>The first rule of functions is that they should be small.<br>The second rule of functions is that they should be smaller than that.</em></p></blockquote><p>So each function should have <strong>one clear responsibility</strong>.</p><p>Sometimes a function might be just 5 lines of code, while other times it might be 50 lines of code to fulfill a single responsibility.</p><p>If you can describe what your function does with &#8220;and&#8221;, it probably does too much.</p><p>There&#8217;s no universal rule to draw the line.</p><p>Trust your experience and your judgment based on the context you have.</p><blockquote><p><strong>Be pragmatic. Don&#8217;t be dogmatic.</strong></p></blockquote><div><hr></div><h2>#2: Name Functions to Reveal Intent</h2><p>Function names like <em>process()</em> or <em>handle()</em> force readers to examine the implementation to understand what the function does.</p><p>This slows down code reading and increases the cognitive load.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AyAv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AyAv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 424w, https://substackcdn.com/image/fetch/$s_!AyAv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 848w, https://substackcdn.com/image/fetch/$s_!AyAv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 1272w, https://substackcdn.com/image/fetch/$s_!AyAv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AyAv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png" width="428" height="305.7142857142857" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1040,&quot;width&quot;:1456,&quot;resizeWidth&quot;:428,&quot;bytes&quot;:181611,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.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_!AyAv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 424w, https://substackcdn.com/image/fetch/$s_!AyAv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 848w, https://substackcdn.com/image/fetch/$s_!AyAv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.png 1272w, https://substackcdn.com/image/fetch/$s_!AyAv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32e978c8-0bac-4cfe-8f1a-ad38278a276c_1780x1271.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>Function names should clearly state what they do with action verbs.</p><p>A good function name should answer:<br><em>&#8220;<strong>What action does this perform?</strong>&#8221;</em> and <em>&#8220;<strong>What does it return?</strong>&#8221;</em></p><p>You can also follow these tips:</p><ul><li><p><strong>Use terms and language based on the specific domain</strong>, so your functions are more tailored to the business context.</p></li><li><p>Follow the already established <strong>naming conventions.</strong></p></li><li><p><strong>Use verbs and verb phrases for actions</strong> (<em>calculate</em>, <em>validate</em>, <em>send</em>).</p></li><li><p>Use <strong>question words for boolean functions</strong> (<em>is</em>, <em>has</em>, <em>can</em>).</p></li><li><p><strong>Be consistent</strong> with the naming, so you don&#8217;t use two words for the same thing.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tw8z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tw8z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 424w, https://substackcdn.com/image/fetch/$s_!tw8z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 848w, https://substackcdn.com/image/fetch/$s_!tw8z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 1272w, https://substackcdn.com/image/fetch/$s_!tw8z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tw8z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png" width="613" height="342.2864010989011" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:813,&quot;width&quot;:1456,&quot;resizeWidth&quot;:613,&quot;bytes&quot;:283364,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.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_!tw8z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 424w, https://substackcdn.com/image/fetch/$s_!tw8z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 848w, https://substackcdn.com/image/fetch/$s_!tw8z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.png 1272w, https://substackcdn.com/image/fetch/$s_!tw8z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee6d5a86-6acf-4ecd-a061-b31b885b3f09_2426x1355.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><div><hr></div><h2>#3: Return Early to Avoid Nesting</h2><p>Deeply nested functions create a &#8220;pyramid of doom&#8221;, which is hard to follow, debug, and understand.</p><p>Your brain has to track multiple logical branches simultaneously.</p><p>The main business logic gets &#8220;hidden&#8221;, making it hard to find.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KDV6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KDV6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 424w, https://substackcdn.com/image/fetch/$s_!KDV6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 848w, https://substackcdn.com/image/fetch/$s_!KDV6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 1272w, https://substackcdn.com/image/fetch/$s_!KDV6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KDV6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png" width="480" height="337.9120879120879" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1025,&quot;width&quot;:1456,&quot;resizeWidth&quot;:480,&quot;bytes&quot;:248576,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.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_!KDV6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 424w, https://substackcdn.com/image/fetch/$s_!KDV6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 848w, https://substackcdn.com/image/fetch/$s_!KDV6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.png 1272w, https://substackcdn.com/image/fetch/$s_!KDV6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd29dc29-d07a-49cb-9b2d-61932abaf32f_2282x1607.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 fix this, you can use the early return principle.</p><p>You can handle edge cases and invalid inputs using guard clauses.</p><p>This removes the many levels of branches, keeping the &#8220;happy path&#8221; obvious, clear, and easy to follow.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4OZT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4OZT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 424w, https://substackcdn.com/image/fetch/$s_!4OZT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 848w, https://substackcdn.com/image/fetch/$s_!4OZT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 1272w, https://substackcdn.com/image/fetch/$s_!4OZT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4OZT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png" width="444" height="417.4697802197802" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1369,&quot;width&quot;:1456,&quot;resizeWidth&quot;:444,&quot;bytes&quot;:247953,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.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_!4OZT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 424w, https://substackcdn.com/image/fetch/$s_!4OZT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 848w, https://substackcdn.com/image/fetch/$s_!4OZT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.png 1272w, https://substackcdn.com/image/fetch/$s_!4OZT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F698cc6bd-dd6b-4650-9c43-51e7d5f8d2cb_2067x1943.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><div><hr></div><h2>#4: Limit Function Parameters</h2><p>Functions with many parameters are a cognitive load.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-U7F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-U7F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 424w, https://substackcdn.com/image/fetch/$s_!-U7F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 848w, https://substackcdn.com/image/fetch/$s_!-U7F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 1272w, https://substackcdn.com/image/fetch/$s_!-U7F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-U7F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png" width="204" height="273.9230769230769" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1187,&quot;width&quot;:884,&quot;resizeWidth&quot;:204,&quot;bytes&quot;:114609,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.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_!-U7F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 424w, https://substackcdn.com/image/fetch/$s_!-U7F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 848w, https://substackcdn.com/image/fetch/$s_!-U7F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.png 1272w, https://substackcdn.com/image/fetch/$s_!-U7F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F121dc9b4-127f-43ba-9390-f91ca5ebd457_884x1187.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>You can&#8217;t remember parameter order, and it&#8217;s easy to pass the wrong values.</p><p>To improve this, group related parameters into objects.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uBZZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uBZZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 424w, https://substackcdn.com/image/fetch/$s_!uBZZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 848w, https://substackcdn.com/image/fetch/$s_!uBZZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 1272w, https://substackcdn.com/image/fetch/$s_!uBZZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uBZZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png" width="385" height="292.9807692307692" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1108,&quot;width&quot;:1456,&quot;resizeWidth&quot;:385,&quot;bytes&quot;:176507,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.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_!uBZZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 424w, https://substackcdn.com/image/fetch/$s_!uBZZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 848w, https://substackcdn.com/image/fetch/$s_!uBZZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.png 1272w, https://substackcdn.com/image/fetch/$s_!uBZZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8bc463-5437-483b-ac6d-6b0b3e501e55_1780x1355.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>This reduces cognitive load and makes parameter order irrelevant.</p><div><hr></div><h2>#5: Write Pure Functions When Possible</h2><p>Functions with side effects are unpredictable.</p><p>They might work differently based on a global state, making them hard to test and debug.</p><p>You can&#8217;t reason about them in isolation.</p><p>They also cause mysterious bugs in unrelated parts of the system.</p><p>To mitigate this problem, strive to write functions that depend only on their inputs and produce no side effects.</p><p>Pure functions are predictable, testable, and can be safely called from anywhere.</p><p>And we can also run them in parallel.</p><div><hr></div><h2>#6: Avoid Boolean Parameters</h2><p>Boolean parameters make function calls unclear and hard to extend.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hoZl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hoZl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 424w, https://substackcdn.com/image/fetch/$s_!hoZl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 848w, https://substackcdn.com/image/fetch/$s_!hoZl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 1272w, https://substackcdn.com/image/fetch/$s_!hoZl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hoZl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png" width="480" height="262.0879120879121" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:795,&quot;width&quot;:1456,&quot;resizeWidth&quot;:480,&quot;bytes&quot;:218280,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.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_!hoZl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 424w, https://substackcdn.com/image/fetch/$s_!hoZl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 848w, https://substackcdn.com/image/fetch/$s_!hoZl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.png 1272w, https://substackcdn.com/image/fetch/$s_!hoZl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20bd4ca1-0cea-4ff7-9238-9a31627eb773_2175x1187.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>When you see <em>processOrder(order, true)</em>, you can&#8217;t tell what <em>true</em> means without checking the function definition.</p><p>Boolean flags also often indicate that a function is doing two different things.</p><p>A better approach is to use objects, enums, or separate functions instead of single boolean flags.</p><p>This makes your code self-documenting and easier to extend.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uQ2w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uQ2w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 424w, https://substackcdn.com/image/fetch/$s_!uQ2w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 848w, https://substackcdn.com/image/fetch/$s_!uQ2w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 1272w, https://substackcdn.com/image/fetch/$s_!uQ2w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uQ2w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png" width="542" height="346.93956043956047" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:932,&quot;width&quot;:1456,&quot;resizeWidth&quot;:542,&quot;bytes&quot;:361552,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.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_!uQ2w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 424w, https://substackcdn.com/image/fetch/$s_!uQ2w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 848w, https://substackcdn.com/image/fetch/$s_!uQ2w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.png 1272w, https://substackcdn.com/image/fetch/$s_!uQ2w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6df1a66-37d5-4309-b3a0-944a9c8b559e_2641x1691.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><div><hr></div><h2>#7: Return Results, Not Exceptions</h2><p>Using exceptions for expected failures makes error handling invisible and easy to forget.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Naxj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Naxj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 424w, https://substackcdn.com/image/fetch/$s_!Naxj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 848w, https://substackcdn.com/image/fetch/$s_!Naxj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 1272w, https://substackcdn.com/image/fetch/$s_!Naxj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Naxj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png" width="341" height="361.8440934065934" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1545,&quot;width&quot;:1456,&quot;resizeWidth&quot;:341,&quot;bytes&quot;:257827,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.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_!Naxj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 424w, https://substackcdn.com/image/fetch/$s_!Naxj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 848w, https://substackcdn.com/image/fetch/$s_!Naxj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.png 1272w, https://substackcdn.com/image/fetch/$s_!Naxj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31ec126f-2366-4531-8987-df7ca07b6d45_1673x1775.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>Callers don&#8217;t know what can go wrong just by looking at the function signature.</p><p>This leads to unhandled edge cases and application crashes.</p><p>To fix this, apply the Result Pattern and <strong>make errors part of your return type</strong>.</p><p>This forces callers to handle error cases and makes your <strong>function&#8217;s behaviour predictable and explicit</strong>.</p><p>A good rule of thumb is:</p><blockquote><p><strong>Use Result Pattern for expected errors to make them explicit.</strong></p><p><strong>Use Exceptions for unexpected errors and exceptional situations.</strong></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NvQu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NvQu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 424w, https://substackcdn.com/image/fetch/$s_!NvQu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 848w, https://substackcdn.com/image/fetch/$s_!NvQu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 1272w, https://substackcdn.com/image/fetch/$s_!NvQu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NvQu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png" width="510" height="602.8228021978022" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1721,&quot;width&quot;:1456,&quot;resizeWidth&quot;:510,&quot;bytes&quot;:501269,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.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_!NvQu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 424w, https://substackcdn.com/image/fetch/$s_!NvQu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 848w, https://substackcdn.com/image/fetch/$s_!NvQu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.png 1272w, https://substackcdn.com/image/fetch/$s_!NvQu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f445b2e-803d-4b48-b63f-45bfe8811a1d_2426x2867.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><div><hr></div><h2>#8: Replace Magic Numbers and Strings</h2><p>A common code smell is the use of magic numbers and strings.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Macx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Macx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 424w, https://substackcdn.com/image/fetch/$s_!Macx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 848w, https://substackcdn.com/image/fetch/$s_!Macx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 1272w, https://substackcdn.com/image/fetch/$s_!Macx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Macx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png" width="506" height="270.02884615384613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:777,&quot;width&quot;:1456,&quot;resizeWidth&quot;:506,&quot;bytes&quot;:158432,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.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_!Macx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 424w, https://substackcdn.com/image/fetch/$s_!Macx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 848w, https://substackcdn.com/image/fetch/$s_!Macx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.png 1272w, https://substackcdn.com/image/fetch/$s_!Macx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faae53f4c-219c-4d13-946f-f4db13e8d11c_2067x1103.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>These hardcoded values create a <strong>maintenance nightmare</strong>.</p><p>When business requirements and rules change, it&#8217;s very hard to find every occurrence of these numbers or strings.</p><p>Another big problem with these magic numbers and strings is the <strong>lack of meaning</strong>.</p><p>To fix this problem, extract the <strong>numbers into constants</strong> and the <strong>strings into enums</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_!K4VL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!K4VL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 424w, https://substackcdn.com/image/fetch/$s_!K4VL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 848w, https://substackcdn.com/image/fetch/$s_!K4VL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 1272w, https://substackcdn.com/image/fetch/$s_!K4VL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!K4VL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png" width="501" height="430.11675824175825" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1250,&quot;width&quot;:1456,&quot;resizeWidth&quot;:501,&quot;bytes&quot;:282861,&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://thetshaped.dev/i/171130447?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.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_!K4VL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 424w, https://substackcdn.com/image/fetch/$s_!K4VL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 848w, https://substackcdn.com/image/fetch/$s_!K4VL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.png 1272w, https://substackcdn.com/image/fetch/$s_!K4VL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fbc21e3-2821-4414-b954-7039a25e3a93_2067x1775.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><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://thetshaped.dev/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">Subscribe to get actionable JavaScript, React, Node, and Software Architecture tips straight into your inbox every week.</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>&#128204; TL;DR</h2><p>That&#8217;s all for today, 8 tips to write <strong>clean functions</strong>:</p><ul><li><p><a href="https://thetshaped.dev/i/171130447/keep-your-functions-small-and-focused">#1: Keep Your Functions Small And Focused</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/name-functions-to-reveal-intent">#2: Name Functions to Reveal Intent</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/return-early-to-avoid-nesting">#3: Return Early to Avoid Nesting</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/limit-function-parameters">#4: Limit Function Parameters</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/write-pure-functions-when-possible">#5: Write Pure Functions When Possible</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/avoid-boolean-parameters">#6: Avoid Boolean Parameters</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/return-results-not-exceptions">#7: Return Results, Not Exceptions</a></p></li><li><p><a href="https://thetshaped.dev/i/171130447/replace-magic-numbers-and-strings">#8: Replace Magic Numbers and Strings</a></p></li></ul><p>Hope this was helpful.</p><p>See you next week!</p><p><strong>Today&#8217;s action step:</strong> Take a look at your project and see if you&#8217;re making some of the mistakes I highlighted here. Try to fix them using the clean code tips I shared with you.</p><div><hr></div><h2><strong>&#128075; Let&#8217;s connect</strong></h2><p>You can find me on <strong><a href="https://www.linkedin.com/in/petarivanovv9/">LinkedIn</a></strong>, <strong><a href="https://x.com/petarivanovv9">Twitter(X)</a></strong>,<strong> <a href="https://bsky.app/profile/petarivanovv9.bsky.social">Bluesky</a></strong>, or <strong><a href="https://www.threads.net/@petarivanovv9">Threads</a></strong>.</p><p>I share daily practical tips to level up your skills and become a better engineer.</p><p><em>Thank you for being a great supporter, reader, and for your help in growing to 27.4K+ subscribers this week &#128591;</em></p>]]></content:encoded></item></channel></rss>