<?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 Growing Developer]]></title><description><![CDATA[Ideas and observations that will help you grow into a Senior Engineer and beyond. Written by a Staff Engineer at Meta (ex-Amazon, ex-Microsoft)]]></description><link>https://www.growingdev.net</link><image><url>https://substackcdn.com/image/fetch/$s_!LFcD!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5339e164-73b5-4cf8-b8de-60f98d904b29_320x320.png</url><title>The Growing Developer</title><link>https://www.growingdev.net</link></image><generator>Substack</generator><lastBuildDate>Wed, 29 Apr 2026 12:40:31 GMT</lastBuildDate><atom:link href="https://www.growingdev.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Pawel Kadluczka]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[growingdev@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[growingdev@substack.com]]></itunes:email><itunes:name><![CDATA[Pawel Kadluczka]]></itunes:name></itunes:owner><itunes:author><![CDATA[Pawel Kadluczka]]></itunes:author><googleplay:owner><![CDATA[growingdev@substack.com]]></googleplay:owner><googleplay:email><![CDATA[growingdev@substack.com]]></googleplay:email><googleplay:author><![CDATA[Pawel Kadluczka]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Building a Computer That’s Older Than the Internet]]></title><description><![CDATA[Tell me your age without telling me your age]]></description><link>https://www.growingdev.net/p/building-a-computer-thats-older-than</link><guid isPermaLink="false">https://www.growingdev.net/p/building-a-computer-thats-older-than</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Mon, 05 Jan 2026 02:42:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!zMy7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Monty Python is awesome. But there is one thing the Brits gave to the world that is even better: the ZX Spectrum.</p><p>Introduced in 1982, the ZX Spectrum was a computer that sparked the home computer revolution in Britain and, due to its affordability, in many other European countries. The basic version had 16 KB of RAM, while the enhanced version boasted an immense 48 KB.</p><p>Though I&#8217;ve never owned a ZX Spectrum, it is close to my heart. It was the first computer I had a chance to <em>work</em> with. The computer club I was going to as a kid had a dozen of these computers, and we couldn&#8217;t wait for the teacher to finally stop talking and let us play some games.</p><p>Fast forward 40 years, and while browsing eBay, a brand-new replacement case for a ZX Spectrum showed up in my search results. The memories came back, and I impulse-bought it immediately. I didn&#8217;t have any plan for it, but once I got it, I knew I had to put it to good use, i.e., build a ZX Spectrum replica.</p><h2>Getting started</h2><p>A nice case is a good start, but what goes inside is key. I found a few interesting options, but the <a href="https://www.bytedelight.com/?product_cat=harlequin128">Harlequin 128K Kit</a> from ByteDelight was by far the best. This kit contained everything I needed to build a fully functional ZX Spectrum.</p><p>When I received my Harlequin 128K Kit, I felt overwhelmed. While the ZX Spectrum had only a handful of chips (not counting RAM), this kit had more than 50. There is a good reason for this - the kit uses widely available, off-the-shelf chips to emulate the ZX Spectrum&#8217;s <a href="https://en.wikipedia.org/wiki/Gate_array">ULA</a> (Uncommitted Logic Array) specialized chip that went out of production almost 40 years ago.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zMy7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zMy7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!zMy7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!zMy7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!zMy7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zMy7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2594165,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.growingdev.net/i/183507281?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zMy7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!zMy7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!zMy7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!zMy7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40be80f0-c348-4df3-94d7-5398e60c0462_4032x3024.heic 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>I had never done much soldering, and the 50+ chips alone meant hundreds of solder joints. But there were also resistors, diodes, transistors, etc. The website promised it would be a <em>fun challenge</em> and that <em>basic skills and creativity</em> were enough to pull it off. These were encouraging words, but what the website didn&#8217;t mention was that a single mistake would ruin it all.</p><p>To make the assembly process easier, the kit parts were divided into 40 or so clearly labeled bags and provided with the recommended installation order. The detailed assembly guide included additional hints and called out easy-to-miss gotchas. Given my skill level, I found the kit&#8217;s organization extremely helpful.</p><h2>First Try</h2><p>The instructions said the soldering would take a few hours. Indeed, I spent a few hours a day for a week building the board. I followed the assembly steps very closely because I knew troubleshooting any non-obvious issues would be beyond my abilities. Eventually, I emerged from my garage with the board, anxious to try it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3Oh7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3Oh7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!3Oh7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!3Oh7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!3Oh7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3Oh7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1993008,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.growingdev.net/i/183507281?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3Oh7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!3Oh7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!3Oh7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!3Oh7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb3143f5-e0ca-4927-a5ad-4934b377ba89_4032x3024.heic 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>I connected it, and what I saw made my heart sink.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XJkv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XJkv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 424w, https://substackcdn.com/image/fetch/$s_!XJkv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 848w, https://substackcdn.com/image/fetch/$s_!XJkv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 1272w, https://substackcdn.com/image/fetch/$s_!XJkv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XJkv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/70b719af-053a-4d49-a989-deb9f1c9857c.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5033890,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.growingdev.net/i/183507281?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XJkv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 424w, https://substackcdn.com/image/fetch/$s_!XJkv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 848w, https://substackcdn.com/image/fetch/$s_!XJkv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 1272w, https://substackcdn.com/image/fetch/$s_!XJkv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70b719af-053a-4d49-a989-deb9f1c9857c.heic 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>If the board had been completely dead, I might have hoped I had missed a connection, but what I saw indicated a subtle issue I doubted I could fix. A quick Internet search only confirmed my suspicion. A few people reported similar symptoms, but no one could propose a reliable fix.</p><p>I verified that all the chips were inserted correctly and pressed them down firmly to ensure good contact. I inspected my soldering but didn&#8217;t find any missed solder joints. I double-checked the jumpers and found that a couple of them controlling the video settings were misconfigured. I corrected them, but nothing changed. Frustrated, I gave up.</p><h2>Round 2</h2><p>The problem haunted me. A week later, I went over everything again and confirmed I hadn&#8217;t missed anything. As I was out of ideas, I started playing with jumpers for ROM selection. To my astonishment, one of my changes produced this screen:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tHY6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tHY6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 424w, https://substackcdn.com/image/fetch/$s_!tHY6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 848w, https://substackcdn.com/image/fetch/$s_!tHY6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 1272w, https://substackcdn.com/image/fetch/$s_!tHY6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tHY6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d9b60154-017b-4255-b3c3-dfc906e0b088.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5047797,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.growingdev.net/i/183507281?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tHY6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 424w, https://substackcdn.com/image/fetch/$s_!tHY6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 848w, https://substackcdn.com/image/fetch/$s_!tHY6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 1272w, https://substackcdn.com/image/fetch/$s_!tHY6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b60154-017b-4255-b3c3-dfc906e0b088.heic 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 meant the board had been working fine all along! It was just trying to run some garbage instead of a valid ROM program.</p><h2>ROM</h2><p>I turned to the guide to understand what was happening. Due to copyright, the kit doesn&#8217;t ship with the original ZX Spectrum ROM. Instead, it comes with the AM29F040B EEPROM, which is big enough to hold up to 8 different ROM images. The board uses jumpers to select the image to run. Apparently, some of the banks in my EEPROM didn&#8217;t have a valid ROM image, and my initial configuration happened to point to one of these banks.</p><p>Now that I understood the issue, the fix was easy: I needed to burn the ZX Spectrum ROM into my EEPROM. The only problem was that I didn&#8217;t have an EEPROM programmer. After some research, I settled on the XGecu T48 EEPROM programmer. When I got it, I was unpleasantly surprised: the official software only supported Windows, but I am a Mac user.</p><p>I sacrificed a lot for this project, but having to install Parallels would be too much. Fortunately, I found an open-source command-line tool called minipro that offered what I needed.</p><p>The Harlequin 128K board I built was compatible with both ZX Spectrum and ZX Spectrum 128. Because my EEPROM could hold multiple ROM images, I burned them both so I could easily switch between them.</p><h2>Visual Minipro</h2><p>While the <code>minipro</code> tool did the job, setting it up and understanding the options took some effort. A UI version of the tool would make everything so much easier. As nothing like this existed, I decided <a href="https://visualminipro.com/">to build it myself</a>. Because my tool is a <code>minipro</code> GUI wrapper, I called it Visual Minipro and made it available on <a href="https://apps.apple.com/us/app/visual-minipro/id6747261192">the Mac App Store</a>.</p><h2>Finishing the build</h2><p>I was delighted to see my board up and running, but two problems bothered me: the video quality was pretty bad, and I couldn&#8217;t use a joystick.</p><h3>Video</h3><p>The Harlequin 128K board offers two video outputs: composite and RGB. The RGB signal is intended for use with SCART, which has never been a thing in the US. Since none of my monitors supported SCART, composite video felt like a better choice. Besides, exposing the RGB socket would require cutting a hole in my case, which I didn&#8217;t want to do.</p><p>To get NTSC timings over composite video, I installed the NTSC crystal that came with the kit. It did the trick, but the result wasn&#8217;t great. The picture on my <a href="https://de.wikipedia.org/wiki/Commodore_1084/1084S">1084S</a> monitor was blurry, and when I tried to convert it to HDMI using my <a href="https://www.retrotink.com/shop/retrotink-2x-pro">Retrotink 2X Pro</a> converter, I got no color.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JrFK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JrFK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!JrFK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!JrFK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!JrFK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JrFK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3256565,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.growingdev.net/i/183507281?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JrFK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!JrFK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!JrFK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!JrFK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1280bfc-2f14-4d54-a303-df5de8862148_4032x3024.heic 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>Joystick</h3><p>In the 8-bit era, a joystick was a must-have device. Most games couldn&#8217;t even be played without a joystick. While the ZX Spectrum didn&#8217;t support a joystick out of the box, third-party joystick interfaces quickly filled the gap. The most popular one was the <a href="https://en.wikipedia.org/wiki/Kempston_Micro_Electronics">Kempston joystick interface.</a></p><p>The Harlequin 128K board has built-in support for the Kempston joystick interface. This is nice, but there are two problems: the ZX Spectrum case lacks a factory-made hole for a joystick port, and the board lacks mounting points for the DB9 joystick socket. So, even if I had modified the case, that case might not have been strong enough to provide solid support for the joystick port. Besides, I knew the DIY joystick hole would look ugly. So, I decided to look for something different.</p><h3>ZX VGA Joy to the rescue</h3><p>One popular way to get HDMI output on the ZX Spectrum is <a href="https://www.bytedelight.com/?page_id=1800">ZX-HD,</a> an HDMI interface for the ZX Spectrum. It is a fine device, but it wouldn&#8217;t solve my joystick problem. So, I kept looking for alternatives and found something that fit my needs perfectly: <a href="http://zx-vga-joy.com/">ZX VGA Joy</a>. This device could output digital video over HDMI and provided a joystick port compatible with the Kempston interface. As a bonus, it also had the reset button.</p><p>I ordered it, and couldn&#8217;t wait to try it. When it finally arrived, I wasn&#8217;t able to make it work with my setup reliably - the screen would go black soon after turning the Spectrum on. Quick debugging proved this was an issue with the computer - the composite video worked just fine. After reading more about the inner workings of ZX VGA Joy, I got a hunch about what was happening. ZX VGA Joy relies on PAL timings to generate the HDMI output. But my computer had the NTSC crystal installed. My hypothesis was that this difference was responsible for the glitch because the PAL and NTSC frequencies differ.</p><p>My guess was correct. Replacing the NTSC crystal with a PAL crystal indeed fixed the blank-screen problem, but it came at a cost. After installing the PAL crystal, I lost the ability to use the composite video. This wasn&#8217;t a big deal, though. Given the low quality of the composite signal, I wouldn&#8217;t want to use it anyway.</p><h2>Final result</h2><p>Here is the final result after putting everything together (with a modded Nintendo NES controller in lieu of a joystick and the original SimCity game humming happily on 48 KB of RAM).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3_fe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3_fe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!3_fe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!3_fe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!3_fe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3_fe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1570618,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.growingdev.net/i/183507281?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3_fe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!3_fe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!3_fe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!3_fe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180cb7b5-9743-46ac-96ea-7d14b58ff933_4032x3024.heic 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><h1>Conclusion</h1><p>There is no practical reason to build a 40-plus-year-old computer today. To be honest, even when I was starting, I didn&#8217;t expect to really use it. However, the process of building it, the interesting technical challenges, and the satisfaction of seeing it come to life were all well worth it.</p>]]></content:encoded></item><item><title><![CDATA[The Growing Dev turns one]]></title><description><![CDATA[One year ago, I embarked on a journey to improve my writing.]]></description><link>https://www.growingdev.net/p/the-growing-dev-turns-one</link><guid isPermaLink="false">https://www.growingdev.net/p/the-growing-dev-turns-one</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Sat, 30 Nov 2024 02:37:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f9691037-4256-4b3e-8007-6d4003804157_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One year ago, I embarked on a journey to improve my writing. I did it because I believe that writing is not only an <a href="https://www.growingdev.net/p/the-must-have-skill-every-senior">essential skill for software developers</a> but also a <a href="https://www.growingdev.net/p/the-three-categories-of-skills-everyhttps://www.growingdev.net/p/the-three-categories-of-skills-every">universal life skill</a>.</p><p>To make sure I am making steady progress, I challenged myself to write one piece each week. I decided to write in public to guarantee the quality of my posts. My reasoning was simple: publishing something subpar because I didn't put the honest effort into it would feel very uncomfortable, and I wouldn't do it.</p><p>Choosing a newsletter as my medium was an easy decision. With 25 years of experience as a Software Engineer, I have plenty to share. Additionally, a newsletter was the ideal format for maintaining quality and consistency.</p><p>Today, I am thrilled to report that I successfully completed my challenge. I published <a href="https://www.growingdev.net/p/how-to-remove-unnecessary-friction">my first post</a> on 11/29/2023 - exactly a year ago, and I wrote a new post every week after that.</p><h2>What I learned</h2><p>My journey taught me a few important lessons about writing. Here they are:</p><h3>Writing takes a lot of time</h3><p>I knew that writing was time-consuming as I had written tens of posts on my personal blog before. The big difference was that before, I could spend weeks on a single post, but now I was on a schedule. I had about a week to write and publish a post. I found this surprisingly challenging. Initially, I could barely keep up with my plan despite spending most of my weekends writing.</p><h3>Writing consistently is hard</h3><p>Consistently doing anything that demands a significant amount of time is difficult. Writing is no different. It is so easy to justify giving up when a family or a job emergency happens (that tree that fell on our house was no fun, and the clean-up took weeks). It is so tempting to take a week or two off for a family vacation. But I knew that skipping once would only make it easier to skip again.</p><h3>The English language</h3><p>In the past year, thanks to intentional practice, I learned more about written English than I had since I moved to the United States in 2006. My two main resources were books (including "On Writing Well" by William Zinser and "The Elements of Style" by William Strunk Jr. and E.B. White) and Grammarly. (Grammarly proved especially helpful in identifying mistakes I didn't realize I was making consistently.) I also used Chat GPT a bit. It was useful in some aspects, like finding synonyms and generating images, but I wouldn't say I liked the content it produced. It was either very pompous or too vulgar. And it just didn't sound close to how I write.</p><h2>The results</h2><p>Here are the results my practice yielded:</p><ul><li><p>writing a post takes me now half the time it took when I started</p></li><li><p>newer posts read easier than the first ones I published</p></li><li><p>my writing at work became more concise and better tailored for the audience</p></li></ul><p>I also have a library of posts to which I can point my mentees and team members.</p><h2>What's next?</h2><p>Even though I completed my writing challenge, it doesn't mean my writing couldn't improve further. However, going forward, I am going to make it less intense.</p><p>The weekly writing cadence left me little free time to do other things. I have a few topics I have wanted to research for a long time but couldn't put enough continuous effort into making solid progress. I also want to spend more time on some of the hobbies I neglected in the past 12 months. To make room for this, I decided to publish my newsletter less frequently. Furthermore, some upcoming posts might relate to my research topics instead of the Software Engineering career development advice I have been focusing on until now. I hope they will still interest you despite being different. Thank you in advance for your readership.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p><p></p>]]></content:encoded></item><item><title><![CDATA[Using mental models to think about software]]></title><description><![CDATA[All models are wrong, but some are useful.]]></description><link>https://www.growingdev.net/p/using-mental-models-to-think-about</link><guid isPermaLink="false">https://www.growingdev.net/p/using-mental-models-to-think-about</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 22 Nov 2024 07:26:42 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/59d3605b-4577-4d0a-8af2-85c5beeeedc9_390x255.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>No person can function properly without building mental models to understand the world around them. The reality is simply too complex to deal with as is, so we need to abstract it.</p><p>Software is no different. The complexity of software systems has been only growing. As a result, the ability to quickly build mental models and use them to reason about these systems is an important software engineering skill.</p><p>Building good mental models is important because they allow us to better communicate with other software engineers, explain our ideas, and understand the impact of our changes on our software.</p><h2>Building mental models</h2><p>Reasoning about software systems requires building mental models that represent them. The granularity of these models depends on their purpose. Often, one level of granularity is not sufficient. The most effective software engineers can quickly build a few models and switch between them depending on the situation.</p><p>For example, if your team owns a few services, you can draw a lines-and-boxes diagram where boxes represent services and lines represent dependencies. You can then zoom in and build a model for each service. These service-level models could illustrate interactions between the libraries a service consists of. If you want more details, you can create a class diagram. You can continue zooming in and focus on methods, code blocks, statements, etc.</p><p>Each of these models describes your system at a different level of granularity and has a unique set of applications. The high-level model could be useful to troubleshoot larger outages (or when talking with your director) but is unlikely to help you fix a small bug. The more detailed models are best suited for solving gnarly issues but won't be helpful when explaining your infrastructure to other teams.</p><p>Building models covering different aspects of the same system is also common. If you want to analyze your system from the security perspective, your model will include different details than when focusing on performance.</p><h2>Caveats</h2><p>Mental models are so natural to people that we often forget about their flaws.</p><h3>All models are wrong</h3><p>Models, by definition, ignore details. As they only capture certain aspects of reality, they are inaccurate. Furthermore, some relevant information is often omitted because it doesn't <strong>fit the model</strong>. Edge cases are an excellent example.</p><p>For instance, when software developers explain how their code works, they rarely mention error cases. They focus on their <em>if</em>s and <em>for</em>s and the program flow but omit exceptions because exceptions make their model murkier. The problem is that error scenarios are important. Incorrect or missing error handling is a common cause of system outages.</p><h3>Models get more wrong with time</h3><p>The world, including our software systems, is in constant flux. But mental models don't automatically keep up with changing reality. Outdated mental models lead to misunderstandings and bad decisions.</p><p>I experienced this very problem recently. I started working on a feature that depended on a system I had never seen changing. Everything was going swimmingly, and I only needed to tie up a few loose ends related to some new data requirements. But when doing this, I discovered, to my dismay, that the system I depended on had recently changed. It had been updated to accommodate the same data requirements I struggled with. Making my feature work now required additional information I didn't have. Plumbing this data meant revisiting my implementation. Working off of an outdated mental model cost me implementing my feature twice.</p><h3>No two models are identical</h3><p>Building mental models requires deciding which details are important depending on the purpose of the model. However, even if the purpose of the model is well understood, different people will consider different information relevant.</p><p>Also, mental models built at different times will naturally differ because they capture different system versions.</p><p>The interesting fact about this phenomenon is that the overlap between mental models built by different people is usually significant. The differences are often discovered unexpectedly, e.g., when discussing small but important details.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[Overthinking Software Projects]]></title><description><![CDATA[&#8220;Weeks of coding can save you hours of planning.&#8221;]]></description><link>https://www.growingdev.net/p/overthinking-software-projects</link><guid isPermaLink="false">https://www.growingdev.net/p/overthinking-software-projects</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 15 Nov 2024 06:55:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iftJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em><strong>&#8220;Weeks of coding can save you hours of planning.&#8221; </strong></em></p><p>Most developers learn this truth the hard way. I did when I implemented a feature based on incorrect assumptions, and the only way to save it was to rewrite it.</p><p>While junior engineers often fall into the trap of jumping straight to coding without thinking about the problem, more senior engineers fall into a different trap: <strong>overthinking</strong>.</p><p>Senior developers are routinely responsible for projects requiring a handful of engineers and a few months to complete. There is no way to execute these projects without careful thinking and planning. Even if you wanted to start coding on the first day, you couldn't. You simply wouldn't know where to start.</p><p>The top priority in the initial phases of bigger software projects is to sort out the ambiguity that blocks development. The most common way to do this is to devise a design that will guide the implementation.</p><p>The tricky part is that figuring out the design is by itself an ambiguous problem. There is usually more than one way to implement the solution, and many constraints and requirements are unclear. Even estimating how long it will take to prepare the design can be difficult.</p><p>All these uncertainties put pressure on the engineer(s) responsible for the project. Making a bad decision can lead to wasted time (amplified by the size of the team) or even a project failure.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iftJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iftJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!iftJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!iftJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!iftJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iftJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97039,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iftJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!iftJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!iftJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!iftJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a16798-3eae-43c8-a4dd-c0fbfb7431b3_1024x1024.jpeg 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><figcaption class="image-caption">The &#8220;Am I Overthinking This?&#8221; book cover</figcaption></figure></div><p>When stakes are high, it is natural to proceed carefully, explore potential problems, and work with others to identify gaps that may otherwise go unnoticed. However, setting limits for these activities is crucial. Failing to do so will inevitably lead to overthinking, which can also put the project at risk due to:</p><ul><li><p>Delays - analyzing every imaginable scenario takes a long time and will eat into development time, making meeting expected timelines impossible.</p></li><li><p>Overengineering - trying to address minor or hypothetical issues leads to overly complex designs that are hard to implement and expensive to maintain.</p></li><li><p>Missed opportunity - endless discussions, revisions, and feedback rounds steal time engineers could spend on other project activities or elsewhere.</p></li></ul><h2>How do you know if you are overthinking?</h2><p>One of the problems with overthinking is that the line between productive analysis and overthinking is thin, and it is easy to miss this line. However, there are signs of getting there:</p><ul><li><p>Although all critical requirements have been satisfied, new requirements are being added.</p></li><li><p>The same topics continue to be discussed repeatedly without reaching any resolution.</p></li><li><p>Edge cases, minor issues, and esoteric scenarios start to dominate the discussion.</p></li><li><p>The debate moves to <a href="https://www.growingdev.net/p/future-proof-code">future scenarios</a> that are out of the scope of the project at hand.</p></li></ul><h2>What to deal with overthinking?</h2><p>It is important to understand that the goal of the planning and design phases is not to identify and solve all possible problems. First, it is impossible even to list all the issues. No matter how much time you spend thinking you will miss something. Second, many problems will never materialize, or if they do, their impact will be minimal. To focus on what's important, create a list of requirements, decide which are critical (the list should be short), and satisfy those. Leave out the remaining ones and revisit them if they become a major problem.</p><p>Many problems have no one correct or even best solution. No amount of debate is going to change that. It may take time to arrive at this conclusion, but once it is settled, you must pick one of the alternatives and live with the consequences.</p><p>If you are not sure, prototype. An hour of coding can save you a few hours of meetings. <a href="https://www.growingdev.net/p/rfc-pull-requests-because-code-wins">Code does win arguments</a>.</p><p>Design for your current needs. If you don't operate at Facebook's scale, don't design for Facebook's scale. Don't build abstractions for your <a href="https://www.growingdev.net/p/future-proof-code">hypothetical future scenarios</a>.</p><p>Accept the fact that things may not work out. Fortunately, you are not pouring concrete. This is software, and the ability to modify it is one of its greatest advantages. You can build small and evolve your solution when your needs grow.</p><p>Build vertically. A small feature working end-to-end will allow you to discover issues early and course-correct. If you build horizontally, you won't see gaps until very late when all the layers are ready. Fixing bigger problems at this stage will be an undertaking.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[How to quickly ramp up on new codebases]]></title><description><![CDATA[Joining a new team is intimidating.]]></description><link>https://www.growingdev.net/p/how-to-quickly-ramp-up-on-new-codebases</link><guid isPermaLink="false">https://www.growingdev.net/p/how-to-quickly-ramp-up-on-new-codebases</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 08 Nov 2024 06:41:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c12fa055-b02f-4256-9c83-7205c24d79be_494x352.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Joining a new team is intimidating. There is always much to learn - new people, new processes, and a new code base.</p><p>Ramping up on your new team&#8217;s code base is difficult, but knowing how to work effectively in it is crucial to your success. So, how do you do it quickly?</p><p>My mid- and early senior developer years were intense. Due to a mix of reorgs and personal interests, I found myself on a new team every year or so. As a result, I had to learn new codebases in quick succession. They included .NET System.Xml, OData, Entity Framework, Entity Framework Designer, <a href="http://asp.net/">ASP.Ne</a>t SignalR, <a href="http://asp.net/">ASP.Net</a> Core, and the Alexa mobile app, and most of them were over one hundred thousand lines.</p><p>The first couple of transitions were slow and overwhelming. But they helped me develop a strategy I used later to quickly get up to speed on new codebases.</p><h2>Get your hands dirty ASAP</h2><p>The sooner you start working actively with the code base, the sooner you will get productive. Reading documentation can be helpful, but nothing can replace the hands-on experience.</p><p>When I joined Amazon, I asked my manager to assign me a simple bug to fix on my first day. Even though the fix amounted to a single line of code, it took me a few days to send it for review. It might seem long, but this quest was not about fixing the bug. Rather, it was about forcing myself to set up my development environment, learn how to build and run the code, write unit tests, and debug our product.</p><h2>Review code</h2><p>Each team has its way of letting members know there is a new PR (Pull Request) for review. It could be email, chat, or review tool notifications. Whatever it is, subscribe to this channel and start reviewing PRs. You won&#8217;t understand much initially, but you may still catch some bugs (e.g., off-by-one errors). More importantly, these reviews will allow you to <a href="https://www.growingdev.net/i/149472792/understand-the-code-and-ask-questions-when-in-doubt">ask questions</a> and gather a broader context of what the team is working on.</p><h2>Identify code that matters</h2><p>The 80/20 rule does apply to codebases. This is especially noticeable in the bigger ones, where most code changes developers make are concentrated in one area. Knowing which code it is allows you to focus your ramp-up on the area you are likely to work on soon.</p><p>There are a couple of easy ways to tell which code is in the top 20%:</p><ul><li><p>paying attention to code reviews</p></li><li><p>checking the commit history</p></li></ul><h2>Take notes, draw diagrams</h2><p>I discovered that taking notes and drawing diagrams is a very effective way to grok the most complex parts of the code. Call graphs, class diagrams, and dependency graphs all help organize the information and are great reference material in case you need to refresh your memory.</p><p>After I joined Amazon, I drew diagrams of a few areas of code I couldn&#8217;t understand. They became an instant hit. Even people who had been on the team for much longer than me wanted a copy.</p><h2>Debug code</h2><p>Reading a new codebase is like reading a book in a language you barely know. You can do it, but it is excruciating.</p><p>For me, one of the best ways to overcome this is to step through the code with the debugger. Initially, I have no idea what I am looking at. But if I follow the same code path a few times, I begin to recognize code I have already seen, and soon, everything starts to fall into place.</p><p>To get the most out of my debugging sessions, I do two things:</p><ul><li><p>I continuously inspect the state - the stack trace, parameters, and local and class variables</p></li><li><p>I take notes and draw diagrams</p></li></ul><p>Using the debugger to learn the code base is slower and narrower than reading the code. But it is also much deeper. In fact, when debugging, I often realize that the understanding I gained from reading the code was incomplete or sometimes even incorrect.</p><h2>Read documentation</h2><p>Reading documentation can help accelerate your onboarding. It could be especially useful when it comes to the high-level architecture and concepts that are hard to deduce from code.</p><p>However, you should take documentation with a grain of salt. It is often sparse and outdated. But this could be good news for you. Updating the documentation as part of your ramp-up could be a great contribution to your new team.</p><h2>Join on-call rotation</h2><p>Joining the on-call rotation to accelerate team onboarding might sound extreme but I did it on my first team at Facebook. I did it because I was concerned that my ramp-up was slow, so I decided to push myself. I learned more about our services this week than in weeks before. After my shift ended, I knew what services our team owned, their dependencies and where to find their code. Alerts immediately pointed me to the hot code paths, and troubleshooting issues forced me to dig into the code.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[The Must-Have Skill Every Senior Developer Needs]]></title><description><![CDATA[What got you here won't get you there]]></description><link>https://www.growingdev.net/p/the-must-have-skill-every-senior</link><guid isPermaLink="false">https://www.growingdev.net/p/the-must-have-skill-every-senior</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 01 Nov 2024 06:36:02 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/98cabeb3-5e3f-4d88-b79d-9663db766ea9_500x500.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Writing code is a fundamental skill every junior software developer needs to master. However, coding skills are no longer the biggest differentiator at senior and above levels. Every senior engineer is expected to have solid coding skills, and growing to higher levels based on coding alone is rare.</p><h2>If not coding, then what?</h2><p>If coding is not the skill to grow beyond senior levels, what skill is it?</p><p>This question has no correct answer, as no single skill can elevate you to the staff+ levels.</p><p>However, software development is a team sport, and successful senior engineers must focus on many areas besides coding. They are often responsible for projects spanning one or more teams. They drive the design, collaborate with partner teams, communicate progress, etc. Doing all this work effectively requires good communication skills, especially writing (which I consider one of the <a href="https://www.growingdev.net/i/149793781/universal-skills">Universal Skills</a>.)</p><h2>Why writing?</h2><p>Writing clarifies thinking and promotes the exploration of ideas. I don't know how many times I thought I understood something, only to struggle to summarize it in writing. But once I succeeded, I had a much deeper grasp of the concept and noticed new insights I hadn't considered before.</p><p>Thanks to its durability and asynchronous nature, writing is also a great way to scale. You can write something once and refer to it later. Your readers can benefit from it even if you are not around. Here are a few examples from the software engineering field:</p><ul><li><p>Project execution plans are useful for aligning all interested parties: the team that will execute the project, partner teams, your manager, etc., without having to talk to them individually.</p></li><li><p>Documentation helps avoid explaining the same concepts again and again. It protects the team from scrambling when a key team member leaves the project or the team (see also: <a href="https://en.wikipedia.org/wiki/Bus_factor">bus factor</a>)</p></li><li><p>Design documents allow for gathering feedback without holding a meeting for all interested parties. They are also an invaluable resource to understand why certain design choices were made and what alternatives were considered.</p></li></ul><h2>Writing is difficult</h2><p>Writing is not natural for most people. Making the content clear, concise, and well-organized is grueling work.</p><p>I often see software developers dismay when I ask them to write a rollout plan or a design doc. Some tell me they were relieved to graduate from college because it meant they would never have to write again, and I am shuttering their world.</p><p>There are also other reasons why writing is difficult. Many developers have to write in a non-native language. But even native speakers often struggle because the way of writing they learned at school does not serve them at work.</p><h2>Opportunities to practice writing</h2><p>Even though writing becomes important gradually, it doesn't mean you should wait to improve it. On the contrary, the sooner you start, the better. Fortunately, every developer has plenty of opportunities to practice writing on the job.</p><h3>Emails</h3><p>Emails are everyone's bread and butter these days. However, many emails are hard to read and understand and, as a result, fail to achieve their goal.</p><p>In my first job, our manager asked us to send a weekly email summarizing what we worked on and accomplished in the past week. I was proud of my reports: they were very detailed and explained everything. Despite these emails, my manager kept asking me what I had been working on. When I saw one of these emails years later, I understood. He never read them. I couldn't blame him - it was an unbearable wall of text.</p><h3>Memos / Announcements</h3><p>Posts, memos, and announcements meant for a wide audience need to be tailored to that audience. Otherwise, readers won't understand them and will give up reading them.</p><p>I recently read a post from my co-worker reporting on the status of our project. The audience of this post was broad (more than 150 people) and included managers, directors, and partner teams. The technical details in this post left me lost despite my heavy involvement in this project. I can only guess what others took away from this post.</p><h3>Design documents</h3><p>Good design documents explain complex topics using simple language. This combination makes them hard to write, but the payoff is worth the effort. Confusing design documents lead to lengthy discussions, feedback on unimportant matters, and frustration.</p><p>I once asked a junior engineer to write a design document explaining how he plans to implement a feature we promised to deliver. What I got was an untitled Google Doc with no text and two pictures - a diagram and "<a href="https://en.wikipedia.org/wiki/The_Starry_Night">The Starry Night</a>" by van Gogh. While I have nothing against "The Starry Night", the document didn't give me the faintest idea about the design of the feature, assumptions, and considered alternatives.</p><h3>Code review feedback</h3><p>The main purpose of sending code for review is to gather feedback. But giving <a href="https://www.growingdev.net/p/top-5-blunders-made-by-code-reviewers?open=false#%C2%A7unclear-or-unactionable-feedback">short, clear, and actionable feedback</a> professionally is an art. The conclusion: if you want to improve your writing, you should review a lot of code (and provide feedback).</p><h3>Code comments</h3><p>I am not a huge fan of <a href="https://www.growingdev.net/p/how-not-to-ruin-your-code-with-comments">writing code comments</a>, but in some situations, they are warranted. Unfortunately, many code comments are so poorly written that it is sometimes hard to tell if they are there to help you or make you more confused.</p><p>The main challenge with code comments is that they need to be short to not overshadow the code but must clearly explain intricate ideas that the code cannot express. These requirements make writing code comments good practice.</p><h3>Documentation</h3><p>Writing documentation is one of the least favorite tasks software developers want to do. Yet, it often is one of the most impactful they can do. Good documentation helps put out on-call fires faster, makes onboarding new team members easier, and reduces randomization caused by repeatedly answering the same questions. By writing documentation, you help your team achieve more and polish your writing skills.</p><h3>Bug reports</h3><p>If you want someone to do something for you, you need to make it as easy as possible for them to do it. If you don't, what you are asking for will take a long time or will never get done.</p><p>This rule applies perfectly to bug reports. If you encounter a bug that blocks your work, writing a clear bug report dramatically increases the chances of getting the issue fixed. Despite this, many reported bugs are incomprehensible.</p><p>At Microsoft, I worked on a few high-profile open-source projects like Entity Framework or <a href="http://asp.net/">ASP.Net</a> Core. As thousands of developers used our products, we received a decent number of bug reports. Unfortunately, we often couldn't understand what issue was being reported, how to reproduce it, and the expected behavior. Following up on these issues was painful. The back-and-forth took weeks. The "bugs" slipped from release to release while we were waiting for the details we requested. Eventually, we closed most of these bugs without resolution as it was hard to prioritize them over other issues we could immediately investigate and fix.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[Understand the purpose of your work]]></title><description><![CDATA[One mistake I've seen junior software engineers repeat again and again is their lack of understanding of why they work on tasks they work on.]]></description><link>https://www.growingdev.net/p/understand-the-purpose-of-your-work</link><guid isPermaLink="false">https://www.growingdev.net/p/understand-the-purpose-of-your-work</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 25 Oct 2024 06:32:14 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/17b61ece-7cc5-4c3e-9006-268db8510394_600x529.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One mistake I've seen junior software engineers repeat again and again is their lack of understanding of <strong>why</strong> they work on tasks they work on. This confusion can be somewhat justified by the relatively small scope junior engineers typically have but it's a slippery slope. Doing something only "because my manager (or a senior engineer) asked me to do it" has a few drawbacks:</p><ul><li><p><strong>Inability to execute independently</strong>: making even the smallest decision without involving your manager or the tech lead will be hard if you don't understand the bigger picture. You will get stuck if you can't get hold of them. It will also be difficult for you to demonstrate you know how to solve problems at your level and are ready for bigger challenges.</p></li><li><p><strong>Communication gap:</strong> your manager or senior engineer may unintentionally give you incomplete or incorrect information. If you don't have enough context, it will be hard to notice this. You will struggle to complete the task, but once you finally do, it may turn out that what you built is not what they hoped for and needs to be redone.</p></li><li><p><strong>Hindered innovation:</strong> unawareness of where your work fits limits your ability to propose solutions beyond what you're asked to do. Sometimes, the approach you're instructed to follow may not be the best solution to the problem, but exploring alternatives is impossible if you don't understand the broader context.</p></li><li><p><strong>Incorrect prioritization:</strong> working on a task without knowing its purpose may lead to neglecting this task and unknowingly delaying work that depends on it.</p></li></ul><h2>How to understand the bigger picture?</h2><p>The easiest way to understand where your work fits is to ask your manager or the tech lead. They are responsible for what the team needs to deliver, so they should be able to explain this instantly.</p><p>Your question may, however, come to them as a surprise. They probably assume everyone on the team already understands the purpose of their work. In my experience, this is not always the case. The bigger and more complex the project, the harder it is to connect the dots.</p><p>When talking to your manager or tech lead, you can start small, but it is important to go deep. Start asking about your task. You may hear that it contributes to a project the team is working on. An answer like this is not very helpful but could be a great starting point. It allows you to drive the discussion further and ask more interesting questions like:</p><ul><li><p>Why are we working on this project? Why is it important?</p></li><li><p>What metrics is this work expected to move, and how?</p></li><li><p>How does it support the company's goals and priorities?</p></li><li><p>What projects did we decide not to pursue to fund this work (a.k.a. opportunity cost)?</p></li></ul><p>A different way to understand where your work fits might be by talking to your product manager or people from the UX (User Experience) or marketing team. Because of their different perspective, they can teach you things you would never learn from fellow engineers. The challenge with this approach, however, is that you need to be able to explain your role in the project to them.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[Want your productivity to skyrocket? Avoid this trap]]></title><description><![CDATA[As a junior engineer, I felt the urge to jump on each new project that showed on the horizon.]]></description><link>https://www.growingdev.net/p/want-your-productivity-to-skyrocket</link><guid isPermaLink="false">https://www.growingdev.net/p/want-your-productivity-to-skyrocket</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 18 Oct 2024 06:26:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gmGS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a junior engineer, I felt the urge to jump on each new project that showed on the horizon. I never checked what I already had on my plate. Inevitably, I ended up with too many projects to work on simultaneously. Whenever my manager or a customer mentioned one of my projects, I immediately switched to it to show I was making progress. It took me years to realize that while this approach pleased the customer or the manager (and saved my junior dev butt) for the moment, it quietly hurt everyone.</p><h2>The three-line execution graph</h2><p>Executing multiple projects of the same priority at the same time looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gmGS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gmGS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 424w, https://substackcdn.com/image/fetch/$s_!gmGS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 848w, https://substackcdn.com/image/fetch/$s_!gmGS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gmGS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gmGS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png" width="1456" height="357" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:357,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83597,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gmGS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 424w, https://substackcdn.com/image/fetch/$s_!gmGS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 848w, https://substackcdn.com/image/fetch/$s_!gmGS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gmGS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b1973cc-b883-4626-ae1d-5c2ef8a4b7e7_2444x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Initially, there are two projects: Project A and Project B. You start working on Project A, but after a while, you receive a call from the customer inquiring about the progress of Project B. To make this customer happy, you switch to project B. In the meantime, a new interesting project, C, pops up. It is cool and seems small, so you pick it up. Your manager realizes that project A is dragging and asks about it. You somehow manage to finish your toy project C and move to A, which is well past the deadline. Then you pick B again.</p><p>If you didn't jump from project to project, the execution could look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XgNB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XgNB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 424w, https://substackcdn.com/image/fetch/$s_!XgNB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 848w, https://substackcdn.com/image/fetch/$s_!XgNB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 1272w, https://substackcdn.com/image/fetch/$s_!XgNB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XgNB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png" width="1456" height="358" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:358,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77594,&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;: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_!XgNB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 424w, https://substackcdn.com/image/fetch/$s_!XgNB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 848w, https://substackcdn.com/image/fetch/$s_!XgNB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 1272w, https://substackcdn.com/image/fetch/$s_!XgNB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F239a5220-e9ce-4bc1-946e-e431838481c8_2438x600.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>If you compare these graphs, three things stand out in the second scenario:</p><ul><li><p>Overall, the execution took less time. Resuming a paused project requires time to remember where the project was left off and get in the groove, i.e., to switch the context, which is time-consuming.</p></li><li><p>Projects A and B finished much quicker than in the first case. While you didn't make customer B feel good by saying you were working on their project, ultimately, the project was completed sooner. In fact, both projects, A and B, were finished much sooner than they would have if you bounced between them.</p></li><li><p>Project C came in late, so it should wait unless it is a much higher priority than other projects. Otherwise, it disrupts the execution of these projects.</p></li></ul><p>I know that life is not that simple. Completely avoiding context switching is rarely possible. But if you can limit it, your productivity will dramatically increase.</p><h2>Does it mean you should only work on one thing at a time?</h2><p>In the past I thought a good solution for junior engineers to combat context switching was to ask them to work on just one project at a time. But this idea has a serious drawback - projects often get stuck due to factors outside our control. If this happens and there is no backup, idling until the issue gets resolved is a waste of time.</p><p>Having two projects with different priorities works best. You execute on the higher-priority project whenever you can. If you can't, you turn to the other project until the main project gets unblocked.</p><p>What I like about this approach is that it is always clear what to work on: the higher priority project wins unless working on it is impossible.</p><p>Falling back to the lower priority project means there might be some context switching. While it is not ideal, it is better than idly waiting until the issues blocking the main project are resolved.</p><h2>But my TL (Tech Lead) always works on five projects!</h2><p>Indeed, experienced senior and staff engineers often work on a few projects at the same time. In my experience, however, it is a different kind of work. It might be preparing a high-level design, working on an alignment with a partner team, breaking projects into smaller tasks, and tracking the progress.</p><p>The secret is that most of these activities don't require as much focus as coding. Handling a few of them at the same time is much more manageable because the cost of switching contexts is much lower.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[A simple way to ship maintainable software]]></title><description><![CDATA[Avoid missing the obvious.]]></description><link>https://www.growingdev.net/p/a-simple-way-to-ship-maintainable</link><guid isPermaLink="false">https://www.growingdev.net/p/a-simple-way-to-ship-maintainable</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 10 Oct 2024 03:27:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/44b4123d-61e7-47e9-8284-a57e7e748690_220x166.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This was my first solo on-call shift on my new team. I was almost ready to go home when a Critical alert fired. I acknowledged it almost instantly and started troubleshooting. But this was not going well. Wherever I turned, I hit a roadblock. The alert runbook was empty. The dashboards didn't work. And I couldn't see any logs because logging was disabled.</p><p>Some team members were still around, and I turned to them for help. I learned that the impacted service shipped merely a week before, and barely anyone knew how it worked. The person who wrote and shipped it was on sick leave.</p><p>It took us a few hours to figure out what was happening and to mitigate the outage. This work made one thing apparent - this service was not ready for the prime time.</p><p>In the week following the incident, we filled the gaps we had found during the outage. Our main goal was to ensure that future on-calls wouldn't have to scramble when encountering issues with this service.</p><p>But the bigger question left unanswered was: how can we avoid similar issues with any new service or feature we will ship in the future?</p><p>The idea we came up with was the Service Readiness Checklist.</p><h2>What is the Service Readiness Checklist?</h2><p>The Readiness Checklist is a checklist that contains requirements each service (or a bigger feature) needs to meet to be considered ready to ship. It serves two purposes:</p><ul><li><p>to guarantee that none of the aspects related to operating the service have been forgotten</p></li><li><p>to make it clear who is responsible for ensuring that requirements have been reviewed and met</p></li></ul><p>When we are close to shipping, we create a task that contains a copy of the readiness checklist and assign it to the engineer driving the project. They become responsible for ensuring all requirements on the checklist.</p><p>Having one engineer responsible for the checklist helps avoid situations where some requirements fall through the cracks because everyone thought someone else was taking care of them. The primary job of this engineer is to ensure all checkboxes are checked. They may do the work themselves if they choose to or assign items to people involved in the project and coordinate the work.</p><p>Occasionally, the checklist owner may decide that some requirements are inapplicable. For example, the checklist may call for setting up deployment, but there is nothing to do if the existing deployment infrastructure automatically covers it.</p><p>The checklist will usually contain more than ten requirements. They are all obvious, but it is easy to miss some just because of how many there are.</p><h2>Example readiness checklist</h2><p>There is no single readiness checklist that would work for every team because each team operates differently. They all follow different processes and have their own ways of running their code and detecting and troubleshooting outages. There is, however, a common subset of requirements that can be a starting point for a team-specific readiness checklist:</p><p>&#9744; Has the service/feature been introduced to the on-call?<br>&#9744; Has sufficient documentation been created for the service? Does it contain information about dependencies, including the on-calls who own them?<br>&#9744; Does the service have working dashboards?<br>&#9744; Have alerts been created and tested?<br>&#9744; Does the service/feature have runbooks (a.k.a. playbooks)?<br>&#9744; Has the service been load tested?<br>&#9744; Is logging for the service/feature enabled at the appropriate level?<br>&#9744; Is automated deployment configured?<br>&#9744; Does the service/feature have sufficient test coverage?<br>&#9744; Has a rollout plan been developed?</p><h2>Success story</h2><p>Our team was tasked to solve a relatively big problem on tight timelines. The solution required building a pipeline of a few services. Because we didn't have enough people to implement this infrastructure within the allotted amount of time, we asked for help. Soon after, a few engineers temporarily joined our team. We were worried, however, that this partnership may not work out because of the differences in our engineering cultures. The Service Readiness Checklist was one of the things (others included coding guidelines, interface-based programming, etc.) that helped set clear expectations. With both teams on the same page, the collaboration was smooth, and we shipped the project on time.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[The 3 categories of skills every software developer needs to know]]></title><description><![CDATA[100% of software engineers who don't keep their skills sharp become obsolete[*].]]></description><link>https://www.growingdev.net/p/the-three-categories-of-skills-every</link><guid isPermaLink="false">https://www.growingdev.net/p/the-three-categories-of-skills-every</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 04 Oct 2024 06:00:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/cf378c2f-f9f3-43a1-b1e7-6c6fd0a23926_666x500.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>100% of software engineers who don't keep their skills sharp become obsolete[*]. Many who do keep their skills sharp also become obsolete. It all boils down to what skills they focus on.</p><p>I divide skills into three main categories: company-specific, job-specific, and universal. This categorization makes it easy for me to decide where to invest my time when it comes to skill development.</p><h2>Company-specific skills</h2><p>Each company has internal infrastructure, processes, and tools. Knowing them before joining the company is impossible, but everyone must learn them after joining.</p><p>Being strategic about what to focus on can save you a lot of time. Company-specific knowledge and skills are, by definition, not transferable. You need to learn them to do your job, but they become useless the moment you move on.</p><p>My strategy is to have a solid understanding of company-specific tools and processes but not dive too deeply unless I have to. Being in the dark will slow me down, but drilling into all the details is not much better. Most of these things constantly change, and I will quickly forget what I don't use. Instead, my time is better spent developing other, more general skills.</p><p>When I worked at Microsoft, I had a colleague named Ben. Ben was the most knowledgeable person I knew when it came to the .NET Framework build system. Although he was not on the build team, he knew all the scripts, hacks, and environment variables used in this build system. Acquiring and keeping this knowledge fresh ate much of Ben's time. Having Ben around was great for the team. We could (and constantly did) ping him for help with build-related issues. Eventually, Ben moved to a different team outside our organization. His expertise evaporated instantly, even though he didn't go far.</p><h2>Job-specific skills</h2><p>Job-specific skills are usually the skills that get us hired. Companies look for people who can hit the ground running, and having skills in demand increases the chances of getting hired substantially.</p><p>Job-specific skills are transferable. You learned them before getting hired and may use them in your next job. There is a caveat, though. It is only true if you keep your skills up-to-date. Knowing React and knowing React-as-of-four-years-ago is not the same thing.</p><p>I learned that trying to keep skills sharp just by using them at work doesn't always work. Companies rarely move as fast as technology. For instance, the product you work on might have been on the bleeding edge a few years ago. But it got stuck there because there was never a good enough business reason to migrate it to the newest framework version. You still need to maintain it but can't use the latest features.</p><p>Another thing to pay attention to is the signs that the technology you specialize in is becoming obsolete. Some technologies are more durable, but some can fade fast. You don't want to wake up one day only to realize that everyone except you has moved on.</p><p>CoffeeScript was one of the most followed projects on GitHub in the early to mid-2010s. It was incredibly popular, and there was a lot of hype around it. Today, hardly anyone remembers it.</p><p>Even if you got hired for your job-specific skills, it doesn't mean you can't learn new skills on the job. If you want to develop a new skill, you may consider joining a new project or moving to a different team. It isn't always easy because you don't have the skills they need, but it is doable - especially if you are known as someone who learns fast.</p><p>And the biggest secret: not only do you develop a new skill that may land you your next job, but you are also paid to do this.</p><h2>Universal skills</h2><p>Finally, there are the universal skills. These are skills that never become obsolete. You can use them at your current job, at your next job, or for non-work-related purposes. You can also apply them instantly.</p><p>These are skills like writing, effective time management, delivering great presentations, etc.</p><p><strong>The biggest problem with universal skills is that developing them never seems urgent.</strong> As a software developer, you will not lose your job because you write lengthy emails. But eventually, you may hit a glass ceiling and realize that what inhibits you is not coding but the lack of these universal skills.</p><p>&#8212;</p><p>* - citation needed</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[These 5 habits will make you a great code reviewer]]></title><description><![CDATA[High-quality code reviews are hard.]]></description><link>https://www.growingdev.net/p/these-5-habits-will-make-you-a-great</link><guid isPermaLink="false">https://www.growingdev.net/p/these-5-habits-will-make-you-a-great</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 27 Sep 2024 00:51:31 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a70e880c-8ee8-412b-b72b-b9caf9f0a082_577x433.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>High-quality code reviews are hard.</p><p>They are time-consuming and require significant mental effort.</p><p>Code reviewing is also not taught at school, and figuring it out on your own is hard work. In this post, I share five crucial habits all great code reviewers I know have in common.</p><h2>Make the code review about the code</h2><p>Code reviews are about the code, not the person who wrote the code. If you think the proposed change is incorrect or have suggestions to improve it, then, by all means, leave your comments (just remember to make <a href="https://www.growingdev.net/p/top-5-blunders-made-by-code-reviewers">them professional and high-quality</a>). However, leave out comments that don&#8217;t relate to the code under review.</p><h2>Understand the code and ask questions when in doubt</h2><p>Understanding the code under review is the foundation of a solid code review.</p><p>It is also the most difficult part.</p><p>Whenever you have doubts about proposed changes, you should ask the author for clarification. You might not be aware of an assumption the author is making or need help understanding how their changes fit in. However, the difficulty in grasping the changes is also often a sign of a mistake.</p><p>Asking a question will prompt the author to explain their thought process. As a result, they will either answer the question and clear up your doubts or realize that something is indeed wrong and needs to be fixed.</p><h2>Be clear about your expectations</h2><p>Code reviews can generate a wide variety of comments. Some are nits that you would like to see fixed but are not real issues. Some, however, identify serious problems that must be corrected before merging. If you leave a comment, make sure that the author understands which category it falls into. Doing this will save you and the PR author time and frustration.</p><p>Sometimes, you may take on a PR that is outside of your area of expertise. You may realize it only after you already left some comments. You are now in a weird situation: the author expects you to finish the review and approve the PR, but you don&#8217;t feel confident you can. If this happens, instead of accepting the change you don&#8217;t understand, it is better to leave a comment recommending the author get a review from someone more familiar with the code they are changing.</p><p>Side note: reviewing code that is outside of your area of expertise is a good thing. Even if you don&#8217;t understand the change enough to approve it, you can still provide useful feedback, identify bugs, and learn something. Just make sure the author does not expect to get your approval.</p><h2>Cross-check with the existing code</h2><p>Code reviews show only code that changed. Most of the time, it is sufficient. But sometimes, to understand the change fully, you need to check how the new code works with the code not included in the review because it hasn&#8217;t changed.</p><p>This idea may be obvious to most developers, but I was surprised to meet some who had never considered checking the existing code when reviewing PRs. In my experience, the biggest surprises are caused by not what&#8217;s included in the PR but by what&#8217;s missing.</p><p>Occasionally, examining the existing code may not give you all the answers. The ultimate weapon for these situations is to use a debugger. You can check out the PR branch and step through the code. It should resolve all your doubts. I resort to a debugger very rarely. It&#8217;s almost always easier and faster to ask the author.</p><h2>Resist the &#8220;stamp&#8221; pressure</h2><p>The pressure to merge changes quickly for projects on tight timelines is high. And it only grows as the deadline nears.</p><p>During the end game, engineers enter a Pull Request frenzy. Eventually, due to the number of PRs, code reviews often become a bottleneck. So, the engineers try to unblock themselves by asking to &#8220;stamp the diff&#8221; (i.e., approve changes without looking).</p><p>On the one hand it is understandable - no one wants to miss the deadline. On the other hand, these are the times when code changes need even more scrutiny than usual. Due to the time pressure, most PRs are coded very hastily. The changes may not be validated thoroughly (or at all) and the stress only increases the likelihood of mistakes.</p><p>While a proper code review takes time, merging code with issues a review could have caught is more costly. At best, fixing the problem will require sending a new PR (which, by the way, will trigger a review). At worst, an embarrassing bug ships to customers.</p><p>I remember when one of my teams worked extremely hard to finish a project on time. We were very close, and then one of the team members dropped a 1000-line PR a few hours before the deadline. The manager was trying hard to find someone willing to approve the PR. It wasn&#8217;t easy because the PR had a bunch of red flags, like spotty test coverage or many TODO comments, but he eventually succeeded. As soon as our product shipped, we started getting reports from angry customers complaining that important scenarios stopped working. We found that the hastily merged PR was the culprit. The team scrambled to fix the issues, but the damage was done. This one PR cost us the reputation we&#8217;d been building for a long time.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[On-call manual: How to cope with on-call anxiety]]></title><description><![CDATA[That's easy ...NOT!]]></description><link>https://www.growingdev.net/p/on-call-manual-how-to-cope-with-on</link><guid isPermaLink="false">https://www.growingdev.net/p/on-call-manual-how-to-cope-with-on</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 19 Sep 2024 06:37:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6f3c88c7-f0f8-44cd-8392-3d842e3c22dd_560x446.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>On-call anxiety is real. I've been there, and I know engineers who experienced it. Many factors contribute to it, but from my experience, three stand out.</p><h1>1. Unpredictability</h1><p>Unpredictability is the number one reason for on-call anxiety. You might be responsible for a wide range of services. They may break anytime for various reasons like network issues, deployments, failing dependencies, shared infra outages, data center drains (a.k.a. storms), excavators damaging fiber-optic cables (real!), etc. On-calls, especially new ones, worry they won't know what to do if they get an alert. How would they figure out what broke? How would they come up with a fix?</p><h2>What to do about it?</h2><p>With experience, the unpredictability aspect of the on-call gets easier. But even for the most seasoned on-call engineers, handling an outage can be difficult without the proper tools like:</p><ul><li><p>Easy-to-navigate dashboards that allow to tell quickly if a service is working correctly and identify problematic areas in case of failures</p></li><li><p>Playbooks (a.k.a. runbooks) explaining troubleshooting and mitigation steps</p></li><li><p>Documentation describing the service and its dependencies, including the relevant on-call rotations to reach out if necessary</p></li></ul><p>Having a team eager to jump in and help mitigate an outage quickly is priceless. Your team members understand some areas better than you. Knowing they have your back is reassuring.</p><h1>2. Too many alerts and incidents</h1><p>The second most common reason engineers fear their on-call is a never-ending litany of alerts, requests, and tasks. If you get a new alert when you barely finished acknowledging a previous one and are also expected to handle customer tickets and deal with requests from other teams, fretting your on-call is understandable. The exhaustion is usually exacerbated by the feeling of not doing a decent job. I was on a rotation like this once. After a while, I realized that everyone, not only me, was overwhelmed. Even though we toiled long hours, most alerts were ignored, customer tickets remained answered, and requests from other teams were only handled after they escalated them to the manager.</p><h2>What to do about it?</h2><p>There is no way a single person can fix a very heavy on-call by themselves. They won't have the time during their shift, and by the time the shift ends, they will be so fed up that they won't want to hear about anything on-call-related. There are, however, a few low-hanging fruits that can help improve the quality of the on-call quickly:</p><ul><li><p>Delete alerts - find routinely ignored alerts and determine if they're useful. If they aren't - delete them.</p></li><li><p>Tune noisy but useful alerts - adjust thresholds and windows for flapping alerts, alerts that fire prematurely, and short-lived alerts.</p></li><li><p>Get a secondary on-call - a second person could help handle tasks the primary on-call does not have the capacity to deal with (e.g., customer tickets). This could be only temporary.</p></li></ul><p>These ideas can alleviate on-call pain but are unlikely to fix a bad on-call for good. Improving a heavy on-call requires identifying and addressing problems at their source and demands effort from the entire team to maintain on-call quality. I wrote a <a href="https://www.growingdev.net/p/on-call-manual-boost-your-career">post dedicated to this topic</a>. Take a look.</p><h1>3. Middle-of-the-night alerts</h1><p>Many on-call rotations are 24/7. The on-call is responsible for dealing with incidents promptly, even if they happen in the middle of the night. Waking to an alert is not fun, and if it happens regularly, it is a valid reason to resent being on-call.</p><h2>What to do about it?</h2><p>While it may not be possible to avoid all middle-of-the-night alerts, there might be some actions you can take to reduce the disruption. A lot will depend on your specific situation, but here are some ideas:</p><ul><li><p>Check your dashboards in the evening and address any issues that could raise an alert.</p></li><li><p>Increase alert thresholds outside working hours. If your traffic is cyclical - e.g., you have much lower traffic at night because most requests come from one timezone - you may be able to relax thresholds outside working hours. Even if an incident happens, its impact will be smaller. Also, alerts get much noisier if the traffic volume is low (e.g., if you get ten requests in an hour and one fails, you might get an alert due to a 10% error rate).</p></li><li><p>Disable alerts at night, if you can. Some outages won't cause any impact unless they last for a long time. For instance, our team was responsible for a service that would work fine even if one of its dependencies was down for a day. This 24-hour grace period allowed us to turn off alerts at night.</p></li></ul><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[How to improve your coding skills (without spending a lot of time)]]></title><description><![CDATA[Is there a silver bullet?]]></description><link>https://www.growingdev.net/p/how-to-improve-your-coding-skills</link><guid isPermaLink="false">https://www.growingdev.net/p/how-to-improve-your-coding-skills</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 13 Sep 2024 06:46:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/75f67cae-5c21-4f9a-a9c7-2eda63662ddd_600x400.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every developer wants to get better at coding. But they sometimes don't know how and feel stuck. The good news is that there are a few simple ways to improve coding skills that many developers neglect. Most can be done as part of a regular job, so they don't require additional time. And doing them consistently can make you a better coder.</p><h2>Code reviews</h2><p>Code reviews are the easiest way to learn from others. Unfortunately, many developers treat code reviews as a chore. They want to spend as little time as possible on them. This way, they lose great learning opportunities.</p><p>What makes code reviews special is their interactivity. They allow asking the author about their choices and discuss alternatives they considered. Other participants often leave interesting comments or propose novel alternative solutions.</p><h2>Reading other developers' code</h2><p>I learned a lot about programming by reading code written by other developers. I often want to <a href="https://www.linkedin.com/posts/pawel-kadluczka_accelerate-your-software-engineering-career-activity-7125359972401500162-ztsq">know how a feature or library I use works</a>. Usually, the fastest way to get this information is by inspecting its code.</p><p>For instance, TypeScript supported some features, e.g., async/await, before they were added to JavaScript. I was curious how it was possible. So, I wrote short TypeScript snippets and checked how they were transpiled.</p><p>Your company's codebase is another great resource to learn from. When I get stuck, I often search my company repository to check how other developers solved a similar problem. Our <a href="https://www.growingdev.net/p/what-it-is-like-to-work-in-metas">repo is big</a>, so if I can't find anything useful, I am almost sure what I am trying to do is questionable.</p><p>I use the same strategy for my side projects but search GitHub.</p><p>If you find reading other developers' code challenging (I sure did), take a look at <a href="https://www.growingdev.net/p/the-art-of-code-reading">this post</a>.</p><h2>Debugging</h2><p>Stepping through the code, analyzing the stack trace, and inspecting variables will allow you to understand important nuances and easy-to-miss details much deeper. I often fire a debugger if I can't answer all my questions after reading the code.</p><h2>"Borrowing" code</h2><p>Let's be honest. Not all code needs to be written from scratch. Sometimes, we just need a boilerplate. But sometimes, we don't know how to solve a problem. In these cases, copying and adapting code is often faster (and easier). It could be the code you wrote in the past or someone else's code, e.g., copied from StackOverflow (I have yet to find a software developer who never copied code from StackOverflow.) AI-powered programming tools are built on this idea. Tools like Github Copilot ask you to constantly vet and adapt the code they generate. Here is the thing, though. You'll learn nothing if you don't try to understand why the code you copied works or can't correctly adapt it.</p><h2>Programming contests</h2><p><a href="https://adventofcode.com/">Advent of Code</a> taught me a lot. It is a light programming contest that takes place every December and consists of a series of small programming puzzles that can be solved in any programming language. I find it an excellent way to keep my coding skills sharp.</p><p>Solving Advent of Code problems is a good exercise, but examining other participants' solutions is where the real learnings are. And quite frankly, it can be a humbling experience. The different techniques the participants use to solve the problems can be astonishing. I remember being proud of my ultra-short, 30-line-long solution, only to see someone else solve the same problem in the same programming language with just two lines of code because they used a clever idea.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[Do code reviews find bugs?]]></title><description><![CDATA[I recently overheard this: Code reviews are a waste of time - they don't find bugs!]]></description><link>https://www.growingdev.net/p/do-code-reviews-find-bugs</link><guid isPermaLink="false">https://www.growingdev.net/p/do-code-reviews-find-bugs</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Fri, 06 Sep 2024 05:57:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/387874da-9827-46bb-b6a7-904caefd6084_889x500.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently overheard this: <em>Code reviews are a waste of time - they don't find bugs! We should rely on our tests and skip all this code review mambo-jumbo.</em></p><p>And I agree - tests are important. </p><p>But they won't identify many issues code reviews will. Here are a few examples.</p><h2><strong>Unwanted dependencies</strong></h2><p>Developers often add dependencies they could easily do without. Bringing in libraries that are megabytes in size only to use one small function or relying on packages like <a href="https://www.npmjs.com/package/true">true</a> may not be worth the cost. Code reviews are a great opportunity to spot new dependencies and discuss the value they bring.</p><h2><strong>Potential performance issues</strong></h2><p>In my experience, most automated tests use only basic test inputs. For instance, tests for code that operates on arrays rarely use arrays with more than a few items. These inputs might be sufficient to test the basic functionality but won't put the code under stress.</p><p>Code reviews allow spotting suboptimal algorithms whose execution time rapidly grows with the input size or scenarios prone to <a href="https://en.wikipedia.org/wiki/Combinatorial_explosion">combinatorial explosion</a>.</p><p>The latter bit our team not too long ago. When reviewing a code change, one of the reviewers mentioned the possibility of a combinatorial explosion. After discussing it with the author, they concluded it would never happen. Fast forward a few weeks, and our service occasionally uses 100% CPU before it crashes due to running out of memory. Guess what? The hypothetical scenario did happen. Had we analyzed the concern mentioned in the code review more thoroughly, we would've avoided the problem completely.</p><h2>Code complexity and readability</h2><p>Computers execute all code with the same ease. They don't care what it looks like. Humans are different. The more complex the code, the harder it is to understand and correctly modify. Code review is the best time to identify code that will become a maintenance nightmare due to its complexity and poor readability.</p><h2>Missing test coverage</h2><p>The purpose of automated tests is to flag bugs and regressions. But how do we ensure that these tests exist in the first place? Through a code review! If test coverage for a proposed change is insufficient, it is usually enough to ask in a code review for improving it.</p><h2>Bugs? Yes, sometimes.</h2><p>Code reviews do find bugs. They don't find all of them, but any bug caught before it reaches the repository is a win. Code reviews are one of the first stages in the software development process making them the earliest chance to catch bugs. And the sooner a bug is found, the cheaper it is to fix.</p><h2>Conclusion</h2><p>Tests are not a replacement for code reviews. However, code reviews are also not a replacement for tests. These are two different tools. Even though there might be some overlap, they have different purposes. Having both helps maintain high-quality code.</p><h2>Storytime</h2><p>One memorable issue I found through a code review was the questionable use of regular expressions. My experience taught me to be careful with regular expressions because even innocent-looking ones can lead to serious performance issues. But when I saw the proposed change, I was speechless: the code generated regular expressions on the fly in a loop and executed them.</p><p>At that time, I was nineteen years into my Software Engineering career (including 11 years at Microsoft), and I hadn't seen a problem whose solution would require generating regular expressions on the fly. I didn't even completely understand what the code did, but I was convinced this code should never be checked in (despite passing tests). After digging deeper into the problem, we found that a single `for` loop with two indices could solve it. If not for the code review, this change would've made it to millions of phones, including, perhaps, yours, because this app is very popular and has hundreds of millions of downloads across iOS and Android.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[What it is like to work in Meta's (Facebook's) monorepo]]></title><description><![CDATA[One to rule them all]]></description><link>https://www.growingdev.net/p/what-it-is-like-to-work-in-metas</link><guid isPermaLink="false">https://www.growingdev.net/p/what-it-is-like-to-work-in-metas</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Sun, 01 Sep 2024 07:15:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I love monorepos! Or at least I love Meta's (Facebook's) monorepo, which is the only real monorepo I have ever worked with. Here is why I think it&#8217;s great.</p><h3>Easy access to all code</h3><p>Meta's monorepo contains most of the company's code. Any developer working at Meta has access to it. We can search it, read it, and check the commit history. We also can, and frequently do, modify code code managed by other teams.</p><p>This easy access to all the code is great for the developer's productivity. Engineers can understand their dependencies deeper, debug issues across the entire stack, and implement features or bug fixes regardless of who manages the code. All this is available at their fingertips. They can hit the ground quickly without talking to other teams, reading their out-of-date wikis, and spending time figuring out how to clone and build their code.</p><h3>Linear commit history</h3><p>Meta's monorepo does not use branches, so the commit history is linear. The linear commiit history saves engineers from having to reverse engineer a London Tube Map-like merge history to determine if a given commit's snapshot contains their changes. With linear commit history, answering this question boils down to comparing commit times.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xEtC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xEtC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 424w, https://substackcdn.com/image/fetch/$s_!xEtC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 848w, https://substackcdn.com/image/fetch/$s_!xEtC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 1272w, https://substackcdn.com/image/fetch/$s_!xEtC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xEtC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png" width="1136" height="604" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:604,&quot;width&quot;:1136,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:441975,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xEtC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 424w, https://substackcdn.com/image/fetch/$s_!xEtC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 848w, https://substackcdn.com/image/fetch/$s_!xEtC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.png 1272w, https://substackcdn.com/image/fetch/$s_!xEtC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff38e89ec-2690-40d9-9de1-408ee8341c0a_1136x604.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></p><h3><strong>No versioning</strong></h3><p>Versioning is one of the most complex problems when working with multiple repos. Each repo is independent, and teams are free to decide which versions of dependencies they want to adopt. However, because each repo evolves at its own pace, different repos will inevitably end up with different versions of the same package. These inconsistencies lead to situations where a project may contain more than one version of the same dependency, but no single version works for everyone.</p><p>I experienced this firsthand during my time at Amazon. I was working on the Alexa app, which consisted of tens of packages, each pulling in at least a few dependencies. It was a versioning hell: conflicts were common, and resolving them was difficult. For example - one package used an older dependency because a newer version contained a bug. Another package, however, required the latest version because older versions lacked the needed features.</p><p>A monorepo solves versioning issues in a simple way: there is no versioning. All code is built together, so each package or project has only one version for a given commit.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ba-P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ba-P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 424w, https://substackcdn.com/image/fetch/$s_!Ba-P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 848w, https://substackcdn.com/image/fetch/$s_!Ba-P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 1272w, https://substackcdn.com/image/fetch/$s_!Ba-P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ba-P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png" width="702" height="395" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:395,&quot;width&quot;:702,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:384237,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ba-P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 424w, https://substackcdn.com/image/fetch/$s_!Ba-P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 848w, https://substackcdn.com/image/fetch/$s_!Ba-P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.png 1272w, https://substackcdn.com/image/fetch/$s_!Ba-P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73f76f22-2d9f-40d9-b783-c6e751918f31_702x395.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>Atomic commits</h3><p>Monorepos allow atomic cross-project commits. Developers can rename classes or change function signatures without breaking code or tests. They just need to fix all the code affected by their change in the same commit.</p><p>Doing the same is impossible in a multi-repo environment. Introducing breaking changes is either safe but slow (as it requires multiple commits for a proper migration) or fast but at the expense of broken builds.</p><p>This problem plagued the ASP.NET Core project in its early days (ProjectK anyone?). The team was working on getting abstractions right, so the foundational interfaces constantly changed. Many packages (each in its repo) implemented or used these interfaces. Whenever they changed, most repos stopped compiling and needed fixes.</p><h3>Build</h3><p>Builds in monorepos are conceptually simple: all code in the repo is built at a given commit.</p><p>This approach makes it possible to quickly tell what's included in the build and create bundles where all build artifacts match.</p><p>While the idea is simple, building the entire monorepo becomes increasingly challenging as the repository grows. Compiling big monorepos, like Meta's, in a reasonable time is impossible without specialized build tools and massive infra.</p><p>Multiple repos make creating a list of matching packages surprisingly hard. I learned this when working on ASP.NET Core. The framework initially consisted of a couple of dozen of repos. Our build servers were constantly grinding because of what we called "build waves." A build wave was initiated by a single commit that triggered a build. When this build finished, it triggered builds in repos depending on it. This process continued until all repos were built. Not only was this process slow and fragile, but with a steady stream of commits across all the repos, producing a list of matching packages was difficult.</p><p>The ASP.NET Core team eventually consolidated all the code in a single repository adopting the monorepo approach. This change happened after I left the team, but I believe the challenges behind getting fast and consistent builds were an important reason.</p><h2>What are the problems with monorepos?</h2><p>If monorepos are so great, why isn't everyone using them? There are several reasons.</p><h3>Scale</h3><p>Scale poses the biggest challenge for monorepos. Meta's repository is counted in terabytes and receives thousands of commits each day. Detecting conflicts and ensuring that all changes are merged correctly and don't break the build without hurting developers' productivity is tough. As most off-the-shelf tools cannot handle this scale, Meta has many dedicated teams that maintain the build infrastructure. Sometimes, they need to go to great lengths to do their job. Here is an example:</p><p>Back in 2013, tooling teams ran a simulation that showed that in a few years, basic git commands would take 45 minutes to execute if the repo continued to grow at the rate it did. It was unacceptable, so Facebook engineers turned to Git folks to solve this problem. At that time, Git was uninterested in modifying their SCM (Source Code Management) to support such a big repo. The Mercurial (hg) team, however, was more receptive. With significant <a href="https://engineering.fb.com/2014/01/07/core-infra/scaling-mercurial-at-facebook/">contributions from Facebook</a>, it rearchitected Mercurial to meet Facebook's requirements. This is <a href="https://graphite.dev/blog/why-facebook-doesnt-use-git">why Meta (a.k.a. Facebook) uses Mercurial (hg) as its source control</a>.</p><h3>Granular project permissions</h3><p>Monorepos make accessing any code in the repository easy, which is great for developers' productivity. However, companies often have sensitive code only selected developers should be able to access. This requirement goes against the idea of the monorepo, which aims to make all code easily accessible. As a result, enforcing access to code in a monorepo is problematic. Creating separate repos for sensitive projects is also not ideal, especially if these projects use the common infrastructure the monorepo provides for free.</p><h3>Release management</h3><p>A common strategy to maintain multiple releases is to create a branch for each release. Follow-ups (e.g., bug fixes) can be merged to these branches without bringing unrelated changes that could destabilize the release. This strategy won't work in monorepos with a linear history.</p><p>I must admit that I don't know how teams that ship their products publicly handle their releases. Our team owns a few services we deploy to production frequently. If we find an issue, we roll back our deployment and fix the bug forward.</p><h3>A single commit can break the build</h3><p>Because for monorepos, the entire codebase is built at a given commit, merging a mistake that causes compilation errors will break the build. These situations happen despite the tooling that is supposed to prevent them. In practice, this is only rarely a problem. Developers are only affected if the project that doesn't compile is a dependency. And even then, they can workaround the problem by working off of an older commit until the breakage is fixed.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[What is "gold plating" and why you should avoid it]]></title><description><![CDATA[Would you gold plate gold?]]></description><link>https://www.growingdev.net/p/what-is-gold-plating-and-why-you</link><guid isPermaLink="false">https://www.growingdev.net/p/what-is-gold-plating-and-why-you</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 22 Aug 2024 17:47:51 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fbde89f7-0f5d-40c9-8c83-fe7eef7bb74d_620x465.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I didn&#8217;t know what &#8220;<strong>gold plating</strong>&#8221; was until a senior engineer called out on one of my code changes and recommended that I &#8220;stop gold plating.&#8221; I was clueless about what he meant, so I went to talk to him. This meeting ended up being a memorable lesson in my software engineering journey.</p><p><a href="https://en.wikipedia.org/wiki/Gold_plating_(project_management)">Wikipedia defines gold plating</a> as: &#8220;<strong>the phenomenon of working on a project or task past the point of&nbsp;<a href="https://en.wikipedia.org/wiki/Diminishing_returns">diminishing returns</a>.</strong>&#8221; While the article talks about gold plating in the context of project management, the same phenomenon occurs in software development under a more familiar name: unnecessary refactoring.</p><p>The feedback I got from the senior engineer was that he noticed a pattern where I continued working on code that was already finished. I was polishing tests without covering new scenarios, changing perfectly fine variable or method names, or making functions slightly shorter.</p><p>I felt offended - I was making the code better!</p><p>How could a senior software engineer not see it?</p><p>How could they be against improving code?</p><p>So, he asked me to explain how my changes improved the code. I couldn&#8217;t. Only then did I realize he was right. I had to admit the new code was a bit different, but it wasn&#8217;t objectively better.</p><p>But then he went further and asked me how my changes impacted the team. I got confused: why would these small changes affect the team? It turned out they could and in a few ways.</p><p><strong>I didn&#8217;t use my time effectively.</strong></p><p>I spent time working on unimportant changes instead of taking on work that mattered. Therefore, someone else had to pick up tasks I could work on. If I did it, we could fix more bugs, implement more features, or ship faster. I also hurt myself - important work is usually a good learning opportunity and can lead to a quicker promotion, but I chose to pass on it.</p><p><strong>I stole time from team members.</strong></p><p>Code reviews were standard practice on every team I worked on in the past 20 years. Reviewing even small changes requires time. By requesting reviews of unneeded changes, I demanded that my team members spend time on trivialities.</p><p>Changing any code can lead to merge conflicts and disrupt other developer&#8217;s work. Sometimes, it is unavoidable. But it is not fun when changes no one needs cause conflicts.</p><p><strong>I occasionally introduced issues</strong>.</p><p>A few times, my gold plating resulted in bugs. I missed an edge case in the new code, and somehow, tests didn&#8217;t catch it. The bug would break the build or make it to production. Having to justify fixing issues introduced by unnecessary changes is always embarrassing.</p><h2>Not all refactoring is gold plating.</h2><p>I am not trying to convince anyone that refactoring, in general, is a waste of time. In most cases, it&#8217;s the opposite. Refactoring code often aims to simplify implementing future changes, remove duplication, or make code more understandable. Sometimes, especially when deadlines loom, developers (myself included) make shortcuts or introduce hacks that are a ticking bomb. Removing them is the right thing to do, substantially improving the code quality. These kinds of refactoring are not gold plating. Gold plating is about changes we could live without without anyone noticing them.</p><p>Now that you know what gold plating is, whenever you decide to refactor some code, you should ask yourself: &#8220;Is it a real improvement, or am I just gold plating?&#8221;</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[How to effectively work in big codebases]]></title><description><![CDATA[It takes some practice.]]></description><link>https://www.growingdev.net/p/how-to-effectively-work-in-big-codebases</link><guid isPermaLink="false">https://www.growingdev.net/p/how-to-effectively-work-in-big-codebases</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 15 Aug 2024 07:08:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!q5JS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You wouldn't hire a software engineer who cannot navigate code. Yet, I turned out to be one after I joined Microsoft and explored my new team's codebase. What I saw shocked me.</p><p>Before Microsoft, I worked in a small start-up, and our projects didn't exceed tens of thousands of lines of code. We could open, edit, and compile these projects directly in the IDE (Integrated Development Environment). My new team's codebase had a few hundred thousand lines written in several programming languages. It was about 15 years old and used pretty much all possible technologies Microsoft invented in those years. Compiling it successfully was impossible without setting tens of environment variables and using magic command line incantations. No single IDE could handle this. It took me a few weeks before I began to feel comfortable with this codebase and all the tools I had to use for development.</p><p>This was almost twenty years ago, and since then, I have worked in several other big codebases, including .NET Framework, Visual Studio, <a href="http://asp.net/">ASP.NET</a> Core, Amazon's codebase, and Meta's (Facebook's) mono repo. Even though all these codebases were different, they had many similar challenges, most of which could be overcome using similar tactics.</p><h2>Trying to understand all code is futile</h2><p>A single person cannot deeply understand a codebase that has a few hundred thousand lines. But this is not the only challenge. Large codebases are not static. They often receive hundreds of contributions each day, so they evolve rapidly.</p><p>On the bright side, understanding all the code is not necessary. Rather, it is better to have a very good understanding of the area your team works on and a <a href="https://www.linkedin.com/posts/pawel-kadluczka_accelerate-your-software-engineering-career-activity-7125359972401500162-ztsq">decent knowledge of the areas your code interacts with</a>.</p><h2>Code searching</h2><p>It's hard to be productive if you can't search code. But it gets exponentially harder if you can't even find the repo. And this was my experience during my years at Microsoft.</p><p>At that time, each team managed its codebase and source control individually, but there wasn't any tool to find these repositories. The internal search returned an incomplete list of, often outdated, wikis. The easiest way to find code was to first find the team responsible for it and then get all the details from them.</p><p>(Around the time I was leaving Microsoft, it implemented its new engineering system, 1ES (One Engineering System), which I am sure brought significant improvements.)</p><p>Searching large codebases on a dev machine may not be an option. Cloning the entire codebase to a dev box may not be feasible, especially if the codebase consists of thousands of federated repos, like Amazon's. Even if cloning is possible, tools such as grep are often too slow. This is why most big codebases have dedicated tools that make searching the code fast. Many of them also support following references, which is extremely helpful.</p><p>One factor that tremendously simplifies searching the code is formatting. If coding style is not enforced, finding anything is almost impossible. Searching a uniformly formatted codebase is much easier. This is why implementing a tool <a href="https://www.growingdev.net/p/the-downsides-of-an-inconsistent">that enforces coding style is a good investment</a>.</p><h2>Build system complexity</h2><p>Understanding the build system is key to being productive when working with big codebases.</p><p>Big codebases tend to have extremely complex build systems, often consisting of custom scripts, one-off tools, and specialized extensions stitched together to do the job. Off-the-shelf developer tools (e.g., IDEs) rarely can handle this complexity. Developers may struggle for days when they encounter a build system issue.</p><p>Many big companies have built their own tools to reign in this complexity and make it easier and faster for developers to work on large, multi-language code bases. Meta has <a href="https://buck.build/">buck</a> Amazon has <a href="https://gist.github.com/terabyte/15a2d3d407285b8b5a0a7964dd6283b0">brazil</a>, and Google has <a href="https://bazel.build/">bazel</a>. But from my experience, especially, with <code>brazil,</code> these tools also have some rough edges, so understanding how they work can go a long way.</p><h2>The development environment is constantly in flux</h2><p>Due to the number of engineers working in large codebases, even small productivity improvements can yield savings measured in engineering years. Maintainers work all the time to identify and fix bottlenecks. Because of this, the developer environment changes constantly, and the transitions are often not smooth, ironically resulting in lost productivity.</p><p>In 2019, Facebook decided to move away from Nuclide as its main IDE and migrate to VS Code. As a fan and an early adopter of VS Code (I even created an <a href="https://marketplace.visualstudio.com/items?itemName=moozzyk.Arduino">extension</a>, and it was only in 2015!) I welcomed this change. But the ride was bumpy. The command I used the most (a few times per hour) during the first year was: <code>Developer: Reload Windows.</code> I had to use Vim or go back to Nuclide multiple times because VS Code stopped working. The early versions were bare - it took more than two years to bring all the features Nuclide offered to VS Code.</p><p>(To clarify, the tooling team did an awesome job. It supported both IDEs during the migration and put immense effort into making this migration successful. And it paid off&#8212;today, our VS Code is very stable, constantly gets new features, and is a pleasure to work with.)</p><h2>Slow builds</h2><p>Compiling large codebases takes time. Fortunately, you never need to do it yourself. In most cases, you only need to build and integrate with your product the sub-project you modified. However, even these steps can take considerable time despite the miracles that build engineers perform.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!q5JS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!q5JS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 424w, https://substackcdn.com/image/fetch/$s_!q5JS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 848w, https://substackcdn.com/image/fetch/$s_!q5JS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 1272w, https://substackcdn.com/image/fetch/$s_!q5JS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!q5JS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png" width="413" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:413,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Compiling&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&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="Compiling" title="Compiling" srcset="https://substackcdn.com/image/fetch/$s_!q5JS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 424w, https://substackcdn.com/image/fetch/$s_!q5JS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 848w, https://substackcdn.com/image/fetch/$s_!q5JS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.png 1272w, https://substackcdn.com/image/fetch/$s_!q5JS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523fa428-2283-4ec0-8573-c3fa89f52814_413x360.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">https://xkcd.com/303/</figcaption></figure></div><h2>Legacy code</h2><p>The codebases of many successful products that have been around for decades (e.g., Microsoft Windows) are big. They grow organically over the years thanks to the contributions of hundreds or thousands of developers who merge code daily. New releases are developed by expanding previous releases. Consequently, large codebases accumulate a lot of legacy code that almost no one is familiar with. I am sure some of the code I considered legacy when I joined Microsoft twenty years ago is still around because the product I worked on is still on the market.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[On-Call manual: Onboarding a new person to the on-call rotation]]></title><description><![CDATA[Welcome to the party.]]></description><link>https://www.growingdev.net/p/on-call-manual-onboarding-a-new-person</link><guid isPermaLink="false">https://www.growingdev.net/p/on-call-manual-onboarding-a-new-person</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 08 Aug 2024 06:14:46 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5c76b249-362f-466d-a82a-bfcaa70ed578_600x543.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One (selfish) reason to celebrate a new team member is that they will eventually join the on-call rotation. And when they do, the existing shifts will move farther apart. However, adding an unprepared engineer to the on-call rotation can be a disaster. This post describes what on-call onboarding looks like on our team.</p><p>The on-call onboarding process is the same for each new team member. It consists of the following steps:</p><ol><li><p>Regular ramp-up</p></li><li><p>On-call overview</p></li><li><p>Shadow shift</p></li><li><p>Reverse shadow shift</p></li><li><p>First solo shift</p></li></ol><p>Let's look into each of these steps in more detail.</p><h2>Regular ramp-up</h2><p>The regular ramp-up aims to help new team members familiarize themselves with the problems the team is solving and teach them how to work effectively in the team's codebase. We want new colleagues to work on the code they will be responsible for when they are on call later. This approach allows them to acquire basic context that will be useful for maintaining this code and troubleshooting issues.</p><h2>On-call overview</h2><p>Regular ramp-up is rarely sufficient for new people to grasp the entire infra the team is responsible for. And knowing this infra is just the tip of the iceberg. There is much more an effective on-call needs to be familiar with, for instance:</p><ul><li><p>what are the dependencies, and what is the impact of their failures</p></li><li><p>how to find dashboards and use them for debugging</p></li><li><p>where to find the documentation (e.g., runbooks)</p></li><li><p>expectations, e.g., is the on-call responsible for alerts raised outside working hours</p></li><li><p>how to do deployments and rollbacks</p></li><li><p>tools used to troubleshoot and fix issues</p></li><li><p>standard operating procedures</p></li><li><p>and more</p></li></ul><p>On our team, we organize knowledge-sharing sessions that give new team members an overview of all these areas. We record these sessions to make revisiting unclear topics easy.</p><h3>Shadow on-call shift</h3><p>During the shadow on-call shift, the on-call-in-training (a.k.a. secondary on-call) shadows an experienced on-call (a.k.a. primary on-call). Both on-calls are subscribed to all tasks and alerts, but resolving issues is the primary on-call's responsibility. The primary on-call is expected to show the secondary on-call how to deal with outages. This is usually limited to problems occurring during working hours. Finally, the primary on-call can ask the secondary on-call to handle non-critical tasks, providing guidance as needed.</p><h3>Reverse shadow on-call shift</h3><p>After the shadow shift, things get real: the on-call in training becomes the primary on-call. They are now responsible for handling all alerts, tasks, deployments, etc. However, they are not alone&#8212;they have an experienced on-call having their back during the entire shift.</p><p>We schedule shadow and reverse shadow shifts back-to-back. This way, everything the on-call-in-training learned during the first shift is fresh when they become the primary on-call.</p><h3>First solo shift</h3><p>Once shadowing is complete, we add the new team member to the on-call rotation. We add them to the queue's end, giving them additional time to learn more about our systems and the infrastructure.</p><p>In addition to training new on-calls, our team maintains a chat to discuss on-call problems and get help when resolving issues. Both new and experienced on-calls regularly use this chat when they are stuck because they know someone will be there to help them.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[What can Taylor Swift teach us about Software Engineering?]]></title><description><![CDATA[...Ready for It?]]></description><link>https://www.growingdev.net/p/what-can-taylor-swift-teach-us-about</link><guid isPermaLink="false">https://www.growingdev.net/p/what-can-taylor-swift-teach-us-about</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 01 Aug 2024 06:01:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/40663e4e-7835-49b5-af16-5a0bdf975e29_500x266.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I can't stop listening to Taylor Swift. And it's not because I am a big fan of her&#8212;my daughter is.</p><p>With no choice but to listen to Taylor Swift, I wanted to know if her songs had anything to say about Software Engineering. Surprisingly, the answer was "yes." Here is what I've discovered.</p><h2>On being a Senior Software Engineer</h2><p>I found this gem in the song <strong>Karma.</strong> It is a perfect description of a Senior Software Engineer. I don't know any who wouldn't identify with it:</p><p><em>Ask me what I learned from all those years<br>Ask me what I earned from all those tears<br>Ask me why so many fade but I'm still here<br>I'm still here</em></p><h2>Gnarly bugs</h2><p>When it comes to bugs, every developer remembers one they struggled with for a long time and became obsessed with fixing. The song <strong>Tell Me Why</strong> articulates this feeling extremely well.</p><p><em>Why do you have to make me feel small<br>So you can feel whole inside?<br>Why do you have to put down my dreams<br>So you're the only thing on my mind?</em></p><h2>Botched Deployments</h2><p>Remember the time your push brought the entire production down? You can hear about it in the song <strong>Ivy</strong>.</p><p><em>So yeah, it's a fire<br>It's a goddamn blaze in the dark<br>And you started it<br>You started it</em></p><h2>Aggressive schedules</h2><p>In the <strong>Long Story Short,</strong> Taylor Swift sings about how developers feel after delivering a critical project on impossible-to-meet timelines. And it's exactly what you'd expect.</p><p><em>Long story short, it was a bad time<br>Long story short, I survived</em></p><h2>Career Development</h2><p>When I consider all the career conversations I've had in the past 20+ years, the <strong>I Forgot That You Existed</strong> song perfectly reflects my experience.</p><p><em>Sent me a clear message<br>Taught me some hard lessons<br>I just forget what they were<br>It's all just a blur</em></p><p></p><p>I had my domestic Taylor Swift SME (Subject Matter Expert) review this post. She didn't agree with any of my interpretations, so you should, perhaps, take them with a grain of salt, too.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item><item><title><![CDATA[On-call Manual: Boost your career by improving your team's on-call]]></title><description><![CDATA[Kill two birds with one stone.]]></description><link>https://www.growingdev.net/p/on-call-manual-boost-your-career</link><guid isPermaLink="false">https://www.growingdev.net/p/on-call-manual-boost-your-career</guid><dc:creator><![CDATA[Pawel Kadluczka]]></dc:creator><pubDate>Thu, 25 Jul 2024 16:17:53 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4a620e17-97e2-4b53-b343-49879ad5c95d_600x357.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have yet to find a team maintaining critical systems that is happy with its on-call. Most engineers dread their on-call shifts and want to forget about on-call as soon as their shift ends. For some, hectic on-call shifts are the reason to leave the team or even the company.</p><p>But this is great news for you. All these factors make improving on-call a great career opportunity. Here are a few reasons:</p><ul><li><p><strong>Team-wide impact.</strong> Making the on-call better increases work satisfaction for everyone on the team.</p></li><li><p><strong>Finding work is easy.</strong> No on-call is perfect. There's always something to fix.</p></li><li><p><strong>No competition.</strong> Most engineers consider work related to on-call uninteresting, so you can fully own the entire area. As a result, your scope might be bigger than any other development work you own.</p></li></ul><h3>Getting started</h3><p>It is difficult to propose meaningful improvements to your team's on-call before your first shift. You need to become familiar with your team's on-call responsibilities and problems before trying to make it better.</p><p>Once you have a few shifts under your belt, you should know the most problematic areas. Come up with a few concrete actions to remedy the biggest issues. This list doesn't have to be complete to get started. Some examples include tuning (or deleting) the noisiest alerts, refactoring fragile code, or automating time-consuming manual tasks.</p><p>Talk to your manager about the improvements you want to make. No manager who cares about their team would refuse the offer to improve the team's on-call. If the timing is not right (e.g., your team is closing a big release), ask your manager when a better time would be. Mention that you may need their help to ensure the participation of all team members.</p><p>Set your expectations right. Despite the improvements, don't expect your team members to suddenly start loving their on-call. It's a win if they stop dreading it.</p><h3>Execution</h3><p>From my experience, the two most effective ways to improve the on-call is to have regular (e.g., twice a year) fixathons combined with ongoing maintenance.</p><p>During a fixathon, the entire team spends a few days fixing the biggest on-call issues. In most cases, these will be issues that started occurring since the previous fixathon but weren't taken care of by on-calls during their shifts. You may need to work closely with your manager to ensure the entire team's participation, especially at the beginning.</p><p>Ongoing maintenance involves fixing problems as they arise, usually done by the person on call. As some shifts are heavier than others, the on-call may not always be able to address all issues.</p><h3>Your role</h3><p>Before talking about what your role is, let's talk about what your role isn't.</p><blockquote><p><strong>Your role isn't to single-handedly fix all on-call issues.</strong></p></blockquote><p>This approach doesn't scale. If you try it, you will eventually burn out, struggling to do two full-time jobs simultaneously: your regular responsibilities and fixing on-call issues. The worst part is that your team members won't feel responsible for maintaining the on-call quality. They might even care less because now somebody is fixing issues for them.</p><p>While you should still participate in fixing on-call issues, your main role is to:</p><ul><li><p><strong>organize fixathons</strong> - identify the most pressing issues and distribute issues for the team to work on, track progress, and measure the improvement</p></li><li><p><strong>ensure on-calls are addressing issues</strong> they encountered during their shifts</p></li><li><p><strong>build tools</strong> - e.g., <a href="https://www.growingdev.net/p/on-call-manual-measuring-the-quality">dashboards to monitor the quality of the on-call</a> or queries that allow to identify the biggest problems quickly</p></li></ul><p>If you do this consistently, your team members will eventually find fixing on-call issues natural.</p><h3>Skills you will learn</h3><p>Driving on-call improvements will help you hone a few skills that are key for successful senior and even staff engineers:</p><ul><li><p><strong>leading without authority</strong> - as the owner of the on-call improvement area you're responsible for coming up with the plan and leading its execution</p></li><li><p><strong>scaling through others</strong> - because you involve the entire team, you can get much more done than if you did it yourself</p></li><li><p><strong>influencing the engineering culture of the team</strong> - ingraining a sense of responsibility for the on-call quality in team members is an impactful change</p></li><li><p><strong>holding people accountable</strong> - making sure everyone does their part is always a challenge</p></li><li><p><strong>identifying problems worth solving</strong> - instead of being told what problems to solve, you are responsible for finding these problems and deciding if they are worth solving</p></li></ul><h3>Expanding your scope</h3><p>Once you start seeing the results of your work, you can take it further to expand your scope.</p><p>You can become the engineer who manages the on-call rotation for your team. This work doesn't take a lot of time but can save a lot of headaches for your manager. The typical responsibilities include:</p><ul><li><p>managing the on-call schedule</p></li><li><p>organizing onboarding new team members to the on-call rotation</p></li><li><p>helping figure out shift swaps and substitutions</p></li></ul><p>Another way to increase your scope is to share your experience with other teams. You can organize talks showing what you did, the results you achieved, and what worked and what didn't. You can also generalize <a href="https://www.growingdev.net/p/on-call-manual-measuring-the-quality">the tools you built</a> so that other teams can use them.</p><div><hr></div><p>If you found this useful, <strong>please share it with a friend and consider subscribing if you haven&#8217;t already.</strong></p><p><em>Thanks for reading!</em></p><p>-Pawel</p>]]></content:encoded></item></channel></rss>