<?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[verbosemode]]></title><description><![CDATA[Kotlin, Cloud and the rest.]]></description><link>https://verbosemode.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!nwKE!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd04236c-782e-47e5-92a6-f993558eebd0_384x384.png</url><title>verbosemode</title><link>https://verbosemode.dev</link></image><generator>Substack</generator><lastBuildDate>Thu, 09 Apr 2026 13:37:40 GMT</lastBuildDate><atom:link href="https://verbosemode.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Mirco Franzek]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[verbosemode@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[verbosemode@substack.com]]></itunes:email><itunes:name><![CDATA[Mirco]]></itunes:name></itunes:owner><itunes:author><![CDATA[Mirco]]></itunes:author><googleplay:owner><![CDATA[verbosemode@substack.com]]></googleplay:owner><googleplay:email><![CDATA[verbosemode@substack.com]]></googleplay:email><googleplay:author><![CDATA[Mirco]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Field Notes: Go and “Parse, don’t validate”]]></title><description><![CDATA[What a Go currency example reminded me about API design]]></description><link>https://verbosemode.dev/p/field-notes-go-and-parse-dont-validate</link><guid isPermaLink="false">https://verbosemode.dev/p/field-notes-go-and-parse-dont-validate</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Tue, 03 Feb 2026 09:00:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Y5X3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y5X3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y5X3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 424w, https://substackcdn.com/image/fetch/$s_!Y5X3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 848w, https://substackcdn.com/image/fetch/$s_!Y5X3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 1272w, https://substackcdn.com/image/fetch/$s_!Y5X3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y5X3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png" width="724" height="263.71945701357464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:322,&quot;width&quot;:884,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;@startuml ' ---------- Hand-drawn style ---------- skinparam backgroundColor #FFFFFF skinparam shadowing false skinparam roundcorner 18 skinparam defaultFontSize 14 skinparam padding 12 !option handwritten true  skinparam ArrowThickness 1.5  ' Wide layout for header (16:9-ish) left to right direction   ' ---------- Nodes ---------- rectangle \&quot;External Input\&quot; as Input #EEEEEE  rectangle \&quot;<b>Validate</b>\&quot; as Validate #FFF4E5 {   rectangle \&quot;Create value\&quot; as V1 #FFE8CC   rectangle \&quot;Use value\&quot; as V2 #FFE8CC   rectangle \&quot;Forget to validate\&quot; as V3 #FFCCCC }  rectangle \&quot;<b>Parse</b>\&quot; as Parse #EAFBF3 {   rectangle \&quot;Parse input\&quot; as P1 #D1FAE5   rectangle \&quot;Valid value\\n(by construction)\&quot; as P2 #A7F3D0   rectangle \&quot;Use guaranteed valid value\&quot; as P3 #D1FAE5 }  ' ---------- Connections ---------- Input -[#CC7A00]-> V1 V1 -[#CC7A00]-> V2 V2 -[#CC0000]-> V3  Input -[#047857]-> P1 P1 -[#047857]-> P2 P2 -[#047857]-> P3 @enduml&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="@startuml ' ---------- Hand-drawn style ---------- skinparam backgroundColor #FFFFFF skinparam shadowing false skinparam roundcorner 18 skinparam defaultFontSize 14 skinparam padding 12 !option handwritten true  skinparam ArrowThickness 1.5  ' Wide layout for header (16:9-ish) left to right direction   ' ---------- Nodes ---------- rectangle &quot;External Input&quot; as Input #EEEEEE  rectangle &quot;<b>Validate</b>&quot; as Validate #FFF4E5 {   rectangle &quot;Create value&quot; as V1 #FFE8CC   rectangle &quot;Use value&quot; as V2 #FFE8CC   rectangle &quot;Forget to validate&quot; as V3 #FFCCCC }  rectangle &quot;<b>Parse</b>&quot; as Parse #EAFBF3 {   rectangle &quot;Parse input&quot; as P1 #D1FAE5   rectangle &quot;Valid value\n(by construction)&quot; as P2 #A7F3D0   rectangle &quot;Use guaranteed valid value&quot; as P3 #D1FAE5 }  ' ---------- Connections ---------- Input -[#CC7A00]-> V1 V1 -[#CC7A00]-> V2 V2 -[#CC0000]-> V3  Input -[#047857]-> P1 P1 -[#047857]-> P2 P2 -[#047857]-> P3 @enduml" title="@startuml ' ---------- Hand-drawn style ---------- skinparam backgroundColor #FFFFFF skinparam shadowing false skinparam roundcorner 18 skinparam defaultFontSize 14 skinparam padding 12 !option handwritten true  skinparam ArrowThickness 1.5  ' Wide layout for header (16:9-ish) left to right direction   ' ---------- Nodes ---------- rectangle &quot;External Input&quot; as Input #EEEEEE  rectangle &quot;<b>Validate</b>&quot; as Validate #FFF4E5 {   rectangle &quot;Create value&quot; as V1 #FFE8CC   rectangle &quot;Use value&quot; as V2 #FFE8CC   rectangle &quot;Forget to validate&quot; as V3 #FFCCCC }  rectangle &quot;<b>Parse</b>&quot; as Parse #EAFBF3 {   rectangle &quot;Parse input&quot; as P1 #D1FAE5   rectangle &quot;Valid value\n(by construction)&quot; as P2 #A7F3D0   rectangle &quot;Use guaranteed valid value&quot; as P3 #D1FAE5 }  ' ---------- Connections ---------- Input -[#CC7A00]-> V1 V1 -[#CC7A00]-> V2 V2 -[#CC0000]-> V3  Input -[#047857]-> P1 P1 -[#047857]-> P2 P2 -[#047857]-> P3 @enduml" srcset="https://substackcdn.com/image/fetch/$s_!Y5X3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 424w, https://substackcdn.com/image/fetch/$s_!Y5X3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 848w, https://substackcdn.com/image/fetch/$s_!Y5X3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png 1272w, https://substackcdn.com/image/fetch/$s_!Y5X3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.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>A couple of weeks ago I read the fantastic post <a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/">Parse, don&#8217;t validate</a> by Alexis King. It is a longer post and worth reading, but I want to summarize what I got out of it. For me, the core ideas were:</p><ol><li><p>It is better to <strong>parse input into valid</strong> values rather than validate</p></li><li><p>People will forget to use your validation.</p></li><li><p>After parsing, the rest of the code must be able to rely on it being correct.</p></li></ol><p>These ideas came back to my mind recently while learning Go for a new project at work.</p><p></p><h2>An example in Go</h2><p>I decided to pick up <a href="https://learning.oreilly.com/library/view/learn-go-with/9781633438804/">Learn Go with Pocket-Sized Projects</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> since I like a &#8220;closed source&#8221; as the starting point when learning something new. While reading chapter 6, I remembered reading King&#8217;s article and thought this was exactly the situation she described. In that chapter, the project is a currency converter. It contains the type <code>Amount</code>.</p><pre><code>type Amount struct {
&#9;quantity Decimal
&#9;currency Currency
}</code></pre><p>The details of the type are not important, it is used to save monetary amounts in minor units of the currency (to avoid rounding errors with <code>float</code>). The authors notice a thing: <strong>you can create invalid instances of </strong><code>Amount</code>:</p><blockquote><p>[&#8230;] it seems wise to check that we&#8217;ll get the expected output [&#8230;] Following are the limitations:</p><ul><li><p>The number can&#8217;t be higher than 1012, or it will lose precision due to the floats.</p></li><li><p>The number&#8217;s precision must be compatible with the currency&#8217;s precision.</p></li></ul></blockquote><p>The chapter goes on by creating a <code>validate()</code> method on <code>Amount</code>:</p><pre><code>func (a Amount) validate() error</code></pre><p>There is nothing inherently wrong with that, but there is a<strong> flaw: you can create invalid </strong><code>Amount</code><strong> in first place.</strong></p><p>So in the sense of <a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/">Parse, don&#8217;t validate</a>, it would be wiser to introduce a <code>Parse() </code>method as the only way to create <code>Amount</code>:</p><pre><code>func Parse(quantity Decimal, currency Currency) (Amount, error) {
&#9;switch {
&#9;case quantity.subunits &gt; maxDecimal:
&#9;&#9;return Amount{}, ErrTooLarge
&#9;case quantity.precision &gt; currency.precision:

&#9;&#9;return Amount{}, ErrTooPrecise
&#9;}

&#9;return Amount{quantity: quantity, currency: currency}, nil
}
</code></pre><p>The code itself is simple, but it shows how moving checks to the point of construction can remove an entire class of problems from the rest of the program.</p><p></p><h2>Closing</h2><p>This post only scratches the surface, and Alexis King does the heavy lifting in the original article. I highly recommend reading <em>Parse, don&#8217;t validate</em> in full.</p><p>I hope you got something useful out of this field note. If you have thoughts, questions, or similar examples, feel free to reply or reach out!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/field-notes-go-and-parse-dont-validate/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/field-notes-go-and-parse-dont-validate/comments"><span>Leave a comment</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div><hr></div><p>&#9997;&#65039; <strong>About these field notes</strong><br>This newsletter is my notebook for things I learn and find useful. Not everything needs a long post, so from time to time I will publish short &#8220;field notes&#8221; like this one instead of letting them sit unread in my notes app.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I can recommend that book. It is a bit wordy, but experienced devs can just skip the fluff around the actual important parts.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Automatic MDC Logging in Ktor]]></title><description><![CDATA[A coroutine-safe Ktor plugin that enriches every log message with path parameters, without touching your routes]]></description><link>https://verbosemode.dev/p/automatic-mdc-logging-in-ktor</link><guid isPermaLink="false">https://verbosemode.dev/p/automatic-mdc-logging-in-ktor</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Tue, 27 Jan 2026 09:45:18 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4161" height="2774" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2774,&quot;width&quot;:4161,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;closeup photography of firewood&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="closeup photography of firewood" title="closeup photography of firewood" srcset="https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1512318601939-07bf29f1b74e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8bG9nfGVufDB8fHx8MTc2Nzc5Nzc5M3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 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">Photo by <a href="https://unsplash.com/@tompeham">Thomas Peham</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Engineers read more code than they write, but they may read even more log messages. We read them to see if everything works and, if not, to locate the problem. More often than not, it is hard to find a needle in a haystack, especially when things work in 99% of cases but fail for a single user.</p><p>To make the haystack smaller, it is vital to filter log messages efficiently, for example by adding the userID. Doing this by hand for every log message would be tedious, but we can leverage the mapped diagnostic context (MDC).</p><p>In this post, I will show how to automatically add useful information to the MDC based on path and query parameters in Ktor. With just a few lines of code, you can enrich log messages with valuable context. But first, let us take a look at what MDC actually is.</p><p><strong>TL;DR: If you already know what MDC is and just want the Ktor plugin, feel free to skip ahead to the section on implementing the </strong><code>PathParameterMDCPlugin</code><strong>.</strong></p><p>You can find the complete code on <a href="https://github.com/ablx/mdc_ktor/tree/main">GitHub</a>.</p><p></p><h2>Understanding Mapped Diagnostic Context</h2><p>Before we start, I want to make it clear that the following is based on <a href="https://logback.qos.ch/manual/mdc.html">SLF4J / Logback.</a> MDC is not a concept exclusive to Logback, but this is the setup I have experience with.</p><p>So, what is MDC? Simplified, it is a <strong>thread-local</strong> <code>Map&lt;String, String&gt;</code>. The contents of this map can be added to each log message without explicitly doing so every time; this is configured once in the logger configuration.</p><p>Here is a simple example. First, we add <code>%X</code> to the Logback pattern to output the MDC content:</p><pre><code>&lt;configuration&gt;
    &lt;appender name=&#8221;STDOUT&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt;
        &lt;encoder&gt;
            &lt;pattern&gt;MDC: [ %X ] %-5level - %msg%n&lt;/pattern&gt;

        &lt;/encoder&gt;
    &lt;/appender&gt;
...
&lt;/configuration&gt;</code></pre><p>We can use <code>MDC</code>&#8217;s methods:</p><pre><code>import org.slf4j.LoggerFactory
import org.slf4j.MDC

fun main() {
    val logger = LoggerFactory.getLogger(&#8221;logger&#8221;)
    logger.info(&#8221;Hello World!&#8221;)
    MDC.put(&#8221;key&#8221;, &#8220;value&#8221;)
    logger.info(&#8221;Hello again!&#8221;)
    MDC.put(&#8221;another key&#8221;, &#8220;new value&#8221;)
    logger.info(&#8221;Goodbye!&#8221;)
}</code></pre><p>Which gives us:</p><pre><code><code>MDC: [  ] INFO  - Hello World!
MDC: [ key=value ] INFO  - Hello again!
MDC: [ another key=new value, key=value ] INFO  - Goodbye!</code></code></pre><p>It is easy to see how this can be useful. <strong>If we can automatically add the userID to every log message, filtering logs becomes trivial.</strong></p><p>However, especially with Kotlin and coroutine-heavy Ktor, <strong>there is a problem: the MDC is bound to the thread.</strong> We can see this in the following example:</p><pre><code>MDC.put(&#8221;userID&#8221;, &#8220;abc&#8221;)
logger.info(&#8221;Start order creation&#8221;)
coroutineScope <strong>{
    </strong><em>launch </em><strong>{
        </strong>MDC.put(&#8221;orderID&#8221;, &#8220;123&#8221;)
        logger.info(&#8221;Created order&#8221;)
    <strong>}

}
</strong>logger.info(&#8221;Publishing order&#8221;)</code></pre><p>The output looks like this:</p><pre><code>MDC: [ userID=abc ] INFO  - Start order creation
MDC: [ orderID=123 ] INFO  - Created order
MDC: [ userID=abc ] INFO  - Publishing order</code></pre><p>We lose important information about how orders relate to users if we rely on the static methods. Fortunately, we can fix this by leveraging the correct coroutine context. To do so, we need to add a dependency and fill the MDC differently.</p><p>First, add the following dependency to your <code>build.gradle.kts</code>:</p><pre><code> implementation("org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.10.2")</code></pre><p>Then adjust the code from above:</p><pre><code>
...
import kotlinx.coroutines.slf4j.MDCContext
import kotlinx.coroutines.withContext

suspend fun main() {
    // ...
    coroutineScope {
        launch(MDCContext()) {
            MDC.put("orderID", "123")
            logger.info("Created order")

        }.invokeOnCompletion { logger.info("Publishing order") }
    }
    logger.info("End order creation") // new here
    <strong>}
</strong>}</code></pre><p>This now produces more useful logging information:</p><pre><code>MDC: [ userID=abc ] INFO  - Start order creation
MDC: [ userID=abc, orderId=123 ] INFO  - Created order
MDC: [ userID=abc, orderId=123 ] INFO  - Publishing order
MDC: [ userID=abc ] INFO  - End order creation</code></pre><p>We can make two observations:</p><ul><li><p><code>userID</code> is now propagated to the coroutine, as intended.</p></li><li><p>Additions to the MDC are not propagated outside of the coroutine implicitly. There is a solution for this, which you can find in the <a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-slf4j/kotlinx.coroutines.slf4j/-m-d-c-context/">KDoc</a>.</p></li></ul><p>Armed with that knowledge, let us take a look at how to fill the MDC based on your routes.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h2>Deriving MDC Values from Routes</h2><p>Our goal is to add any useful information present in the routes to the MDC.</p><p>For example, your application might have the following routes:</p><pre><code>get("/orders/{orderID}/items/{itemID}") {
    logger.info("Processing order")
    call.respond("")
}

get("/items/{itemID}") {
    logger.info("Processing request for item")
    call.respond("")
}</code></pre><p>For each call to <code>/orders</code>, we want both <code>orderID</code> and <code>itemID</code> in the MDC; for <code>/items</code>, only <code>itemID</code>. There are several ways to achieve this. The simplest approach is to add these values to the MDC manually, as shown above. This works fine for two or three routes but quickly becomes a hassle as the number of routes grows.</p><p>Another option is to leverage the <code>CallLogging</code> plugin, which we will look at next.</p><p></p><h3>Using CallLogging to Populate the MDC</h3><p>If your routes are well defined, you can configure CallLogging to populate the MDC. Well defined means that the path segment before a given ID is always the same. For example, <code>items/</code> always precedes the <code>{itemID}</code> path parameter. This is necessary because CallLogging does not know about path parameters. Instead, you need to parse the resolved URL and extract the parameters yourself.</p><pre><code>fun extractPathParameter(url: String, paramName: String) = when (paramName) {
    &#8220;itemID&#8221; -&gt; &#8220;/items/([^/]+)&#8221;.<em>toRegex</em>().find(url)?.groupValues?.get(1)
    &#8220;orderID&#8221; -&gt; &#8220;/orders/([^/]+)&#8221;.<em>toRegex</em>().find(url)?.groupValues?.get(1)
    else -&gt; null
}</code></pre><p>You can then use this function in the CallLogging plugin:</p><pre><code><em>install</em>(<em>CallLogging</em>) <strong>{
    </strong>mdc(&#8221;itemID&#8221;) <strong>{ </strong>call <strong>-&gt;
        </strong><em>extractPathParameter</em>(call.request.<em>uri</em>, &#8220;itemID&#8221;)
    <strong>}
    </strong>mdc(&#8221;orderID&#8221;) <strong>{ </strong>call <strong>-&gt;
        </strong><em>extractPathParameter</em>(call.request.<em>uri</em>, &#8220;orderID&#8221;)
    <strong>}
}</strong></code></pre><p>Note that <code>call.request.uri</code> contains the already resolved URL, which is why the <code>extractPathParameter</code> function is needed. With this setup, calling the endpoints yields:</p><pre><code>MDC: [ itemID=123 ] INFO  - Processing request for item
MDC: [ itemID=123 ] INFO  - 200 OK: GET - /items/123 in 240ms
MDC: [ itemID=789, orderID=456 ] INFO  - Processing order
MDC: [ itemID=789, orderID=456 ] INFO  - 200 OK: GET - /orders/456/items/789 in 2ms</code></pre><p>Nice, we get our IDs into the MDC without changing the routes. However, this approach only works if your routes are predictable and parameters can be reliably extracted from the resolved URL. In older applications with many past maintainers, the API schema is often less consistent. You could try to handle all cases in <code>extractPathParameter</code>, but that quickly becomes tedious. Luckily, there is another solution.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/automatic-mdc-logging-in-ktor?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/automatic-mdc-logging-in-ktor?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/automatic-mdc-logging-in-ktor?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p><h3>Implementing a Custom MDC Plugin</h3><p>So assume the orders endpoint looks like this, using <code>item</code> instead of <code>items</code>:</p><pre><code><em>get</em>(&#8221;/orders/{orderID}/<strong>item</strong>/{itemID}&#8221;) <strong>{
    </strong><em>logger</em>.info(&#8221;Processing order 2&#8221;)
    call.respond(&#8221;&#8220;)
<strong>}</strong></code></pre><p>Now, adding <code>itemID</code> to the MDC will still work for <code>/items</code>, but not for <code>/orders</code>:</p><pre><code>MDC: [ itemID=123 ] INFO  - Processing request for item
MDC: [ itemID=123 ] INFO  - 200 OK: GET - /items/123 in 483ms
MDC: [ orderID=456 ] INFO  - Processing order 2
MDC: [ orderID=456 ] INFO  - 200 OK: GET - /orders/456/item/789 in 1ms</code></pre><p>In this simple example, you could extend the <code>extractPathParameter</code> function, but this becomes error-prone and tedious in a real-life scenario with 30+ routes and many different path parameters. It is easier to find a solution that knows the path parameters directly and does not depend on the URL structure.</p><p>So it is time to write our own Ktor plugin. The idea is simple: intercept the pipeline at a point where path parameters and their values are known, add them to the MDC, and then let the pipeline continue.</p><pre><code>class PathParameterMDCPlugin {
    companion object Plugin : BaseRouteScopedPlugin&lt;Unit, PathParameterMDCPlugin&gt; {
        override val key = <em>AttributeKey</em>&lt;PathParameterMDCPlugin&gt;(&#8221;MdcPlugin&#8221;)

        override fun install(
            pipeline: ApplicationCallPipeline,
            configure: Unit.() -&gt; Unit,
        ): PathParameterMDCPlugin {
            val plugin = PathParameterMDCPlugin()

            pipeline.intercept(ApplicationCallPipeline.Call) <strong>{
                </strong><em>call</em>.parameters.forEach <strong>{ </strong>key, values <strong>-&gt;
                    </strong>MDC.put(key, values.<em>joinToString</em>())
                <strong>}
                </strong>withContext(MDCContext()) <strong>{
                    </strong>proceed()
                <strong>}
            }
            </strong>return plugin
        }
    }
}</code></pre><p>After installing this plugin on the routes, we automatically get an MDC entry for each path parameter:</p><pre><code><em>routing </em><strong>{
    </strong>install(PathParameterMDCPlugin)
...
}</code></pre><pre><code>MDC: [ itemId=123 ] INFO  - Processing request for item
MDC: [ itemId=123 ] INFO  - 200 OK: GET - /items/123 in 407ms
MDC: [ orderId=456, itemId=789 ] INFO  - Processing order 2
MDC: [ orderId=456, itemId=789 ] INFO  - 200 OK: GET - /orders/456/item/789 in 2ms
</code></pre><p>There is one final issue. We get <code>itemID</code> in the MDC for <code>/items</code>, but <code>item</code> for <code>/orders</code>. The fix is a one-time cleanup: unify the path parameter names. Unlike changing URLs, for example renaming <code>&#8230;/item</code> to <code>&#8230;/itemID</code> to satisfy CallLogging, renaming path parameters does not break clients. It is tedious work, but safe and done once.</p><p>With that, you now have everything needed to enrich your log messages with just a few lines of code.</p><p>The nice part is that most log aggregators, such as Graylog or Datadog, can index the MDC. If you use Datadog, you can simply query <code>@orderID:123</code> to retrieve all logs for a given orderID.</p><p></p><h2>Final Thoughts</h2><p>I hope you found this useful. Having the MDC filled more or less automatically helped me a lot when finding the right log messages and filtering out unrelated ones while debugging a problem.</p><p>As a side note, neither Claude nor Junie came up with a robust solution for the inconsistent API path problem. Claude even struggled to create a working Ktor plugin without relying on deprecated APIs. So, Claude, if you are reading this, this is how it is done.</p><p>For transparency: I used ChatGPT to fix spelling and grammar issues.</p><div><hr></div><p></p><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;a9174c32-631f-4cef-a5dd-0a6080d5af82&quot;,&quot;caption&quot;:&quot;I had set a goal to release a blog post each month, but unfortunately, I missed January &#9203;. Life and work sometimes get in the way, and I appreciate your patience. I&#8217;m excited to share this deep dive into a topic that has been on my mind for a while: why Kotlin&#8217;s&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Why Kotlin&#8217;s Result Type Falls Short for Handling Failures&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-02-11T07:48:18.289Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/why-kotlins-result-type-falls-short&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:156736239,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:4,&quot;publication_id&quot;:1328606,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!nwKE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd04236c-782e-47e5-92a6-f993558eebd0_384x384.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div>]]></content:encoded></item><item><title><![CDATA[From Autocomplete to Co-Author: My Year with AI]]></title><description><![CDATA[My honest look at Copilot, Junie, Claude, and what actually changed.]]></description><link>https://verbosemode.dev/p/from-autocomplete-to-co-author-my</link><guid isPermaLink="false">https://verbosemode.dev/p/from-autocomplete-to-co-author-my</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Tue, 30 Dec 2025 09:45:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!n06g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n06g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n06g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!n06g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!n06g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!n06g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n06g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3460646,&quot;alt&quot;:&quot;Comic-style illustration of a large bowl labeled &#8220;AI SLOP&#8221; overflowing with colorful, gooey sludge mixed with circuit boards and tech debris, spilling across a messy desk as a robotic arm scoops the neon slop.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://verbosemode.dev/i/182938615?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Comic-style illustration of a large bowl labeled &#8220;AI SLOP&#8221; overflowing with colorful, gooey sludge mixed with circuit boards and tech debris, spilling across a messy desk as a robotic arm scoops the neon slop." title="Comic-style illustration of a large bowl labeled &#8220;AI SLOP&#8221; overflowing with colorful, gooey sludge mixed with circuit boards and tech debris, spilling across a messy desk as a robotic arm scoops the neon slop." srcset="https://substackcdn.com/image/fetch/$s_!n06g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!n06g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!n06g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!n06g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb94278-3d40-4eb7-b150-078d3617aa19_1536x1024.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><figcaption class="image-caption">Bowl of AI slop, slopped by ChatGPT.</figcaption></figure></div><p>As the year comes to an end, I want to reflect on my AI journey and how it gradually became part of my day-to-day work. My experience with GitHub Copilot dates back to mid-2023, when it gave me an early glimpse of AI-assisted development, without yet feeling transformative.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Early Experiments and Mild Disappointment</h3><p>I wrote about Copilot some time ago. Back then, I was kind of disappointed. Especially in IntelliJ, Copilot was merely an autocomplete on steroids. It was useful, no question, but it was far from groundbreaking.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f37fc45e-128e-4e6c-b9c3-05e28e7eac9f&quot;,&quot;caption&quot;:&quot;When ChatGPT gained popularity back in 2022, I was genuinely surprised by its capabilities. I hadn&#8217;t been closely following the development of generative AI. The last thing I saw was DaVinci, which was also very impressive. However, ChatGPT&#8217;s ability to write correct code was both exciting and frightening.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;GitHub CoPilot: The Missed Chance?&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:27503931,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f7d97b9-7d61-45d1-ac0d-acd6f672e832_200x200.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-09-23T06:08:11.333Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!wzp0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F355ed3de-daf3-4aff-aeff-f3aa238fd987_700x482.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/github-copilot-the-missed-chance&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:137303264,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1328606,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!nwKE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd04236c-782e-47e5-92a6-f993558eebd0_384x384.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>I kept Copilot active in my IDE back then but did not see any amazing benefits or productivity gains. Throughout 2024, I mainly used my former employer&#8217;s own GPT version, which was not as good as ChatGPT but comparable. The workflow was the age-old &#8220;copy code into the prompt and ask for stuff.&#8221; Results were better, but it was not an efficient workflow.</p><p><strong>2025 was the first year I used AI exhaustively in my day-to-day work.</strong> Due to the generous AI policy at my workplace, I got to try a lot of tools that year.</p><p>It started by ditching Copilot in favor of JetBrains AI. To me, they were similar, but <strong>JetBrains AI is way better integrated into IntelliJ</strong>, and the results are overall better (I still love the commit message generation function).</p><p>I continued to use ChatGPT and added Gemini to the mix. However, I do not ask them anymore to write tests, find bugs, or the like, although they have gotten way better at this kind of prompt. I use them as a sounding board for more abstract topics, such as architecture questions. You need to prompt them carefully, but in the end they are like <em>the coworker who read all the blog posts</em>. I would not base my decisions solely on a chat with them, but they provide good starting points. I also like to paste long stack traces into them, as they are faster at finding the important spots and often provide good solutions for more generic problems.</p><p></p><h3>When AI Started to Actually Change My Work</h3><p>This is all nice, but I still did not experience any really big improvements in my day-to-day work. The tools definitely save me time overall. However, I was able to produce code faster once I started using <a href="https://www.jetbrains.com/junie/">Junie</a>, which became available in mid-2025 for us. To be honest, at first, I had the preconception that it was just some <em>vibe coding junk</em>. And <a href="https://garymarcus.substack.com/p/is-vibe-coding-dying">vibe coding is dead</a>, isn&#8217;t it?</p><p>But there&#8217;s no point in being stubborn. &#8220;<em>We&#8217;ve always done it this way</em>&#8221; is the dumbest argument there is. You have to try new things before you can hate them. <strong>And I hated it. At first.</strong></p><p>I did not use Junie in my production code straight away. I tried to really <em>vibe code</em>. I wanted to do things I was not capable of doing because I lacked the knowledge, so I decided to create a simple IntelliJ plugin. I know Kotlin and Java, but I have no experience creating IntelliJ plugins. The goal was simple: <strong>a plugin that changes the text color in the file tree based on regex</strong>. For example, if a file matches <code>.*Document</code>, its name should be yellow. Junie quickly delivered convincing code, including a dialog box in the settings where you could configure the color and RegEx. But in the end, it didn&#8217;t work; the text always remained black. After two hours, I gave up in frustration. In retrospect, that was premature.</p><p>I then used Junie in a domain I am more knowledgeable about, and the results differed vastly. Junie was able to produce meaningful test suites following the general patterns already present. It could also create new functionality and alter existing functionality. The quality was good overall, but not perfect.</p><p>But one thing bugged me: <strong>it was painfully slow</strong>. Strikingly, it seemed slow even on easy tasks, such as modifying an enum. For a few days, I tried to use Junie for literally everything. Through a lot of trial and error, I learned how to get the most out of it. As a result, most of my work consisted of <strong>30% Junie and 70% code I wrote myself</strong>, including modifications to Junie&#8217;s code.</p><p>Junie and I had grown into a happy relationship, until <a href="https://open.spotify.com/track/2SpEHTbUuebeLkgs9QB7Ue"><s>Jolene</s></a> Claude appeared. Sorry Junie, but <strong>Claude is everything you are, just better</strong>. From day one, I was able to use Claude more efficiently than Junie. It is faster, and the results are better.</p><p>Don&#8217;t get me wrong: even Claude produces bullshit from time to time. I would never trust AI&#8217;s results blindly. But given a good prompt, <strong>the amount of corrections I had to apply to Claude&#8217;s code was minimal</strong>. In the end, the ratio shifted to <strong>70% Claude&#8217;s code and 30% handwritten</strong>, including corrections and modifications.</p><p></p><h3>Where This Leaves Me</h3><p>So this is the state of the union for me currently. I can churn out code faster without compromising quality. From an economic point of view, that&#8217;s perfect. But <em>is it still fun</em>? To be honest, yes and no<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>I still love my job, even with the shift it has made due to AI. Writing code was never the focus of software development, at least not once you have some years of experience. Writing code was definitely the focus of my early years, which is probably why graduates and junior devs have a hard time now.</p><p><strong>Reading, understanding, and debugging code</strong> (and maybe changing 1&#8211;2 lines after that) are far more common. This has increased even further with AI. Now I feel more like <em>a pull request review machine</em> than a coder. The number of actual pull requests opened on GitHub has increased, since people can write code faster. At the same time, I am constantly doing mini reviews on the code Claude produces. <strong>Code reviews are now my main focus</strong> (for the coding part) of my job.</p><p><strong>Not sure how to feel about that, to be honest.</strong></p><p>With that being said, I thank you for reading my short end-of-year AI summary. I wish you a happy new year (in which I hope to be able to write more again).</p><p>So long!</p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This sentence was produced by ChatGPT as I did not find a good start for the article. I used ChatGPT to fix spelling and grammar issues through the whole article, as english is not my native language.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Or &#8220;jain&#8221;, as we say in German</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[On Staying Sane as a Developer]]></title><description><![CDATA[Reflections on the small habits that help me stay grounded in the middle of engineering chaos. Simple routines like brain dumps, leaving tasks unfinished, and protecting focus time make the difference]]></description><link>https://verbosemode.dev/p/on-staying-sane-as-a-developer</link><guid isPermaLink="false">https://verbosemode.dev/p/on-staying-sane-as-a-developer</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Sat, 13 Sep 2025 13:46:55 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="5184" height="3888" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3888,&quot;width&quot;:5184,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;brown wooden letter t-and i love you&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="brown wooden letter t-and i love you" title="brown wooden letter t-and i love you" srcset="https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1603880920705-3fcc96d6e602?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Y2hhb3N8ZW58MHx8fHwxNzU3Njg3NTE0fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 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">Photo by <a href="https://unsplash.com/@brett_jordan">Brett Jordan</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p></p><p>Chaos is part of a developer&#8217;s life. Priorities shift, tasks multiply, and the sense of being &#8220;done&#8221; is rare. <a href="https://verbosemode.dev/p/im-changing-my-writing-schedule-for">I had planned to publish one post per month in 2025</a>, yet here we are&#8212;<a href="https://verbosemode.dev/p/why-kotlins-result-type-falls-short">only one post in February so far</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Not because I ran out of ideas. I wanted to write only <em>quality</em> posts, things that felt worth sharing, like my earlier one on Kotlin&#8217;s <code>Result</code> that came out of a big refactor. Then I started a new job, and life quickly filled with busyness.</p><p>That small story is just another example of how unpredictable and messy this work can be. Which is why I want to share the habits that help me keep a bit of sanity in the middle of engineering chaos.</p><div><hr></div><p></p><h2>The Unavoidable Morning Routine &#9749;&#65039;</h2><p>I <strong>try</strong> to do this every morning: sit down, look at my calendar, and write down the three most important tasks of the day. The goal is to bring my brain into &#8220;work mode.&#8221; Combine this with a coffee, and voil&#224;&#8212;you&#8217;ve got a simple morning routine.</p><p>If I recall correctly, I got this idea from the book <strong><a href="https://chrisbailey.com/hyperfocus/">Hyperfocus</a></strong>.</p><p>Morning routines are trendy right now. You&#8217;ll find thousands of videos of people&#8212;famous or not&#8212;explaining why their morning routine is the best one ever. To be honest, sometimes I wish I had one of those strict one-hour routines with sports, meditation, and everything else. But reality bites: I don&#8217;t want to wake up before everyone else just to cram all that in, and I simply don&#8217;t have the time every morning.</p><p>Still, these 10 minutes of focus help me immensely to start the day right.</p><p></p><h2>The Brain Dump &#129504;</h2><p>If you&#8217;re familiar with Cal Newport, you might know his concept of a &#8220;shutdown routine&#8221;: closing open loops by moving tasks into a trusted system so they don&#8217;t linger in your mind after work.</p><p>Open loops are everywhere in software engineering. Some tasks&#8212;like reproducing a bug&#8212;can take minutes, hours, or even days, and during that time they stick in your head. I often found myself thinking about these things well into the evening.</p><p>My solution is simple: an end-of-day <strong>brain dump</strong>. I jot down, often unstructured, everything that comes to mind in my notebook:</p><ul><li><p>What I accomplished today</p></li><li><p>What went well and what didn&#8217;t</p></li><li><p>Any disagreements or frustrations</p></li><li><p>Thoughts on tricky tasks or ongoing bugs</p></li></ul><p>Some days, it&#8217;s just a couple of bullet points. Other days, it can fill several pages. The goal is always the same: <strong>get everything work-related out of my head.</strong></p><p>If something pops into my mind later, I write it down immediately. This has significantly reduced the sleepless nights spent replaying problem X over and over.</p><p>It also helps me transition from &#8220;work&#8221; to &#8220;private life&#8221;&#8212;a crucial boundary when working from home.</p><p></p><h2>Leave Things Broken for Tomorrow &#128736;&#65039;</h2><p>We&#8217;ve all been in retros, trying to recall what we worked on over the past few weeks. Sometimes, we can barely remember what we did the day before.</p><p>To make things easier, I&#8217;ve adopted a small trick: I don&#8217;t stop work with everything perfectly neat. Instead, I deliberately leave a test failing or a piece of code unfinished.</p><p>That way, when I sit down the next day, I know exactly where to pick things up. It jump-starts my brain and makes it easier to re-engage with the task.</p><p></p><h2>Have a Personal &#8220;Definition of Done&#8221; &#9989;</h2><p>You&#8217;ve probably heard of &#8220;Definition of Done&#8221; (DoD)&#8212;a Scrum buzzword meant to ensure a user story is truly complete. In my experience, these team-wide DoDs often fade into obscurity.</p><p>But having a <strong>personal</strong> DoD can be a game changer. Mine applies to pull requests, and before opening one, I mentally check off a short list, for example:</p><ul><li><p>Are all tests green?</p></li><li><p>Have I removed debug logs or quick hacks?</p></li><li><p>Is this the simplest yet most effective solution?</p></li><li><p>Did I test this on Dev?</p></li><li><p>(If applicable) Did I check performance for new queries?</p></li></ul><p>This feels less like Scrum jargon and more like the <a href="https://en.wikipedia.org/wiki/Pointing_and_calling">Pointing and Calling</a> method&#8212;simple but effective.</p><p></p><h2>Focus Time Calendar Blockers &#9995;</h2><p>For me, early mornings are the quietest&#8212;and most productive&#8212;parts of the day. That&#8217;s when I tackle the hardest problems, aka &#8220;eat the frog.&#8221;</p><p>To protect this time, I&#8217;ve blocked two slots in my calendar:</p><ul><li><p><strong>08:30&#8211;10:00</strong></p></li><li><p><strong>10:30&#8211;12:15</strong></p></li></ul><p>These are reserved for deep work. I try to protect them as much as possible, but I&#8217;m not dogmatic about it&#8212;if a meeting really needs to happen then, I&#8217;ll allow it.</p><p>The first block begins right after my short morning routine. It&#8217;s consistently my most productive window of the day.</p><p></p><div><hr></div><h2>Conclusion</h2><p>One of the most important lessons I&#8217;ve learned is that there will always be open tasks. You are never truly &#8220;done.&#8221; That&#8217;s why it&#8217;s essential to have tools and habits that help you stay sane amidst the chaos.</p><p>In this post, I shared some of mine. Hopefully, they inspire you&#8212;or at least give you a starting point for developing your own.</p><p>For further reading:</p><ul><li><p><em><a href="https://calnewport.com/writing/#books">Deep Work</a></em> by Cal Newport (Shutdown, Time Blocking)</p></li><li><p><em><a href="https://chrisbailey.com/hyperfocus/">Hyperfocus</a></em> by Chris Bailey (Three Most Important Things)</p></li><li><p>Unfortunately, I can&#8217;t find the original post where I first read about &#8220;Leave things broken for tomorrow.&#8221;</p></li></ul><p>If this post sparked a thought, I&#8217;d love to hear from you&#8212;drop me a line or leave a comment &#128172;. Always curious about how others tackle the chaos!</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Why Kotlin’s Result Type Falls Short for Handling Failures]]></title><description><![CDATA[The Kotlin standard library warns against using Result for domain logic&#8212;here&#8217;s why you should listen.]]></description><link>https://verbosemode.dev/p/why-kotlins-result-type-falls-short</link><guid isPermaLink="false">https://verbosemode.dev/p/why-kotlins-result-type-falls-short</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Tue, 11 Feb 2025 07:48:18 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="5184" height="3456" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3456,&quot;width&quot;:5184,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;selective focus photography of stop road sign&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="selective focus photography of stop road sign" title="selective focus photography of stop road sign" srcset="https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1523537444585-432d2bacc10d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxzdG9wfGVufDB8fHx8MTczOTE5Mzg3MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 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">Photo by <a href="true">Jose Aragones</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p><em>I had set a goal to release a blog post each month, but unfortunately, I missed January </em>&#9203;<em>. Life and work sometimes get in the way, and I appreciate your patience. I&#8217;m excited to share this deep dive into a topic that has been on my mind for a while: why Kotlin&#8217;s </em><code>Result</code><em> type is not the best choice for error handling in application code. I hope you find it insightful&#8212;let&#8217;s dive in!</em></p><p></p><p>A couple of days ago, I had a discussion about Kotlin&#8217;s <code>Result</code> type vs. <code>arrow-kt</code>'s <code>Either</code>. There are upsides and downsides to both, but I am a big fan of <code>Either</code> over <code>Result</code>, mainly because I think the design of <code>Result</code> comes with some flaws. Before we discuss these flaws, let&#8217;s take a step back and look at <code>Result</code> and why one might want to use it.</p><p></p><h2>Understanding Result</h2><p><code>Result</code> is a class from the Kotlin standard library. The KDoc states that it is:</p><blockquote><p>A discriminated union that encapsulates a successful outcome with a value of type <a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-result/index.html">T</a> or a failure with an arbitrary <a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-throwable/index.html">Throwable</a> exception.</p></blockquote><p>In other words, we can use <code>Result</code> in places where we would throw an exception, with the difference that returning a <code>Result</code> will not change the control flow as a thrown exception does.</p><p>Take a look at this example:</p><pre><code>fun unsafeParseInt(str: String): Int {
    return str.toInt() // This throws NumberFormatException for invalid input
}

fun main() {
    val numbers = listOf("1", "2", "abc", "4")

    val parsedNumbers = numbers.map { unsafeParseInt(it) } // &#128165; CRASH on "abc"
    
    println(parsedNumbers)
}
</code></pre><p>If we use a function that throws an exception inside a collection operation like <code>map</code>, it can cause an unexpected crash. We could mitigate that by returning <code>null</code> instead of throwing an exception, but this weakens our API if there might be several different causes for that Exception. Let&#8217;s see how <code>Result</code> can help us here:</p><pre><code>fun safeParseInt(str: String): Result&lt;Int&gt; {
    return try {
        Result.success(str.toInt())
    } catch (e: NumberFormatException) {
        Result.failure(e)
    }
}

fun main() {
    val numbers = listOf("1", "2", "abc", "4")

    val parsedResults: List&lt;Result&lt;Int&gt;&gt; = numbers.map { safeParseInt(it) }

    parsedResults.forEach { result -&gt;
        result.onSuccess { println("Parsed: $it") }
              .onFailure { println("Error: ${it.message}") }
    }
}</code></pre><p>Instead of letting the function throw, we return a <code>Result</code>. If everything worked fine, we can get the parsed number from the <code>Result</code>; otherwise, the <code>Result</code> will contain the exception. We can even write this more concisely:</p><pre><code>fun safeParseInt(str: String): Result&lt;Int&gt; = runCatching { str.toInt() }</code></pre><p>This behaves the same as the try-catch version above.</p><p>So far, so good. <code>Result</code> might be overkill for this example, but it has its uses. Think about API calls, which might fail regularly.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h3>Issues with <code>Result</code></h3><p>The most significant issue for the described use case with <code>Result</code> is its signature:</p><pre><code>@JvmInline
value class Result&lt;out T&gt; : Serializable</code></pre><p>As you can see, <code>Result</code> only has one generic parameter, yet it covers two cases: success and failure. In case of failure, <code>Result</code> cannot tell you exactly what went wrong, as it only returns a <code>Throwable</code>. Why is this bad? Going back to the API call example, you definitely want to know what went wrong. Is the server not reachable? Did you provide an incorrect payload? Were the credentials invalid? Sure, you can use <code>when</code> expressions to check error types, but you might never know if you missed a case.</p><p>Because <code>Result</code> only explicitly knows the success type, it does not provide a meaningful <code>map</code> operation for the failure case. Additionally, <code>Result</code> lacks a <code>flatMap</code> function, making it cumbersome to chain multiple <code>Result</code> values.</p><p>Finally, failures in <code>Result</code> are always <code>Throwable</code> instances, which implies that something unexpected happened. However, this is not always the case, especially in the domain layer. Validation errors, for example, are not unexpected. They are not exceptions; they are the rule and can be modeled as domain classes. <code>Result</code> does not support this.</p><p><strong>Why is </strong><code>Result</code><strong> designed this way</strong>? Because it was <strong>not</strong> designed to be used in application code. The <a href="https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/result.md#use-cases">Kotlin KEEP proposal</a> specifically states:</p><blockquote><p>The <code>Result</code> class is designed to capture generic failures of Kotlin functions for their latter processing and should be used in general-purpose API like futures, [...] The <code>Result</code> class is not designed to represent domain-specific error conditions.</p></blockquote><p></p><div><hr></div><h2></h2><h3>Alternative: <code>Either</code> from Arrow</h3><p>There are some alternatives to <code>Result</code>, but first, let&#8217;s discuss what to do if your code already uses <code>Result</code>. The Arrow library provides some utilities to make <code>Result</code> more usable in your code. First, it adds a <code>flatMap</code> <a href="https://apidocs.arrow-kt.io/arrow-core/arrow.core/flat-map.html">function</a>, making chaining <code>Result</code> instances easier. For more advanced cases, Arrow includes an implementation of its <code>Raise</code> API for <code>Result</code>.</p><pre><code>fun result1(): Result&lt;String&gt; = <em>TODO</em>()
fun result2(): Result&lt;String&gt; = <em>TODO</em>()

fun workWithResults(): Result&lt;String&gt; = <em>result </em><strong>{
    </strong>val string1: String = <em>result1</em>().bind()
    val string2: String = <em>result2</em>().bind()
    string1 + string2
<strong>}</strong></code></pre><p>Here, <code>bind</code> returns the success value if available or propagates the failure. If <code>result1()</code> returns a failure, <code>workWithResults()</code> will also return that failure, and <code>result2()</code> will never be called.</p><p>But this is just a workaround. The real solution is <code>Either</code>.</p><p></p><h3>Why <code>Either</code>?</h3><p><code>Either</code> is not an invention of Arrow; it is a general-purpose solution from functional programming. Unlike <code>Result</code>, <code>Either</code> does not limit failure cases to <code>Throwable</code>. It has two generic types, one for success and one for failure:</p><pre><code>
object NotANumber // typed error

fun parseIntSafely(str: String): Either&lt;NotANumber, Int&gt; = try {
    str.<em>toInt</em>().<em>right</em>()
} catch (e: NumberFormatException) {
    NotANumber.<em>left</em>()
}</code></pre><p><code>Either</code> is a more flexible alternative to <code>Result</code>, as it allows defining a specific failure type instead of relying on <code>Throwable</code>. It follows a functional approach and supports useful operations like <code>map</code>, <code>flatMap</code>, and <code>fold</code>, making error handling more structured and predictable.</p><p>While <code>Either</code> is powerful, using it effectively requires understanding functional programming principles, which is beyond the scope of this post. If you want to dive deeper, check out <a href="https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#concepts-and-types">Arrow&#8217;s documentation</a>.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/why-kotlins-result-type-falls-short?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/why-kotlins-result-type-falls-short?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/why-kotlins-result-type-falls-short?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p><h2>Rolling Your Own Solution</h2><p>If <code>Either</code> feels too abstract, you can roll your own <code>Result</code>-like classes. However, I recommend this only for smaller applications, as you may end up reimplementing what <code>Either</code> already provides. For our string parsing example, it could look like this:</p><pre><code>
sealed class ParseResult {
    data class Success(val value: Int) : ParseResult()
    data object NotANumber : ParseResult()
}

fun parseIntSafely(str: String): ParseResult = try {
    ParseResult.Success(str.<em>toInt</em>())
} catch (e: NumberFormatException) {
    ParseResult.NotANumber
}</code></pre><p></p><h2>Verdict</h2><p>If you can, avoid <code>Result</code> in your application code. It is not designed for domain-specific error handling. Rolling your own solution is feasible for small projects, but for medium to large applications, <code>Either</code> is the better choice.</p><p>That being said, it's always worth considering whether you need something like this at all. If you're dealing with a simple success-or-failure scenario, returning <code>null</code> for failure might be a reasonable and lightweight alternative. This pattern is already used in many Kotlin standard library functions, such as <code>toIntOrNull</code>, which:</p><blockquote><p>Parses the string as an <a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html">Int</a> number and returns the result or <code>null</code> if the string is not a valid representation of a number.</p></blockquote><p>Often, the simplest solution is the best.</p><p></p><p>What do you think about <code>Result</code>? Do you use it extensively in your code? Let me know in the comments below! Thanks for reading! &#128522;</p>]]></content:encoded></item><item><title><![CDATA[I’m Changing My Writing Schedule for 2025 🖊️]]></title><description><![CDATA[Reflecting on 2024: Lessons Learned About Writing and Sustainability]]></description><link>https://verbosemode.dev/p/im-changing-my-writing-schedule-for</link><guid isPermaLink="false">https://verbosemode.dev/p/im-changing-my-writing-schedule-for</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Tue, 12 Nov 2024 11:55:54 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="2992" height="2000" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2000,&quot;width&quot;:2992,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;white ceramic mug with coffee on top of a planner&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="white ceramic mug with coffee on top of a planner" title="white ceramic mug with coffee on top of a planner" srcset="https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1506784983877-45594efa4cbe?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0MXx8c2NoZWR1bGV8ZW58MHx8fHwxNzMxNDEyNDc0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 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">Photo by <a href="true">Est&#233;e Janssens</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p></p><p>Hey all &#128075;, it&#8217;s Mirco here with a quick update on my writing plans.</p><p>Long-time readers may have noticed that my publishing rhythm has been quite irregular this year, with bursts of weekly posts followed by month-long periods of silence. Reflecting on this past year&#8217;s challenges, I&#8217;ve rethought how to approach my writing schedule moving forward.</p><p>I love writing blog posts, but I must admit that, for now, I can&#8217;t match the high output of others on Substack. Writing posts on a weekly or bi-weekly basis didn&#8217;t work for me; it wasn&#8217;t a sustainable rhythm.</p><p><strong>Therefore, my plan for 2025 is to publish at least one high-quality, long-form post each month.</strong> I plan to release them at the <strong>end of each month</strong>. By focusing on one valuable post each month, I can concentrate on creating deeper, more meaningful content. I may sprinkle in shorter posts now and then, but I&#8217;m publicly committing to twelve posts per year for some added pressure.</p><p>Thank you all for reading my articles and especially for your comments and other reactions.</p><p>I plan to release the first post in the new schedule at the end of December&#8212;I hope you enjoy it. &#128591;</p>]]></content:encoded></item><item><title><![CDATA[If You’re Not Refactoring Every Day, You’re Making a Mistake]]></title><description><![CDATA[Small Daily Refactors Prevent Big Headaches: How Regular Cleanups Save Your Team from Code Spaghetti, Tech Debt, and Customer Frustration]]></description><link>https://verbosemode.dev/p/if-youre-not-refactoring-every-day</link><guid isPermaLink="false">https://verbosemode.dev/p/if-youre-not-refactoring-every-day</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Wed, 25 Sep 2024 06:32:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1UdC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1UdC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1UdC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!1UdC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!1UdC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!1UdC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1UdC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:541272,&quot;alt&quot;:&quot;A simple comic-style illustration of a tangled ball of wires or string being pulled free by sleek robot hands, primarily using various shades of blue tones. The wires and robot hands are colored in soft and bold blue hues, creating a cohesive, clean look. The image focuses on the robot hands gently untangling the wires, symbolizing problem-solving or refactoring in progress. The blue color palette gives the image a modern, light, and futuristic feel, with clear, minimalistic lines.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&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="A simple comic-style illustration of a tangled ball of wires or string being pulled free by sleek robot hands, primarily using various shades of blue tones. The wires and robot hands are colored in soft and bold blue hues, creating a cohesive, clean look. The image focuses on the robot hands gently untangling the wires, symbolizing problem-solving or refactoring in progress. The blue color palette gives the image a modern, light, and futuristic feel, with clear, minimalistic lines." title="A simple comic-style illustration of a tangled ball of wires or string being pulled free by sleek robot hands, primarily using various shades of blue tones. The wires and robot hands are colored in soft and bold blue hues, creating a cohesive, clean look. The image focuses on the robot hands gently untangling the wires, symbolizing problem-solving or refactoring in progress. The blue color palette gives the image a modern, light, and futuristic feel, with clear, minimalistic lines." srcset="https://substackcdn.com/image/fetch/$s_!1UdC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!1UdC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!1UdC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!1UdC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c227b6c-265e-45a8-b6f4-6191fd47f74a_1792x1024.webp 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">Drawn by DALL-E</figcaption></figure></div><p></p><p>Let me take you back to a time when I worked on an old internal product &#8212; let&#8217;s call it <strong>Garbo</strong>. Now, Garbo wasn&#8217;t glamorous. It wasn&#8217;t directly responsible for generating revenue. It worked in the background, keeping everything running smoothly. That is, until one day, boom &#8212; it failed<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><p>Our customers got seriously irritated. And once that happened, we had to drop everything to fix it.</p><p>The codebase? It had been neglected for years. There was <strong>duplicate code</strong> everywhere, <strong>unused features</strong> still floating around, and the worst part? Tons of special-case logic for every <em>exotic</em> scenario you could think of. <strong>Business logic was scattered</strong> between the UI and the backend, making it nearly impossible to figure out what was actually in use. <strong>Testing?</strong> Yeah, right. Trying to make sense of the system was like unraveling a huge knot of code spaghetti. Tests were 80% mocking and 20% actual tests. However, most of the time it was unclear if the test did something useful.</p><p>It took <strong>four senior engineers</strong> (including me) months to make Garbo maintainable again. We spent countless hours untangling it just to keep things running smoothly. Time that could&#8217;ve been used to build something new &#128736;&#65039; was spent cleaning up a mess that could have been avoided.</p><p>Ever since then, every time I tackle a bigger refactoring project, I remind my product owner: <strong>&#8220;You don&#8217;t want a second Garbo.&#8221;</strong> And trust me, you don&#8217;t.</p><p>What could have saved us from this nightmare? <strong>Refactoring. Every. Single. Day.</strong> &#128736;&#65039;</p><p></p><h3>Refactor Every Day &#9881;&#65039;</h3><p><strong>Spending just 20 minutes a day refactoring can save you hours of frustration down the road.</strong></p><p>Whether it&#8217;s simplifying the code you just wrote or revisiting something from the backlog, small improvements make your codebase cleaner, more maintainable, and easier to understand. Refactoring isn&#8217;t just about cleaning up &#8212; it&#8217;s about understanding your code on a deeper level, and that leads to writing better code in the future.</p><p><strong>Even the best-written code will eventually need refactoring</strong>. Hotfixes, last-minute feature requests, and quick patches  can clutter even the most carefully crafted code. No matter how great your code is today, it&#8217;s going to need maintenance as things evolve.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p>Not sure where to begin? Here&#8217;s a quick checklist to get you started during your 20-minute daily refactor:</p><ul><li><p><strong>Simplify logic</strong>: Break down bloated methods into smaller, more focused ones.</p></li><li><p><strong>Rename variables</strong>: Make sure your variable names clearly describe their purpose &#128221;.</p></li><li><p><strong>Remove unused code</strong>: &#128465;&#65039; Get rid of any dead code that&#8217;s no longer needed.</p></li><li><p><strong>Reduce complexity</strong>: Simplify deeply nested conditionals or loops when possible.</p></li><li><p><strong>Use your tools</strong>: &#128736;&#65039; Leverage your IDE&#8217;s refactoring features, like automatic method extraction, renaming, and refactor hints. These built-in tools make the process faster and less error-prone.</p></li></ul><p>Want to dig deeper? Here are some great resources:</p><ul><li><p><strong><a href="https://refactoring.guru">Refactoring.guru</a></strong>: If you&#8217;re wondering where to start, this site is packed with refactoring tips. It&#8217;s like a treasure chest of practical advice &#8212; start here if you&#8217;re feeling stuck.</p></li><li><p><strong><a href="https://www.amazon.de/Working-Effectively-Legacy-Code-English-ebook/dp/B005OYHF0A/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=12OSCFI9IAOO7&amp;dib=eyJ2IjoiMSJ9.Q5fQHv2_0TBj5rn6xwV1Zz-vdEuoMcUkUeMBpDf2snHg01QR99nVw5uMsljIrCoZ8L5KoafOm8qh0-p0atTEHLgEj57JOL938I2m_IoEdhbmF_HU-MoahpuOznw1nehP5KHdFeHvk-MGZTD1xGTv0knQhRhtlkRS7_1r-MW8AmhONAQzJOEbSk0_PPKB0x9Lm9Y42TYsdTXCOLolpj1aAFaLHGfmuzF_VlxY50jLf6Q.xNAuFswVeA75AJuAyrebobvt6hj68cjXWN7BtbtSeMA&amp;dib_tag=se&amp;keywords=Working+Effectively+with+Legacy+Code%3A&amp;qid=1727182117&amp;sprefix=working+effectively+with+legacy+code+%2Caps%2C85&amp;sr=8-1">Working Effectively with Legacy Code</a></strong>: If you're battling a legacy codebase (like Garbo), this book is a must-read. Sure, it&#8217;s a bit dated, but the advice is solid and will help you tame the beast.</p></li><li><p><strong>The Usual Suspects</strong>: You&#8217;ve heard of them &#8212; <a href="https://www.amazon.de/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=pd_bxgy_d_sccl_2/261-1125973-6519463?pd_rd_w=NqjoI&amp;content-id=amzn1.sym.46a82004-1254-4eab-a26d-553fc9d388c8&amp;pf_rd_p=46a82004-1254-4eab-a26d-553fc9d388c8&amp;pf_rd_r=0V8RKTQ3VDVB8QQMH9JH&amp;pd_rd_wg=qrUxt&amp;pd_rd_r=b0f9b851-f184-46b0-a2e7-e28ab71f605d&amp;pd_rd_i=0132350882&amp;psc=1">Clean Code</a>, <a href="https://www.amazon.de/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073/ref=bmx_dp_o28b7p6n_d_sccl_3_12/261-1125973-6519463?pd_rd_w=d9KE0&amp;content-id=amzn1.sym.7df9fb5e-3feb-4608-b891-7f6abaed1317&amp;pf_rd_p=7df9fb5e-3feb-4608-b891-7f6abaed1317&amp;pf_rd_r=3S8TKF1QE7ZF5CVDD096&amp;pd_rd_wg=xMRY5&amp;pd_rd_r=5ef951c4-1245-41f1-8dcc-481a88b9ea4f&amp;pd_rd_i=0137081073&amp;psc=1">The Clean Coder</a>, and <a href="https://www.amazon.de/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164/ref=pd_bxgy_d_sccl_1/261-1125973-6519463?pd_rd_w=kPTaV&amp;content-id=amzn1.sym.46a82004-1254-4eab-a26d-553fc9d388c8&amp;pf_rd_p=46a82004-1254-4eab-a26d-553fc9d388c8&amp;pf_rd_r=3S8TKF1QE7ZF5CVDD096&amp;pd_rd_wg=xMRY5&amp;pd_rd_r=5ef951c4-1245-41f1-8dcc-481a88b9ea4f&amp;pd_rd_i=0134494164&amp;psc=1">Clean Architecture</a>. These books are classics for a reason and worth your time if you&#8217;re serious about writing better, cleaner code.</p></li><li><p><a href="https://martinfowler.com/bliki/OpportunisticRefactoring.html">Martin Fowler</a> wrote about this 13 years ago.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p></p><p></p></li></ul><h3>It Benefits Everyone &#129309;</h3><p>This isn&#8217;t just about you &#8212; regular refactoring helps the entire team. Cleaner code means fewer bugs , faster feature development, and a much easier time onboarding new developers.</p><p><strong>It&#8217;s a long-term investment in the health of your codebase.</strong></p><p>Make it a habit. Refactoring. <strong>Every. Single. Day.</strong> Encourage your team to do the same. Refactoring doesn&#8217;t have to be a solo activity &#8212; pairing up with a teammate or incorporating it into code reviews can help spread the practice across the whole team.</p><p>If you&#8217;re not refactoring regularly, your codebase is slowly becoming harder to manage. Start making small, daily improvements and see how much easier life gets &#8212; for you and your team. Your future self will thank you &#128522;.</p><p></p><div><hr></div><p><em><strong>Disclaimer:</strong></em> Take everything here with a grain of salt &#8212; this is just my opinion based on my experience. Every codebase is unique, and what works for one may not work for another. Always approach advice with critical thinking and adapt it to your context.</p><div><hr></div><p><strong>Thanks for reading!</strong> Now it&#8217;s your turn &#8212; commit to just 20 minutes of refactoring each day and start transforming your codebase. Your team and your future self will be grateful!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/if-youre-not-refactoring-every-day/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/if-youre-not-refactoring-every-day/comments"><span>Leave a comment</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Due to the COVID-triggered increase in traffic by orders of magnitude.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Thanks to Reddit user <a href="https://www.reddit.com/user/dAnjou/">dAnjou</a> for the hint</p></div></div>]]></content:encoded></item><item><title><![CDATA[Debugging 🔍 - Reduce ✂️ or Rebuild 🔨?]]></title><description><![CDATA[Choosing Between Removing Dependencies or Incrementally Adding Parts to Solve Issues]]></description><link>https://verbosemode.dev/p/debugging-reduce-or-rebuild</link><guid isPermaLink="false">https://verbosemode.dev/p/debugging-reduce-or-rebuild</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Thu, 19 Sep 2024 10:54:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ifE8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As developers, problem-solving is part of the job. Some bugs are easy, others require a fresh perspective after a good night&#8217;s sleep &#128564;. <strong>But when a problem is deeply hidden in your code, isolating it is the first step.</strong></p><p>Two approaches can help: removing parts of the system to reveal the issue (<em>via negativa<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></em>), or building it up incrementally (<em>via positiva</em>). These methods, known as <strong>divide and conquer</strong> or <strong>incremental debugging</strong>, are essential tools for tackling complex problems. <strong>Let&#8217;s explore how they work using a simple event-driven system as an example.</strong></p><p>Say you have an application that receives events, parses them, applies some business logic, writes to a database, and then publishes events.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vFd0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vFd0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 424w, https://substackcdn.com/image/fetch/$s_!vFd0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 848w, https://substackcdn.com/image/fetch/$s_!vFd0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 1272w, https://substackcdn.com/image/fetch/$s_!vFd0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vFd0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png" width="283" height="398" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:398,&quot;width&quot;:283,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A simple diagram showing a system receiving events, processing them, saving in the database and then publishing events.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="A simple diagram showing a system receiving events, processing them, saving in the database and then publishing events." title="A simple diagram showing a system receiving events, processing them, saving in the database and then publishing events." srcset="https://substackcdn.com/image/fetch/$s_!vFd0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 424w, https://substackcdn.com/image/fetch/$s_!vFd0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 848w, https://substackcdn.com/image/fetch/$s_!vFd0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.png 1272w, https://substackcdn.com/image/fetch/$s_!vFd0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F987229c1-3fd2-4ad6-84e4-c98603d63654_283x398.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><figcaption class="image-caption">Simple system for our discussion.</figcaption></figure></div><p></p><div><hr></div><h2>Via Negativa (Divide and Conquer): Isolate by Removing Dependencies &#9986;&#65039;</h2><p><strong>TL;DR:</strong> Start with your full system and gradually remove parts to isolate the issue.</p><p>Via negativa, often known as divide and conquer, involves starting with your complete system and gradually removing parts. After each step, check if the problem remains, disappears, or changes.</p><ul><li><p><strong>If the problem doesn&#8217;t change</strong>, the removed part is probably not involved.</p></li><li><p><strong>If the problem disappears</strong>, the removed part is likely the culprit, but continue adding the parts back one by one to confirm.</p></li><li><p><strong>If the problem changes</strong>, the removed part contributes to the issue.</p></li></ul><p>This can be done at the code layer (classes, methods, lines of code) or component level (e.g., database, messaging).</p><p>For example, if you suspect the business logic is causing the issue, remove the event consumption component first, then the mapping logic. If the bug remains, you&#8217;ve eliminated those as causes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ifE8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ifE8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 424w, https://substackcdn.com/image/fetch/$s_!ifE8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 848w, https://substackcdn.com/image/fetch/$s_!ifE8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 1272w, https://substackcdn.com/image/fetch/$s_!ifE8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ifE8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png" width="892" height="459" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:459,&quot;width&quot;:892,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Left: same diagram as at the beginning of the article. Middle: same dirgram without the event receiver. Right: diagram without event receiver and publisher.&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="Left: same diagram as at the beginning of the article. Middle: same dirgram without the event receiver. Right: diagram without event receiver and publisher." title="Left: same diagram as at the beginning of the article. Middle: same dirgram without the event receiver. Right: diagram without event receiver and publisher." srcset="https://substackcdn.com/image/fetch/$s_!ifE8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 424w, https://substackcdn.com/image/fetch/$s_!ifE8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 848w, https://substackcdn.com/image/fetch/$s_!ifE8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.png 1272w, https://substackcdn.com/image/fetch/$s_!ifE8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6ebcc0-0f0f-4809-a59a-5f4c100aba6a_892x459.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">Removing parts of the system step by step.</figcaption></figure></div><p><strong>If the problem persists, continue removing components like event publishing or database interactions.</strong> Adding logging or unit tests helps pinpoint the failure. Track key points or test individual methods for better visibility.</p><p>If the problem disappears after a particular step, repeat the process by focusing on the removed component to isolate the faulty code or functionality.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">verbosemode is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div><hr></div><h2>Via Positiva (Incremental Debugging): Isolate by Adding Parts &#128296;</h2><p><strong>TL;DR:</strong> Start with a minimal project and gradually add parts until the problem appears.</p><p>Via positiva, or <strong>incremental debugging</strong>, works in reverse. You start with a minimal setup and incrementally add parts of your code until the problem surfaces.</p><p>This approach is <strong>great when adding a new feature that doesn&#8217;t behave as expected</strong>. There might be hidden interactions between the existing code and the new addition. For instance, if you're adding tracing and traces aren&#8217;t showing up, is the issue with the implementation, or is a dependency pulling in an incompatible version?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bi-i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bi-i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 424w, https://substackcdn.com/image/fetch/$s_!Bi-i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 848w, https://substackcdn.com/image/fetch/$s_!Bi-i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 1272w, https://substackcdn.com/image/fetch/$s_!Bi-i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bi-i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png" width="721" height="350" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:350,&quot;width&quot;:721,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!Bi-i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 424w, https://substackcdn.com/image/fetch/$s_!Bi-i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 848w, https://substackcdn.com/image/fetch/$s_!Bi-i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.png 1272w, https://substackcdn.com/image/fetch/$s_!Bi-i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13b9bac-8999-4e2d-bbb0-4e1393d341ca_721x350.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">Adding components step by step shows how they interact with each other, visible or invisible.</figcaption></figure></div><p>In cases like this, via negativa might be impractical. Instead, <strong>create a new service with just the essential parts</strong>: consume messages, log them, and publish events&#8212;nothing more. You can run this locally and debug step by step.</p><p>Adding parts back incrementally helps identify which component introduces the issue. This method builds complexity in a controlled way, making it easier to pinpoint interactions or dependencies that cause the bug.</p><p><strong>By recreating the problem in a simplified environment, you can isolate the root cause and test fixes with minimal interference.</strong></p><div><hr></div><h2>Wrapping Up &#127873;</h2><p>The approach you choose depends on the problem. If you&#8217;re troubleshooting an existing system, <strong>divide and conquer</strong> (removing parts) works well. For new features, <strong>incremental debugging</strong> (adding parts) helps you build complexity until the issue surfaces.</p><p><strong>Both methods make complex problems easier to tackle.</strong></p><p><strong>Thanks for reading!</strong> I hope this helped you think through new ways to approach problem-solving in code.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/debugging-reduce-or-rebuild?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/debugging-reduce-or-rebuild?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/debugging-reduce-or-rebuild?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p><em>I like these philosophical concepts as they are "abstract base classes" for the concrete debugging strategies. While they work well for code, their principles apply to non-code problems, too.</em></p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Scalability Cheat Sheet #2 - When Things go Wrong and Partitioning]]></title><description><![CDATA[Tackling Replication Lag &#9203;, Write Conflicts &#9876;&#65039;, and Partitioning &#129513;]]></description><link>https://verbosemode.dev/p/scalability-cheat-sheet-2-things</link><guid isPermaLink="false">https://verbosemode.dev/p/scalability-cheat-sheet-2-things</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Wed, 11 Sep 2024 11:15:11 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="5616" height="3744" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3744,&quot;width&quot;:5616,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;assorted-color neckties&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="assorted-color neckties" title="assorted-color neckties" srcset="https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 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">Partitioning: like the Sorting Hat, splitting data into distinct houses, all working towards magical scalability! - Photo by <a href="true">Rhii Photography</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Building on the concepts covered in the <a href="https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics">first part</a>, we&#8217;ll explore how to manage   replication lag, resolve write conflicts, and efficiently partition data across multiple nodes.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e12b7b98-87d2-4252-81da-137910933a0c&quot;,&quot;caption&quot;:&quot;Scalability is a key non-functional requirement that can sometimes feel a bit elusive, especially when you're diving into system design for the first time. This cheat sheet pulls together essential concepts of scalability in a practical, opinionated guide.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Scalability Cheat Sheet #1 - From Basics to Replication&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-09-06T13:59:52.147Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:148574626,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>These topics are critical for ensuring that your system remains responsive, reliable, and scalable as it grows.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">verbosemode is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><strong>In this post, you'll learn about:</strong></p><ul><li><p><strong>&#9203; Replication Lag</strong>: Understanding delays in data synchronization and how to mitigate them.</p></li><li><p><strong>&#9876;&#65039; Write Conflicts</strong>: How to handle conflicts in multi-leader and leaderless modes.</p></li><li><p><strong>&#128295; Fail-over Strategies</strong>: Ensuring continuous availability during node failures.</p></li><li><p><strong>&#129513; Partitioning</strong>: Dividing data efficiently across multiple nodes to handle Big Data and avoid hotspots &#127798;&#65039;.</p><p></p></li></ul><p></p><div><hr></div><h2>Replication Lag &#9203;: Understanding Delays in Data Synchronization</h2><p><strong>Replication lag occurs when replicas have stale data due to delayed updates,</strong> common in async setups. It can also occur in leaderless setups depending on the consistency settings.</p><p>Leaderless systems like Amazon DynamoDB can mitigate lag through quorum reads and writes. In most systems, lag is typically only a few seconds, but it can be longer depending on performance vs. consistency needs.</p><p><strong>Basic considerations &#128161;:</strong></p><ul><li><p><strong>Some applications may not care about replication lag</strong>, depending on the use case.</p></li><li><p>If you always need strong consistent data, use synchronous replication.</p></li><li><p><strong>A basic workaround:</strong> Divide reads into categories. For strong consistency, read from the leader; otherwise, read from replicas. For example, this is supported in Google Cloud Spanner.</p></li></ul><p><strong>Types of Consistency &#129521;:</strong></p><ul><li><p><strong>Read-After-Write &#128218;:</strong> Ensures that the user who wrote <code>x</code> never reads an older version of <code>x</code> after its write. Suitable when users mainly write small portions, like their profile.</p></li><li><p><strong>Monotonic Reads &#8599;&#65039;:</strong> Ensures that if a user reads <code>x</code> at a given time, they won&#8217;t see older versions of <code>x</code> later. Often implemented by assigning the same replica to a user, e.g., based on a hash of the user ID. This method can fail if the assigned replica is down.</p></li><li><p><strong>Causal Consistency &#128279;:</strong> Ensures users see data in the correct causal order, such as never seeing an answer before a question.</p></li><li><p><strong>Configurable Consistency Modes:</strong> Many databases allow you to adjust consistency levels, giving flexibility to meet specific needs. Examples include Amazon DynamoDB, Apache Cassandra, MongoDB, Cosmos DB, Riak, and Couchbase.</p></li><li><p><strong>Leaderless Systems &#129335;&#8205;&#9794;&#65039;:</strong> Rely on additional processes to manage consistency and mitigate lag:</p><ul><li><p><strong>Read Repair &#128105;&#8205;&#128295;:</strong> Fixes inconsistencies during read operations by updating stale replicas with the latest data.</p></li><li><p><strong>Anti-Entropy Processes &#128736;&#65039;:</strong> Periodically synchronize replicas to ensure they converge to the same data.</p></li></ul></li></ul><p><strong>We will discover Consistency in the upcoming Cheat Sheet post in more detail.</strong></p><p>As we&#8217;ve seen, <strong>replication lag is a manageable challenge with the right consistency models and strategies</strong>. </p><div><hr></div><h2>Write Conflicts &#9876;&#65039; and Their Resolution: Keeping Your Data Consistent</h2><p>Write conflicts happen in multi-leader and leaderless modes when nodes accept writes independently. Resolving these conflicts is key to maintaining consistency across replicas.</p><p><strong>How They Happen &#128269;:</strong></p><ul><li><p><strong>Concurrent Writes &#128221;:</strong> Multiple nodes write to the same data simultaneously without coordination.</p></li><li><p><strong>Network Partitions &#127760;:</strong> Nodes become temporarily disconnected and accept conflicting writes.</p></li><li><p><strong>Timing Issues &#9201;&#65039;:</strong> Variations in the timing of updates can cause mismatched data versions across nodes.</p></li></ul><p><strong>Common Resolution Strategies &#128657;:</strong></p><ul><li><p><strong>Avoiding Conflicts Altogether:</strong> Assigning a responsible leader for each record can help avoid conflicts, similar to a partitioned leader approach. This approach fails if the leader goes down.</p></li><li><p><strong>Last Write Wins &#9201;&#65039;:</strong> Each write is timestamped, and the highest timestamp wins. Drawbacks include potential data loss if writes are overwritten.</p></li><li><p><strong>Merging Data &#129730;:</strong> If feasible, merge conflicting writes. Often requires additional application logic.</p></li><li><p><strong>Conflict-Free Replicated Data Types (CRDTs) &#129302;:</strong> Data structures designed to resolve conflicts automatically. Complex and less supported in many databases.</p></li></ul><p>Align your conflict resolution method with your application's specific needs, whether prioritizing speed, simplicity, or data accuracy.</p><div><hr></div><h2>Failover &#128295;: Ensuring Continuous Availability During Failures</h2><p>Failover is the process of switching to a backup when a primary or follower node fails, ensuring high availability and minimal downtime in distributed systems. It covers both leader and follower nodes to maintain seamless operation.</p><ul><li><p><strong>Failed Followers:</strong> Mostly easy to recover. After the follower becomes available again, it requests all data from a leader that has been written since the failure. This assumes that the follower was previously synchronized up to a specific point; longer downtimes or high data volumes can complicate recovery.</p></li><li><p><strong>Leader Failover &#128081;:</strong> More complex.</p><ul><li><p><strong>Automatic:</strong> The system promotes a follower to a leader.</p></li><li><p><strong>Manual:</strong> A human decides who will be the new leader.</p></li><li><p><strong>Split Brain &#129504;:</strong> Must be avoided to prevent multiple nodes from incorrectly assuming the leader role simultaneously, which can lead to data inconsistencies.</p></li><li><p><strong>Failure Detection:</strong> It is challenging to determine if a leader failed. Typically, a timeout is used; if the leader does not respond within a set number of seconds, it is assumed to have failed.</p></li><li><p><strong>Consensus Algorithms &#129309;:</strong> Used for leader election but are a topic on their own and out of scope here. Common algorithms include <a href="https://en.wikipedia.org/wiki/Raft_(algorithm)">Raft</a> and <a href="https://en.wikipedia.org/wiki/Paxos_(computer_science)">Paxos</a>.</p></li></ul></li></ul><p></p><p>Handling write conflicts is crucial for maintaining consistency in multi-leader and leaderless setups. With these resolution strategies in mind, let&#8217;s move on to explore failover strategies</p><div><hr></div><h2>Partitioning &#129513;: Dividing and Conquering Data </h2><p>Partitioning <strong>divides data across multiple nodes</strong> using a partitioning key, e<strong>ssential for managing large datasets</strong> where a single machine can't handle all the data &#8212;common in Big Data scenarios.</p><p><strong>How it works:</strong></p><ul><li><p>Each record belongs to a partition (shard)</p></li><li><p>Partitions are typically replicated for availability and fault tolerance. </p></li><li><p><strong>The goal is to distribute both data and load evenly across nodes</strong>, avoiding skewed partitions (uneven data or load) and hotspots &#127798;&#65039; (partitions bearing most of the load).</p></li><li><p>Sometimes called <strong>Sharding</strong></p></li></ul><p></p><h3><strong>Key-Value Data Partitioning &#128273;</strong></h3><ul><li><p><strong>Partitioning by Key Range &#128207;:</strong> Assigns each partition a range of keys (e.g., A-D, E-F). </p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qspK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qspK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 424w, https://substackcdn.com/image/fetch/$s_!qspK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 848w, https://substackcdn.com/image/fetch/$s_!qspK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 1272w, https://substackcdn.com/image/fetch/$s_!qspK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qspK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png" width="642" height="247" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:247,&quot;width&quot;:642,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19397,&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_!qspK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 424w, https://substackcdn.com/image/fetch/$s_!qspK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 848w, https://substackcdn.com/image/fetch/$s_!qspK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.png 1272w, https://substackcdn.com/image/fetch/$s_!qspK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75210305-1f1a-4802-bf6b-c87f0d1aab60_642x247.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">Partitioning by Key Range</figcaption></figure></div><p> </p><ul><li><p>Ranges can vary in size and may be set manually or automatically.</p></li><li><p><strong>&#9989; </strong>Maintains sorted data, <strong>making range queries straightforward </strong></p></li><li><p>&#10060; Can lead to hotspots &#127798;&#65039; if many keys fall within narrow ranges.</p><p> </p></li></ul></li><li><p><strong>Partitioning by Hash Key &#127922;:</strong> Uses a hash of the key to determine the partition.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s_81!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s_81!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 424w, https://substackcdn.com/image/fetch/$s_!s_81!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 848w, https://substackcdn.com/image/fetch/$s_!s_81!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 1272w, https://substackcdn.com/image/fetch/$s_!s_81!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s_81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png" width="561" height="341" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:341,&quot;width&quot;:561,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26466,&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_!s_81!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 424w, https://substackcdn.com/image/fetch/$s_!s_81!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 848w, https://substackcdn.com/image/fetch/$s_!s_81!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.png 1272w, https://substackcdn.com/image/fetch/$s_!s_81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ef4558c-537f-4e36-a12a-0c82a5f30602_561x341.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">Partitioning by Hash Key</figcaption></figure></div><p></p><ul><li><p>&#9989; Ensuring even distribution across nodes.</p></li><li><p>&#9989; This <strong>gives well-balanced data, </strong>depending on the hash function.</p></li><li><p>&#10060; Makes <strong>range queries inefficient</strong> due to random distribution.</p></li></ul></li></ul><p></p><p><strong>Challenges and Solutions &#128679;</strong></p><ul><li><p><strong>Reducing Hotspots &#127798;&#65039;:</strong> Prefixing keys with numbers or other identifiers (e.g., 00-99) can spread them across multiple partitions, distributing the load more evenly. However, this complicates reads, requiring the application to merge data from various partitions.</p></li><li><p><strong>Secondary Indexes &#128218;:</strong> Secondary indexes don't naturally align with partitions since they're independent of the partitioning key. They can be handled by:</p><ul><li><p><strong>Local Index (Partitioning by Document) &#128196;:</strong> Each partition maintains its index. </p><ul><li><p>Queries must hit all partitions as the client can't know where the data resides.</p></li><li><p>Optimizations like routing information or query hints can sometimes reduce the need to query every partition.</p></li></ul></li><li><p><strong>Global Index (Partitioning by Term) &#127760;:</strong> The index is partitioned by the index keys themselves, allowing more targeted queries but complicating writes as they may span multiple partitions.</p></li></ul></li></ul><p></p><h3>Rebalancing &#9878;&#65039;: Maintaining Even Distribution</h3><p>As data grows or nodes are added, partitions can become unbalanced, necessitating rebalancing to distribute the load evenly:</p><ul><li><p><strong>Fixed Number of Partitions &#128230;:</strong></p><ul><li><p>Set a fixed number of partitions upfront, often more than the number of nodes.</p></li><li><p>New nodes take over some partitions; departing nodes return them.</p></li><li><p>Too many partitions increase overhead, while too few limit scalability.</p></li></ul></li><li><p><strong>Dynamic Number of Partitions &#128260;:</strong></p><ul><li><p>Partitions split if they exceed a size threshold or merge if they shrink too much.</p></li><li><p>Works well for key range partitioning but can cause frequent rebalancing during growth.</p></li></ul></li><li><p><strong>Rebalancing Costs &#128184;:</strong></p><ul><li><p>Moving data across partitions can be resource-intensive.</p></li><li><p>Prefer manual rebalancing during low-traffic periods to minimize impact.</p></li></ul></li></ul><p></p><div><hr></div><h2>Key Takeaways &#128204;</h2><ul><li><p><strong>Replication Lag &#9203;</strong> is a common issue in asynchronous and leaderless setups, where replicas may have outdated data due to delayed updates, affecting data consistency.</p></li><li><p><strong>Consistency Models:</strong> Various consistency levels, such as Read-After-Write, Monotonic Reads, and Causal Consistency, address different needs and scenarios in distributed systems.</p></li><li><p><strong>Write Conflicts &#9876;&#65039;</strong> occur in multi-leader and leaderless modes due to concurrent writes, network partitions, or timing discrepancies, requiring strategies like "Last Write Wins," data merging, or CRDTs for resolution.</p></li><li><p><strong>Failover &#128295;</strong> ensures high availability by switching to backups during node failures. Leader failover is particularly complex and demands robust processes to avoid split brain scenarios and ensure seamless leader election.</p></li><li><p><strong>Partitioning &#129513;</strong> divides data across multiple nodes, essential for handling large datasets in distributed systems, and requires careful management to distribute data and load evenly, avoiding hotspots &#127798;&#65039;.</p></li><li><p><strong>Rebalancing &#9878;&#65039;</strong> is crucial as data grows or when adding nodes, redistributing data to maintain balance and efficiency, with strategies for fixed or dynamic partition numbers to adapt to changing loads.</p></li></ul><p></p><div><hr></div><p><strong>If you found this guide helpful, please share it and drop your thoughts in the comments below&#8212;I'd love to hear your feedback!</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/scalability-cheat-sheet-2-things/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/scalability-cheat-sheet-2-things/comments"><span>Leave a comment</span></a></p><p>In the upcoming post, I&#8217;ll pull together my notes on <strong>Consistency</strong> to create <strong>a new cheat sheet.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">verbosemode is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Scalability Cheat Sheet #1 - From Basics to Replication]]></title><description><![CDATA[Scalability Basics, Vertical vs. Horizontal Scaling, and Introduction to Replication &#128101;]]></description><link>https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics</link><guid isPermaLink="false">https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Fri, 06 Sep 2024 13:59:52 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="4608" height="3456" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3456,&quot;width&quot;:4608,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;a group of star wars stormtroopers are lined up&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="a group of star wars stormtroopers are lined up" title="a group of star wars stormtroopers are lined up" srcset="https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1650363085627-e8a4fd3df996?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8Y2xvbmUlMjB0cm9vcGVyfGVufDB8fHx8MTcyNTYzMDg3MHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 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">Photo by <a href="true">Darren Mosher</a> on <a href="https://unsplash.com">Unsplash</a> - The Empire Got Replication Right</figcaption></figure></div><p></p><p><strong>Scalability is a key non-functional requirement</strong> that can sometimes feel a bit elusive, especially when you're diving into system design for the first time. This cheat sheet pulls together essential concepts of scalability in a practical, opinionated guide.</p><p>In this <strong>first part</strong>, we'll focus on the <strong>basics of scaling and replication</strong>, setting a strong foundation for anyone looking to build or optimize scalable systems.</p><p><strong>You'll learn about:</strong></p><ul><li><p><strong>&#127959;&#65039; Vertical vs. Horizontal Scaling</strong>: The pros and cons of scaling up versus scaling out.</p></li><li><p><strong>&#128081; Leader-Based Replication</strong>: Delve into single-leader and multi-leader setups, understanding how they manage consistency and scale.</p></li><li><p><strong>&#129335;&#8205;&#9794;&#65039; Leaderless Replication</strong>: Explore how leaderless systems handle writes and manage conflicts through quorum reads and writes.</p></li><li><p><strong>&#128260; Replication Methods</strong>: Compare synchronous, semi-synchronous, and asynchronous replication to balance performance and consistency.</p></li></ul><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f1ebdbff-49c6-4f59-a593-1dd37c08fbf4&quot;,&quot;caption&quot;:&quot;Building on the concepts covered in the first part, we&#8217;ll explore how to manage replication lag, resolve write conflicts, and efficiently partition data across multiple nodes.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Scalability Cheat Sheet #2 - When Things go Wrong and Partitioning&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-09-11T11:15:11.160Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/scalability-cheat-sheet-2-things&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:148574669,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><div><hr></div><h3>What is Scalability in the First Place? &#128640;</h3><p>Scalability is <strong>all about ensuring your system can handle increasing loads </strong>&#8212;whether doubling, tripling, or more&#8212;<strong>without a drop in performance</strong> or a steep rise in costs. It&#8217;s crucial for sustaining efficiency as demand grows.</p><p>There are two main strategies:</p><p></p><h4>&#127959;&#65039; Vertical Scaling</h4><p>Vertical Scaling means adding more resources (CPU, RAM, disk space, etc.) to a single host. It's less favored these days due to several downsides &#10060;:</p><ul><li><p><strong>Cost and Performance Imbalance:</strong> Costs can rise disproportionately with performance gains.</p></li><li><p><strong>Physical Limits:</strong> There's a ceiling to how much you can scale a single machine, constrained by technology and physics.</p></li><li><p><strong>Downtime:</strong> Upgrades, like adding a new CPU, may require downtime.</p></li><li><p><strong>Limited Flexibility:</strong> Scaling down isn't straightforward, making it hard to respond to decreased loads.</p></li></ul><p></p><h4>&#127760; Horizontal Scaling</h4><p>Horizontal Scaling involves adding more hosts and distributing the load across them. It has <strong>several advantages &#9989; over vertical scaling:</strong></p><ul><li><p><strong>Cost-Effectiveness:</strong> You can use off-the-shelf components (e.g., deploying 24 machines with 4-core CPUs instead of a single 96-core machine).</p></li><li><p><strong>Flexibility:</strong> It can adapt to traffic increases and decreases.</p></li><li><p><strong>Automation:</strong> Scaling can be fully automated, especially in cloud environments.</p></li></ul><p>However, horizontal scaling also introduces complexity, such as managing distributed storage and computing, and handling increased network traffic.</p><p><strong>In the age of cloud computing, horizontal scaling is often the preferred approach.</strong> Everything mentioned in this post will focus on horizontal scaling and its challenges.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">verbosemode is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div><hr></div><h3>Replication &#128111;&#8205;&#9794;&#65039;: Keeping Your Data Available</h3><p>Replication is a key approach in horizontal scaling, where the <strong>basic idea is to copy data across multiple nodes.</strong> This setup offers several <strong>advantages</strong> &#9989;:</p><ul><li><p><strong>Load Distribution:</strong> Each node only handles a fraction of the requests, balancing the workload.</p></li><li><p><strong>Fault Tolerance:</strong> If one node fails, requests can be redirected to another, improving system resilience.</p></li><li><p><strong>Reduced Latency:</strong> Clients can connect to geographically closer nodes, which reduces latency.</p></li><li><p><strong>Increased Data Safety:</strong> With multiple copies, the risk of data loss decreases.</p></li></ul><p>However, replication introduces <strong>new challenges</strong> &#9888;&#65039;:</p><ul><li><p><strong>Increased Complexity:</strong> The overall system becomes more complex, both in terms of architecture and data management.</p></li><li><p><strong>Network Dependencies:</strong> Many operations now rely on network communication, adding potential points of failure and latency.</p></li><li><p><strong>Data Consistency:</strong> Keeping data synchronized across nodes is a major concern&#8212;should you strive for perfect consistency, or is eventual consistency acceptable?</p></li></ul><p>Different replication approaches can be viewed through the lens of these challenges. Some setups designate specific nodes to manage consistency, leading to single-leader or multi-leader replication. Alternatively, leaderless replication takes a different approach altogether.</p><p>There&#8217;s also another axis to consider: how nodes communicate with each other. This gives rise to synchronous, semi-synchronous, and asynchronous replication models.</p><div id="datawrapper-iframe" class="datawrapper-wrap outer" data-attrs="{&quot;url&quot;:&quot;https://datawrapper.dwcdn.net/UOL5z/3/&quot;,&quot;thumbnail_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2961bc75-9bd3-41f1-b205-e6d6abf47587_1260x660.png&quot;,&quot;thumbnail_url_full&quot;:&quot;&quot;,&quot;height&quot;:340,&quot;title&quot;:&quot;Replication Matrix&quot;,&quot;description&quot;:&quot;&quot;}" data-component-name="DatawrapperToDOM"><iframe id="iframe-datawrapper" class="datawrapper-iframe" src="https://datawrapper.dwcdn.net/UOL5z/3/" width="730" height="340" frameborder="0" scrolling="no"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();</script></div><p></p><h4>Leader-Based Replication &#128081;</h4><p>Leader-based replication scales systems by designating leaders to manage write operations, which are then propagated to followers. This approach balances load, improves read performance, and enhances fault tolerance but also presents challenges related to consistency and failure management.</p><p><strong>How It Works:</strong></p><ul><li><p><strong>Leaders and Followers:</strong></p><ul><li><p>The <strong>Leader</strong> &#128081; handles all write operations and ensures changes are replicated to other nodes.</p></li><li><p><strong>Followers</strong> receive updates from the leader and typically serve read requests, helping to distribute the load.</p></li></ul></li><li><p><strong>Replication Methods:</strong></p><ul><li><p><strong>Synchronous Replication:</strong> Writes are only considered successful when all followers have applied them, ensuring strong consistency but potentially increasing write latency.</p></li><li><p><strong>Semi-Synchronous Replication:</strong> A write is successful when a subset of followers (often just one) applies the change, offering a middle ground between consistency and performance.</p></li><li><p><strong>Asynchronous Replication:</strong> Writes are successful as soon as the leader processes them, with followers catching up later, improving performance but risking consistency issues due to replication lag.</p></li></ul></li></ul><p><strong>&#9989; Advantages of Leader-Based Replication:</strong></p><ul><li><p><strong>Improved Scalability:</strong> Distributing read operations across multiple followers can significantly increase the system's ability to handle larger loads.</p></li><li><p><strong>Fault Tolerance:</strong> Followers can act as backups and be promoted to leaders if the current leader fails, providing resilience against node failures.</p></li><li><p><strong>Reduced Latency:</strong> By directing read operations to followers closer to the clients, latency can be reduced, enhancing user experience.</p></li></ul><p><strong>&#10060; Downsides of Leader-Based Replication:</strong></p><ul><li><p><strong>Replication Lag:</strong> Particularly with asynchronous replication, followers may not always be in sync with the leader, leading to stale reads and inconsistencies.</p></li><li><p><strong>Single Point of Failure:</strong> In single-leader configurations, the leader is a critical failure point, which can halt write operations until a new leader is elected.</p></li><li><p><strong>Conflict Resolution:</strong> In multi-leader setups, concurrent writes on different leaders can lead to conflicts, requiring strategies to resolve discrepancies between nodes.</p></li><li><p><strong>Split Brain:</strong> Network issues or failures can cause multiple nodes to incorrectly assume the leader role, resulting in data inconsistencies.</p></li></ul><p></p><h4>Single-Leader Replication &#129351;</h4><p>In this scenario, there <strong>exists exactly one leader</strong>.</p><p><strong>&#9989; Advantages (compared to multi-leader):</strong></p><ul><li><p><strong>Simplicity and Predictability:</strong> The architecture is straightforward, making it easier to implement, debug, and reason about system behavior.</p></li><li><p><strong>Consistency Management:</strong> Having a single leader ensures a clear source of truth for data writes, simplifying consistency management.</p></li></ul><p><strong>&#10060; Downsides (compared to multi-leader):</strong></p><ul><li><p><strong>Single Point of Failure:</strong> The leader is a critical component; if it goes down, writes are paused until a new leader is elected, which can cause downtime.</p></li><li><p><strong>Scalability Limits on Writes:</strong> Since all writes funnel through a single leader, there's an upper limit to write throughput. Especially with synchronous replication, where every follower must confirm the write, leading to higher latency.</p></li></ul><p></p><h4>Multi-Leader Replication &#129309;</h4><p>Here, we can have an <strong>arbitrary number of leaders</strong>. The number of leaders also may change anytime.</p><p><strong>&#9989; Advantages (compared to single-leader):</strong></p><ul><li><p><strong>Enhanced Write Availability:</strong> Writes can be accepted by multiple leaders, reducing the dependency on any single node and increasing write availability.</p></li><li><p><strong>Better Geographical Distribution:</strong> Leaders in different locations can handle writes closer to their respective regions, reducing latency for distributed users.</p></li><li><p><strong>Improved Fault Tolerance:</strong> If one leader fails, other leaders can continue to handle writes, reducing the impact of node failures on the system's availability.</p></li></ul><p><strong>&#10060; Downsides (compared to single-leader):</strong></p><ul><li><p><strong>Conflict Resolution Complexity:</strong> When the same data is written concurrently on different leaders, conflicts can occur, requiring complex conflict resolution strategies.</p></li><li><p><strong>Increased Operational Complexity:</strong> Managing multiple leaders adds complexity to the system, including ensuring all leaders remain consistent and coordinating writes between them.</p></li><li><p><strong>Split Brain Scenarios:</strong> Multi-leader setups are more susceptible to split brain issues during network partitions, where isolated leaders may independently accept writes, leading to data divergence.</p></li></ul><p></p><p>Leader-based replication improves scalability but has drawbacks like single points of failure. Leaderless replication offers an alternative, with different trade-offs and solutions.</p><div><hr></div><p></p><h4>Leaderless Replication &#129335;&#8205;&#9794;&#65039;</h4><p>As the name suggests, in leaderless replication, there are no designated leaders&#8212;every node can accept writes, effectively making every node a leader.</p><p><strong>How It Works:</strong></p><ul><li><p><strong>Quorum Concept:</strong></p><ul><li><p>Clients perform read and write operations on multiple nodes, using a concept called <strong>quorum</strong>:</p></li><li><p>With <code>n</code> total nodes, clients write to <code>w</code> nodes and read from <code>r</code> nodes.</p></li><li><p>All data is versioned with timestamps or version numbers.</p></li><li><p>For consistency, <code>w + r &gt; n</code> ensures reads always include the latest version.</p></li><li><p><strong>Example</strong>: With <code>n = 5</code>, <code>w = 3</code>, and <code>r = 3</code>, writing to three nodes means two might have outdated versions, but reading from three nodes ensures at least one has the current version.</p></li><li><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RR1l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RR1l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 424w, https://substackcdn.com/image/fetch/$s_!RR1l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 848w, https://substackcdn.com/image/fetch/$s_!RR1l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 1272w, https://substackcdn.com/image/fetch/$s_!RR1l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RR1l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png" width="407" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:407,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!RR1l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 424w, https://substackcdn.com/image/fetch/$s_!RR1l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 848w, https://substackcdn.com/image/fetch/$s_!RR1l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.png 1272w, https://substackcdn.com/image/fetch/$s_!RR1l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09bfbeb5-b4b8-449d-8602-a555ab695f8a_407x480.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">Quorum with n=3, r=2 and w=2</figcaption></figure></div></li></ul><p></p></li><li><p><strong>Failure Tolerance:</strong></p><ul><li><p>If <code>w &lt; n</code>, the system remains operational even if some nodes fail (e.g., with <code>n = 5</code> and <code>w = 3</code>, up to two nodes can fail without impacting availability).</p></li><li><p>Similarly, if <code>r &lt; n</code>, the system can tolerate node failures during reads.</p></li></ul></li></ul><p></p><p><strong>&#9989; Advantages (compared to leader-based replication):</strong></p><ul><li><p><strong>No Leader Failover Required:</strong> Eliminates the need for leader election and failover processes.</p></li><li><p><strong>High Resilience:</strong> Continues functioning even with multiple node failures.</p></li></ul><p><strong>&#10060; Downsides (compared to leader-based replication):</strong></p><ul><li><p><strong>Complex Conflict Resolution:</strong> Handling write conflicts is more complex since all nodes accept writes independently.</p></li><li><p><strong>Increased Latency:</strong> Quorum reads and writes can introduce additional latency due to interactions with multiple nodes.</p></li></ul><p>Leaderless replication promotes resilience with no single point of failure but complicates conflict resolution and may increase latency. It's ideal for high-availability needs but requires careful management of data consistency.</p><div><hr></div><h3>Sync vs. Async Replication &#128260;: Balancing Consistency and Performance</h3><p>Replication modes&#8212;synchronous, semi-synchronous, and asynchronous&#8212;affect how writes are handled across nodes, balancing consistency and performance. Choose based on whether you need immediate consistency or faster writes.</p><p></p><h4>Synchronous Replication</h4><p>Synchronous Replication is the simplest mode. In this setup, the leader waits until all replicas have executed the write.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WNzn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WNzn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 424w, https://substackcdn.com/image/fetch/$s_!WNzn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 848w, https://substackcdn.com/image/fetch/$s_!WNzn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 1272w, https://substackcdn.com/image/fetch/$s_!WNzn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WNzn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png" width="521" height="460" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:460,&quot;width&quot;:521,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!WNzn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 424w, https://substackcdn.com/image/fetch/$s_!WNzn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 848w, https://substackcdn.com/image/fetch/$s_!WNzn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.png 1272w, https://substackcdn.com/image/fetch/$s_!WNzn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14f75b1a-62ea-4446-ac2f-8eed25422fbc_521x460.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">Flow of synchronous replication</figcaption></figure></div><p><strong>&#9989; Advantages:</strong></p><ul><li><p><strong>Strong Consistency:</strong> All replicas contain the same data immediately.</p></li><li><p><strong>Easier Fail-over:</strong> Since all replicas are in sync, any replica can become the new leader without the risk of lost writes after a leader failure.</p></li></ul><p><strong>&#10060; Downsides:</strong></p><ul><li><p>Clients must wait until all replicas complete the write</p></li><li><p>Sensitive to network latency.</p></li><li><p>One failing replica renders the system unusable for writes.</p></li><li><p>Not practical in leaderless scenarios.</p></li></ul><p><strong>Use Cases:</strong> Best for critical applications where strong consistency is paramount, like financial transactions.</p><p></p><h4>Asynchronous Replication</h4><p>In Asynchronous Replication, writes are considered successful once the leader executes the write.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ByRG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ByRG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 424w, https://substackcdn.com/image/fetch/$s_!ByRG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 848w, https://substackcdn.com/image/fetch/$s_!ByRG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 1272w, https://substackcdn.com/image/fetch/$s_!ByRG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ByRG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png" width="516" height="510" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:510,&quot;width&quot;:516,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!ByRG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 424w, https://substackcdn.com/image/fetch/$s_!ByRG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 848w, https://substackcdn.com/image/fetch/$s_!ByRG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.png 1272w, https://substackcdn.com/image/fetch/$s_!ByRG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3466e4b0-5183-4bc2-ab83-b115c4158fe4_516x510.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">Flow of asynchronous replication.</figcaption></figure></div><p><strong>&#9989; Advantages:</strong></p><ul><li><p><strong>Lower Latency on Writes:</strong> Improves system responsiveness.</p></li><li><p><strong>High Availability:</strong> The system remains operational even if some nodes fail.</p></li></ul><p><strong>&#10060; Downsides:</strong></p><ul><li><p><strong>Replication Lag:</strong> Nodes can get out of sync (we will discuss <em>Replication Lag</em> in part 2).</p></li><li><p><strong>Risk of Data Loss:</strong> If a leader fails, unsynced writes may be lost.</p></li></ul><p><strong>Use Cases:</strong> Suitable for applications where write speed is critical, and occasional data staleness is acceptable, like logging, analytics, or social networks.</p><p></p><h4>Semi-Synchronous Replication</h4><p>Semi-Synchronous Replication aims to get the best of both worlds. One follower per leader is synchronous, while the rest are updated asynchronously.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MseA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MseA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 424w, https://substackcdn.com/image/fetch/$s_!MseA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 848w, https://substackcdn.com/image/fetch/$s_!MseA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 1272w, https://substackcdn.com/image/fetch/$s_!MseA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MseA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png" width="491" height="492" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d159978b-0594-4c36-b697-359b0daf6253_491x492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:492,&quot;width&quot;:491,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!MseA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 424w, https://substackcdn.com/image/fetch/$s_!MseA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 848w, https://substackcdn.com/image/fetch/$s_!MseA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 1272w, https://substackcdn.com/image/fetch/$s_!MseA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd159978b-0594-4c36-b697-359b0daf6253_491x492.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p><strong>Partial Consistency:</strong> Provides "partial consistency" and reduces the risk of lost writes.</p></li><li><p><strong>Use Cases:</strong> Ideal for systems needing a balance between consistency and performance, such as content management systems or collaborative tools.</p></li></ul><p></p><p><strong>In summary, synchronous replication ensures strong consistency but can add latency, while asynchronous replication boosts performance with potential data lag. </strong>Choose based on whether your priority is consistency or speed.</p><p></p><div><hr></div><p></p><h2>Key Takeaways &#128204;</h2><p>Here are the key takeaways to solidify your understanding of scalability concepts covered in this guide.</p><ul><li><p><strong>Scalability is essential</strong> for systems to handle increasing loads efficiently without performance loss or disproportionate cost increases.</p></li><li><p><strong>Horizontal Scaling &#127760;</strong> is preferred in modern architectures, spreading the load across multiple nodes, offering flexibility and automation but adding complexity in distributed data management.</p></li><li><p><strong>Replication &#128111;&#8205;&#9794;&#65039;</strong> improves data availability and fault tolerance by duplicating data across multiple nodes, balancing load, and reducing latency for geographically distributed clients.</p></li><li><p><strong>Leader-Based Replication &#128081;</strong> involves leaders managing writes and followers handling reads, offering simplicity and consistency but posing risks of single points of failure and potential conflicts in multi-leader setups.</p></li><li><p><strong>Leaderless Replication &#129335;&#8205;&#9794;&#65039;</strong> allows any node to handle writes, enhancing resilience but complicating conflict resolution and increasing latency through quorum-based reads and writes.</p></li><li><p><strong>Replication Modes &#128260;</strong> (Synchronous, Semi-Synchronous, Asynchronous) balance trade-offs between consistency and performance; synchronous offers strong consistency, while asynchronous favors performance at the risk of data lag.</p></li></ul><p></p><div><hr></div><p><strong>If you found this guide helpful, please share it and drop your thoughts in the comments below&#8212;I'd love to hear your feedback!</strong> </p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/scalability-cheat-sheet-1-from-basics?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p><strong>Stay tuned for Part 2</strong>, where we&#8217;ll explore replication lag &#9203;, write conflicts &#9876;&#65039;, failover strategies &#128295;, and data partitioning &#129513;. </p><p>Special thanks to Nina for her great proofreading and tips! &#128522; </p><p><strong>Happy scaling, and see you in Part 2! &#128640;</strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;a7509602-c1de-4f4e-8247-89698187a037&quot;,&quot;caption&quot;:&quot;Building on the concepts covered in the first part, we&#8217;ll explore how to manage replication lag, resolve write conflicts, and efficiently partition data across multiple nodes.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Scalability Cheat Sheet #2 - When Things go Wrong and Partitioning&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-09-11T11:15:11.160Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1533462506003-13c20d204b58?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1OHx8aG9nd2FydHN8ZW58MHx8fHwxNzI2MDUyNzQxfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/scalability-cheat-sheet-2-things&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:148574669,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div>]]></content:encoded></item><item><title><![CDATA[IntelliJ Magic - Weekly Tech Tidbits #8]]></title><description><![CDATA[Discover How to Enhance Your Workflow with Syntax Highlighting, Search Anywhere, and Keyboard Shortcuts in IntelliJ IDEA]]></description><link>https://verbosemode.dev/p/intellij-magic-weekly-tech-tidbits</link><guid isPermaLink="false">https://verbosemode.dev/p/intellij-magic-weekly-tech-tidbits</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Wed, 07 Aug 2024 11:24:06 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%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi &#128075;, it's great to have you here for this issue of Weekly Tech Tidbits. As the vacation time is over (at least for me), let&#8217;s look today into increase your productivity while using IntelliJ.</p><ol><li><p><strong>Injecting Syntax Highlighting into a String &#127752;</strong></p></li><li><p><strong>Search Anywhere &#128269;</strong></p></li><li><p><strong>Keyboard Shortcuts PDF &#128196;</strong></p></li></ol><p>If you are still on vacation, check out the previous vacation special issue! &#127958;&#65039;&#128526;</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;d522c2f6-f95b-4aa2-b0e7-6c0bfe986a42&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this vacation special issue of Weekly Tech Tidbits. &#127796;&#9728;&#65039; As it's vacation time for many people, we'll share three topics that you can simply enjoy.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;SQL Murder Mystery: A Fun Way to Learn SQL- Weekly Tech Tidbits #7&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-07-17T06:00:43.895Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:146535910,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! &#128226;</p><div><hr></div><h2>Injecting Syntax Highlighting into a String &#127752;</h2><p>It's not unusual to have <code>SQL</code> or <code>JSON </code>as Strings in your code. Whether for tests or in your repositories, you might have something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OqRt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OqRt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 424w, https://substackcdn.com/image/fetch/$s_!OqRt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 848w, https://substackcdn.com/image/fetch/$s_!OqRt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 1272w, https://substackcdn.com/image/fetch/$s_!OqRt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OqRt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png" width="322" height="252" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:252,&quot;width&quot;:322,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15447,&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_!OqRt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 424w, https://substackcdn.com/image/fetch/$s_!OqRt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 848w, https://substackcdn.com/image/fetch/$s_!OqRt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.png 1272w, https://substackcdn.com/image/fetch/$s_!OqRt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c8d4e2-6779-42dd-84f1-c8eac50bc9c9_322x252.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><figcaption class="image-caption">JSON String in a Kotlin class</figcaption></figure></div><p>If your language supports multi-line strings, like Kotlin, this is already quite helpful to keep the formatting. However, you <strong>lose all the syntax information</strong>, and IntelliJ cannot help you if something is wrong with your JSON.</p><p>This is where <strong><a href="https://www.jetbrains.com/help/idea/using-language-injections.html">language injection</a></strong> comes into play. Just add a comment to your <code>String</code>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-REB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-REB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 424w, https://substackcdn.com/image/fetch/$s_!-REB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 848w, https://substackcdn.com/image/fetch/$s_!-REB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 1272w, https://substackcdn.com/image/fetch/$s_!-REB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-REB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png" width="343" height="294" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/786ffdff-452d-4433-b64b-b514836092cd_343x294.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:294,&quot;width&quot;:343,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19251,&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_!-REB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 424w, https://substackcdn.com/image/fetch/$s_!-REB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 848w, https://substackcdn.com/image/fetch/$s_!-REB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.png 1272w, https://substackcdn.com/image/fetch/$s_!-REB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F786ffdff-452d-4433-b64b-b514836092cd_343x294.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">JSON highlighting in a String</figcaption></figure></div><p>Now IntelliJ treats the string as it would treat JSON in a <code>.json</code> file. It even points out any errors in the JSON.</p><p>You can inject almost any language IntelliJ supports in this way:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8wrH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8wrH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 424w, https://substackcdn.com/image/fetch/$s_!8wrH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 848w, https://substackcdn.com/image/fetch/$s_!8wrH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 1272w, https://substackcdn.com/image/fetch/$s_!8wrH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8wrH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png" width="525" height="348" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:348,&quot;width&quot;:525,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57554,&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_!8wrH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 424w, https://substackcdn.com/image/fetch/$s_!8wrH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 848w, https://substackcdn.com/image/fetch/$s_!8wrH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.png 1272w, https://substackcdn.com/image/fetch/$s_!8wrH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a660c-ae3e-4bde-8788-91123e628d6c_525x348.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">IntelliJ autocomplete on the language comment</figcaption></figure></div><p>Adding a comment is just one way to enable language injection. Be sure to check out the <strong><a href="https://www.jetbrains.com/help/idea/using-language-injections.html">documentation</a></strong> for more details!</p><p></p><p><strong>What are your favorite InelliJ features? Share in the comments!</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/intellij-magic-weekly-tech-tidbits/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/intellij-magic-weekly-tech-tidbits/comments"><span>Leave a comment</span></a></p><p></p><div><hr></div><h2>Find Anything Fast: Using IntelliJ&#8217;s Search Anywhere &#128269;</h2><p>IntelliJ's <strong><a href="https://www.jetbrains.com/help/idea/searching-everywhere.html">Search Anywhere</a></strong> feature is an incredibly versatile tool designed to help you quickly find anything within your project or IDE. By pressing <code>Shift</code> twice, you open the Search Anywhere dialog, which allows you to search for classes, files, symbols, and even IDE settings and actions from a single interface.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;106dd3c0-6d04-4817-8b6b-5ec97f463e96&quot;,&quot;duration&quot;:null}"></div><p>This powerful search functionality provides instant results as you type, with IntelliJ smartly prioritizing the most relevant matches. Whether you're looking for a specific method, navigating to a file, or trying to access a particular setting, Search Anywhere simplifies the process by consolidating all searches into one place.</p><p>Personally, I find this feature invaluable for tasks where I haven't memorized the shortcuts since I don't use them frequently.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Subscribe now to ensure you don't miss our next exciting issue!</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Keyboard Shortcuts PDF &#128196;</h2><p>IntelliJ's <strong>Keyboard Shortcuts PDF</strong> is a valuable resource for quickly learning and mastering the IDE's shortcuts.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VVB6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VVB6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 424w, https://substackcdn.com/image/fetch/$s_!VVB6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 848w, https://substackcdn.com/image/fetch/$s_!VVB6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 1272w, https://substackcdn.com/image/fetch/$s_!VVB6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VVB6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png" width="289" height="271" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:271,&quot;width&quot;:289,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20240,&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_!VVB6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 424w, https://substackcdn.com/image/fetch/$s_!VVB6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 848w, https://substackcdn.com/image/fetch/$s_!VVB6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 1272w, https://substackcdn.com/image/fetch/$s_!VVB6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72a7acca-9039-4eb6-999b-74a7fed55ec1_289x271.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>By clicking on <code>Help &gt; Keyboard Shortcuts PDF</code>, a PDF will open, organizing shortcuts by functionality and making it easy to find exactly what you need.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Aqv6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Aqv6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 424w, https://substackcdn.com/image/fetch/$s_!Aqv6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 848w, https://substackcdn.com/image/fetch/$s_!Aqv6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 1272w, https://substackcdn.com/image/fetch/$s_!Aqv6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Aqv6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png" width="503" height="339" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:339,&quot;width&quot;:503,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39401,&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_!Aqv6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 424w, https://substackcdn.com/image/fetch/$s_!Aqv6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 848w, https://substackcdn.com/image/fetch/$s_!Aqv6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.png 1272w, https://substackcdn.com/image/fetch/$s_!Aqv6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690d1bbc-293e-4a80-8e1e-6259b16a5ebe_503x339.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">Snippet from the Shortcut-PDF.</figcaption></figure></div><p></p><p>While plugins like Key Promoter X are excellent for learning shortcuts through practice, having the PDF open on a second monitor is incredibly useful for quick reference. I find it helpful to discover new shortcuts and refresh my memory on less common ones, making everyday tasks faster and more efficient in IntelliJ.</p><div><hr></div><h2>Wrapping Up</h2><p>Thank you for exploring these productivity-boosting features of IntelliJ with me. Here's a quick recap:</p><ul><li><p><strong>Injecting Syntax Highlighting into a String &#127752;:</strong> Add syntax highlighting to your strings with a simple comment to improve code readability and error detection.</p></li><li><p><strong>Search Anywhere &#128269;:</strong> Press <code>Shift</code> twice to search for classes, files, symbols, and settings all in one place, streamlining your navigation.</p></li><li><p><strong>Keyboard Shortcuts PDF &#128196;:</strong> Click to open a PDF with categorized shortcuts for quick reference and improved efficiency.</p></li></ul><p>I hope these tips help you enhance your workflow and boost your productivity in IntelliJ. I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p>Happy coding! &#128640;</p><p></p><div><hr></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;6cfe0261-4b1d-400b-a616-8f09a38b2d33&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this git special issue of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics: The git shortlog Command &#128221; Setting a Global .gitignore &#128683; Linus Torvalds on Git &#128249; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this po&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Git Power Up: Master Shortlog &amp; Global Ignore - Weekly Tech Tidbits #6&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-07-09T06:01:23.242Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/git-power-up-master-shortlog-and&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:146301509,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;67ba2507-e016-4848-9747-50cce30d4c32&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this issue of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics: Master Your Learning Paths with roadmap.sh &#128640; Kotlin Gems: The Scan Function &#128142; Google Cloud Region Picker &#127757; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Kotlin's Scan Function, Fantastic Learning Paths, And More - Weekly Tech Tidbits #5&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-07-03T09:32:19.720Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:146207716,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/intellij-magic-weekly-tech-tidbits/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/intellij-magic-weekly-tech-tidbits/comments"><span>Leave a comment</span></a></p><p></p><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[SQL Murder Mystery: A Fun Way to Learn SQL- Weekly Tech Tidbits #7]]></title><description><![CDATA[Enhance Your Coding Skills: Music for Programming, Clean Code Insights, and SQL Mystery Game]]></description><link>https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn</link><guid isPermaLink="false">https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Wed, 17 Jul 2024 06:00:43 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%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi &#128075;, it's great to have you here for this vacation special issue of Weekly Tech Tidbits. &#127796;&#9728;&#65039; As it's vacation time for many people, we'll share three topics that you can simply enjoy.</p><ol><li><p><strong>Music for Programming</strong></p></li><li><p><strong>Clean Code, The Movie &#127916;</strong></p></li><li><p><strong>SQL Murder Mystery</strong> &#128373;&#65039;&#8205;&#9794;&#65039;&#128269;</p></li></ol><p><strong>I'll be on vacation too, so the next issue will come out on the first of August</strong>. Wishing everyone a great time! &#127958;&#65039;&#128526;</p><p>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! &#128226;</p><div><hr></div><h2>Music for Programming (or any other task) &#127925;</h2><p>First, something for the ears. I often listen to music while coding, but I can't concentrate well if there are vocal parts. Instead, I quite enjoy listening to the tracks on <strong><a href="https://musicforprogramming.net/">musicforprogramming.net </a></strong>&#8211; well, the name says it all. The site currently has 71 episodes (I&#8217;d call them mixtapes) of music specifically designed to help you focus and get things done without distractions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0mxT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0mxT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 424w, https://substackcdn.com/image/fetch/$s_!0mxT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 848w, https://substackcdn.com/image/fetch/$s_!0mxT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 1272w, https://substackcdn.com/image/fetch/$s_!0mxT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0mxT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png" width="1194" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:1194,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:112432,&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_!0mxT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 424w, https://substackcdn.com/image/fetch/$s_!0mxT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 848w, https://substackcdn.com/image/fetch/$s_!0mxT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.png 1272w, https://substackcdn.com/image/fetch/$s_!0mxT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b857fd4-aa3b-49fb-9472-22c0ce61f53c_1194x451.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>My favorite is <strong><a href="https://musicforprogramming.net/four">episode 4</a></strong>, which features Com Truise. There&#8217;s even a podcast feed with all the episodes and an <a href="https://musicforprogramming.net/rss.xml">RSS feed</a> available for easy access. So, next time you need some background music while working or studying, give it a try. You might find it just as helpful as I do. &#127911;</p><p><strong>What are your favorite tracks to code to? Share in the comments!</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn/comments"><span>Leave a comment</span></a></p><p></p><div><hr></div><h2>Clean Code, The Movie &#127916;</h2><p>If you're looking to deepen your understanding of clean code principles, I highly recommend the video series featuring Robert C. Martin (Uncle Bob) live on stage. </p><div id="youtube2-7EmboKQH8lM" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;7EmboKQH8lM&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/7EmboKQH8lM?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Not everyone is a fan of his presentation style &#8211; it's a bit theatrical and sometimes polarizing &#8211; but the substance of his content is top-notch. In these videos, Uncle Bob <strong>dives into the nitty-gritty of what makes code clean</strong>, exploring topics like naming conventions, functions, and error handling.</p><p>You can find the series online, and it's a fantastic resource for anyone looking to improve their coding practices. Whether you're a seasoned developer or just starting out, the series offers practical advice that you can apply directly to your work. So, set aside some time, grab some popcorn, and get ready to learn from one of the best in the business. &#127871;&#128187;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Subscribe now to ensure you don't miss our next exciting issue on August 1st!</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>SQL Murder Mystery &#128373;&#65039;&#8205;&#9794;&#65039;&#128269;</h2><p>Looking for a fun and engaging way to sharpen your SQL skills? Check out "SQL Murder Mystery" at <a href="https://mystery.knightlab.com/">mystery.knightlab.com</a>. This interactive website turns <strong>learning SQL into an exciting detective game where you use your SQL</strong> powers to solve a murder mystery.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WEe5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WEe5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!WEe5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!WEe5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!WEe5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WEe5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp" width="560" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:560,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A film noir style comic panel in 16:9 aspect ratio, depicting a detective working on a computer. The detective is surrounded by data charts, SQL queries, and code snippets. The scene is set in a dimly lit room with a corkboard covered in clues, maps, and photos related to a murder mystery. The detective wears a trench coat and hat, embodying the classic detective look, and appears focused on solving the mystery through his computer. The overall atmosphere is dark, mysterious, and intriguing, with strong contrasts and shadows typical of the film noir style. Include cute and kawaii elements, such as adorable decorations, soft colors, and cute accessories, to add a whimsical and charming touch to the scene.&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="A film noir style comic panel in 16:9 aspect ratio, depicting a detective working on a computer. The detective is surrounded by data charts, SQL queries, and code snippets. The scene is set in a dimly lit room with a corkboard covered in clues, maps, and photos related to a murder mystery. The detective wears a trench coat and hat, embodying the classic detective look, and appears focused on solving the mystery through his computer. The overall atmosphere is dark, mysterious, and intriguing, with strong contrasts and shadows typical of the film noir style. Include cute and kawaii elements, such as adorable decorations, soft colors, and cute accessories, to add a whimsical and charming touch to the scene." title="A film noir style comic panel in 16:9 aspect ratio, depicting a detective working on a computer. The detective is surrounded by data charts, SQL queries, and code snippets. The scene is set in a dimly lit room with a corkboard covered in clues, maps, and photos related to a murder mystery. The detective wears a trench coat and hat, embodying the classic detective look, and appears focused on solving the mystery through his computer. The overall atmosphere is dark, mysterious, and intriguing, with strong contrasts and shadows typical of the film noir style. Include cute and kawaii elements, such as adorable decorations, soft colors, and cute accessories, to add a whimsical and charming touch to the scene." srcset="https://substackcdn.com/image/fetch/$s_!WEe5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!WEe5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!WEe5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!WEe5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57884c3b-8516-4478-9e98-ed8499461f8e_1792x1024.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The premise is simple: a crime has been committed, and it's up to you to analyze data and piece together the evidence to find the culprit. As you navigate through the investigation, you'll write and execute SQL queries to uncover critical information.</p><p>So, if you're ready to put on your detective hat and dive into some data sleuthing, head over to the site and start solving the mystery. It's a fantastic way to learn while having fun. Happy investigating! &#128373;&#65039;&#8205;&#9792;&#65039;&#128450;&#65039;&#128269;</p><div><hr></div><h2>Wrapping Up</h2><p>Thank you for reading this week's vacation special issue of Weekly Tech Tidbits. Here's a quick recap:</p><ul><li><p><strong>Music for Programming &#127925;</strong>: Enjoy distraction-free music to enhance your focus.</p></li><li><p><strong>Clean Code, The Movie &#127916;</strong>: Learn clean code principles from Robert C. Martin.</p></li><li><p><strong>SQL Murder Mystery &#128373;&#65039;&#8205;&#9794;&#65039;&#128269;</strong>: Solve a murder mystery while sharpening your SQL skills.</p></li></ul><p>I'll be on vacation, so the next issue will come out on the first of August. Wishing everyone a great time! &#127958;&#65039;&#128526;</p><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p></p><div><hr></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;6cfe0261-4b1d-400b-a616-8f09a38b2d33&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this git special issue of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics: The git shortlog Command &#128221; Setting a Global .gitignore &#128683; Linus Torvalds on Git &#128249; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this po&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Git Power Up: Master Shortlog &amp; Global Ignore - Weekly Tech Tidbits #6&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-07-09T06:01:23.242Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/git-power-up-master-shortlog-and&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:146301509,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;67ba2507-e016-4848-9747-50cce30d4c32&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this issue of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics: Master Your Learning Paths with roadmap.sh &#128640; Kotlin Gems: The Scan Function &#128142; Google Cloud Region Picker &#127757; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Kotlin's Scan Function, Fantastic Learning Paths, And More - Weekly Tech Tidbits #5&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-07-03T09:32:19.720Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:146207716,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/sql-murder-mystery-a-fun-way-to-learn/comments"><span>Leave a comment</span></a></p><p></p><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Git Power Up: Master Shortlog & Global Ignore - Weekly Tech Tidbits #6]]></title><description><![CDATA[Unlock Advanced Git Functionality with These Powerful Commands to Streamline Contribution Tracking & Repository Housekeeping]]></description><link>https://verbosemode.dev/p/git-power-up-master-shortlog-and</link><guid isPermaLink="false">https://verbosemode.dev/p/git-power-up-master-shortlog-and</guid><pubDate>Tue, 09 Jul 2024 06:01:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F146!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p>Hi &#128075;, it's great to have you here for this <strong>git special issue</strong> of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics:</p><ol><li><p><strong>The git shortlog Command &#128221;</strong></p></li><li><p><strong>Setting a Global .gitignore &#128683;</strong></p></li><li><p><strong>Linus Torvalds on Git &#128249;</strong></p></li></ol><p>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! &#128226;</p><div><hr></div><h2>The <code>git shortlog</code> Command &#128221;</h2><p>The <code>git shortlog</code> command in Git is an excellent tool for summarizing commit histories, providing a concise overview of contributions by author and commit message. It groups commits by author, making it perfect for tracking contributions and generating release notes.</p><p>Using <code>git shortlog</code>, you can easily see who contributed what to the project. Here&#8217;s a basic usage example:</p><pre><code>git shortlog &lt;start commit&gt;...&lt;end commit&gt;
git shortlog HEAD~25..HEAD</code></pre><p>This command <strong>summarizes all commits in the specified range, grouped by author and commit message.</strong> Here&#8217;s a sample output:</p><pre><code>  10  Jane Doe &lt;jane@example.com&gt;
       Fix login issue
       Update user profile page
       ....

   5  John Smith &lt;john@example.com&gt;
       Initial commit
       ... </code></pre><p>This detailed output is ideal for creating a changelog. You can also shorten the output to quickly see who contributed the most:</p><pre><code>git shortlog -sne</code></pre><p>This command adds the number of commits (<code>-s</code>), sorts by the number of commits (<code>-n</code>), and includes the email addresses of the authors (<code>-e</code>). Here&#8217;s how the output might look:</p><pre><code>  10  Jane Doe &lt;jane@example.com&gt;
   5  John Smith &lt;john@example.com&gt;</code></pre><p><code>git shortlog</code> is perfect for understanding the overall contribution landscape. Use it to identify active contributors or summarize changes for a new release. &#127881;</p><p>For more information, check out the <a href="https://git-scm.com/docs/git-shortlog">Git documentation on </a><code>git shortlog</code>.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/git-power-up-master-shortlog-and?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thank you for reading verbosemode. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/git-power-up-master-shortlog-and?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/git-power-up-master-shortlog-and?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p><div><hr></div><h2>Set a Global <code>.gitignore</code> &#128683;</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F146!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F146!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!F146!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!F146!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!F146!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F146!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp" width="576" height="329.14285714285717" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:576,&quot;bytes&quot;:614990,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F146!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!F146!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!F146!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!F146!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858bc40d-d455-43f8-8613-31e51254e0bf_1792x1024.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An allegory on global gitignore as drawn by DALL-E</figcaption></figure></div><p>I always used to accidentally add heap dump files (<code>*.hprof</code>) to my Git repositories. It was a hassle to remove them from GitHub once I pushed them accidentally. To avoid this, <strong>I set up a global </strong><code>.gitignore</code> to ensure such files are never tracked in any of my projects.</p><p>Here&#8217;s how to set up a global <code>.gitignore</code>:</p><p><strong>Create a Global </strong><code>.gitignore</code><strong> File:</strong></p><pre><code>touch ~/dotfiles/.gitignore_global</code></pre><p><strong>Configure Git to Use the Global </strong><code>.gitignore</code><strong> File:</strong></p><pre><code>git config --global core.excludesFile ~/dotfiles/.gitignore_global</code></pre><p><strong>Add Common Exclusions</strong></p><p>Edit the <code>~/.gitignore_global</code> file and add patterns for files you always want to ignore. Here&#8217;s an example:</p><pre><code># Java heap dumps
*.hprof

# macOS system files
.DS_Store</code></pre><p>For a more comprehensive list of ignore patterns, you can find useful templates at <a href="https://github.com/github/gitignore">GitHub's gitignore repository</a>.</p><p>Setting a global <code>.gitignore</code> helps keep your repositories clean by automatically ignoring files that are not relevant to your projects.</p><p>For more information, check out the <a href="https://git-scm.com/docs/gitignore">Git documentation on ignore files</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">verbosemode is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2><strong>Linus Torvalds on git &#128249;</strong></h2><p>Linus Torvalds, the creator of Git, gave an amazing talk at Google in 2007 (yes, the year the iPhone came out!). As o commenters say, the video quality might be a bit dated (it's 240p), but the content is pure gold &#8211; "Content 8k" according to one viewer. In this talk, Linus discusses Git, then a young system at just two years old.</p><div id="youtube2-4XpnKHJAok8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;4XpnKHJAok8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/4XpnKHJAok8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Lean back and enjoy this insightful trip back in tech time!</p><div><hr></div><h2>Wrapping Up</h2><p>Thank you for reading this week's Weekly Tech Tidbits. Here's a quick recap:</p><ul><li><p><strong>The git shortlog Command</strong>: Summarize and understand commit histories efficiently.</p></li><li><p><strong>Setting a Global .gitignore</strong>: Keep your repositories clean by ignoring irrelevant files.</p></li><li><p><strong>Linus Torvalds on Git</strong>: An insightful talk from the creator of Git.</p></li></ul><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p></p><div><hr></div><p><strong>Changelog:</strong></p><ul><li><p>A <a href="https://www.reddit.com/r/programming/comments/1dyvlvj/comment/lcc39ar/?context=3">reddit user </a>mentioned that it is bad practice to put stuff under <code>~</code> which is a valid point. I changed it to<code> ~/dotfiles/</code></p></li></ul><div><hr></div><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;67ba2507-e016-4848-9747-50cce30d4c32&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this issue of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics: Master Your Learning Paths with roadmap.sh &#128640; Kotlin Gems: The Scan Function &#128142; Google Cloud Region Picker &#127757; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Kotlin's Scan Function, Fantastic Learning Paths, And More - Weekly Tech Tidbits #5&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-07-03T09:32:19.720Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:146207716,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/git-power-up-master-shortlog-and/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/git-power-up-master-shortlog-and/comments"><span>Leave a comment</span></a></p><p></p><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Kotlin's Scan Function, Fantastic Learning Paths, And More - Weekly Tech Tidbits #5]]></title><description><![CDATA[Explore roadmap.sh for Learning, Kotlin's Scan Function, and Google Cloud Region Picker for Optimal Cloud Service Choices]]></description><link>https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning</link><guid isPermaLink="false">https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning</guid><pubDate>Wed, 03 Jul 2024 09:32:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!w7KC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi &#128075;, it's great to have you here for this issue of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics:</p><ol><li><p><strong>Master Your Learning Paths with roadmap.sh &#128640;</strong></p></li><li><p><strong>Kotlin Gems: The Scan Function &#128142;</strong></p></li><li><p><strong>Google Cloud Region Picker &#127757;</strong></p></li></ol><p>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! &#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share verbosemode&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share verbosemode</span></a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;cc76e735-7438-49e6-9d8a-3ba4c3d595ba&quot;,&quot;caption&quot;:&quot;Hi &#128075;, it's great to have you here for this Kotlin special edition of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics: IntelliJ IDEA's New K2 Mode &#128187; Hidden Kotlin Gems: The Windowed Function &#128142; Future Directions for Kotlin: What's Next?&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;The Future of Kotlin and Hidden Gems - Weekly Tech Tidbits #4 - Kotlin Special&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-26T10:43:54.129Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/youtube/w_728,c_limit/tAGJ5zJXJ7w&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/the-future-of-kotlin-and-hidden-gems&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145866354,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><p></p><h2>Master Your Learning Paths with roadmap.sh &#128640;</h2><p>Learning new things is hard, especially when you don't know what you need to learn. This is where<a href="https://roadmap.sh"> roadmap.sh </a>comes in. They provide visual graphs of learning content for a wide array of development topics, such as backend, frontend, system design, and more.</p><p>While the site itself offers limited content, it provides valuable links for deeper exploration of these topics. If you log in, you can even track your own progress.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w7KC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w7KC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 424w, https://substackcdn.com/image/fetch/$s_!w7KC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 848w, https://substackcdn.com/image/fetch/$s_!w7KC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 1272w, https://substackcdn.com/image/fetch/$s_!w7KC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w7KC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png" width="1012" height="571" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:571,&quot;width&quot;:1012,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86849,&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_!w7KC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 424w, https://substackcdn.com/image/fetch/$s_!w7KC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 848w, https://substackcdn.com/image/fetch/$s_!w7KC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.png 1272w, https://substackcdn.com/image/fetch/$s_!w7KC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c86998e-33ec-4756-9640-ec95d0346b52_1012x571.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">Start of the System Design Roadmap</figcaption></figure></div><p><strong>This site is incredibly useful if you want to dive into a new topic</strong> &#128161;. Recently, they launched a feature to create roadmaps on anything via AI. While I'm not yet convinced by the quality (the hand-curated ones are much better), it&#8217;s fun to try out.</p><p></p><div><hr></div><h2>Kotlin Gems: The Scan Function &#128142;</h2><p>The<a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/scan.html"> </a><code>scan</code><a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/scan.html"> function</a> in Kotlin is a hidden gem for processing collections, similar to <code>fold</code> but with a twist. <strong>While </strong><code>fold</code><strong> accumulates values to a final result, </strong><code>scan</code><strong> retains all intermediate results</strong>, perfect for tasks like running totals or cumulative distributions.</p><p>Using <code>scan</code>, you can track the progression of computations &#128200;. Here&#8217;s an example:</p><pre><code>val donations = listOf(10, 15, 20, 25, 30)
val runningTotal = donations.scan(0) { total, donation -&gt; total + donation }
</code></pre><p>This code snippet starts with a running total of 0, sequentially adding each donation and capturing each intermediate state along the way. <strong>The </strong><code>scan</code><strong> function generates the following list: </strong><code>[0, 10, 25, 45, 70, 100]</code>, providing a detailed view of the accumulation process.</p><p>While both <code>scan</code> and fold <code>have</code> a similar function signature, they serve distinct purposes. <code>Fold</code> returns only the final accumulated value, which is suitable for scenarios where you only need the end result. Here&#8217;s an example demonstrating fold:</p><pre><code>val donations = listOf(10, 15, 20, 25, 30)
val totalDonations = donations.fold(0) { total, donation -&gt; total + donation }
}
</code></pre><p>This results in <code>100</code>, giving you the cumulative sum without the intermediate steps.</p><p>The choice between scan and fold depends on your needs: <strong>use </strong><code>scan</code><strong> for visibility into each step of the accumulation, and </strong><code>fold</code><strong> when only the final result matters.</strong></p><p></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div><hr></div><h2>Google Cloud Region Picker &#127757;</h2><p>Choosing the right region for your cloud services can be challenging. The most important factor is proximity to your users, but costs and carbon footprint are also factors to consider.</p><p><strong>I was surprised to discover that Google Cloud services can have different costs depending on the region.</strong> For instance, running Cloud Run instances in europe-west1 is cheaper than in europe-west3. Additionally, not all services are available in every region&#8212;Cloud Scheduler, for example, is only available in four regions in Europe.</p><p>The<strong><a href="https://googlecloudplatform.github.io/region-picker/"> Google Cloud Region Picker</a></strong> simplifies this process, helping you select the most suitable region for your needs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-8o7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-8o7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 424w, https://substackcdn.com/image/fetch/$s_!-8o7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 848w, https://substackcdn.com/image/fetch/$s_!-8o7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 1272w, https://substackcdn.com/image/fetch/$s_!-8o7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-8o7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png" width="525" height="488" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:488,&quot;width&quot;:525,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:40273,&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_!-8o7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 424w, https://substackcdn.com/image/fetch/$s_!-8o7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 848w, https://substackcdn.com/image/fetch/$s_!-8o7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.png 1272w, https://substackcdn.com/image/fetch/$s_!-8o7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aaa2b06-ba9d-499e-9a96-ad83d3632d69_525x488.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">Screenshot of the Region Picker</figcaption></figure></div><p>By setting just a few parameters, you'll receive a list of the best-fit regions for your services. This tool makes it much easier than digging through extensive documentation!</p><div><hr></div><p></p><h2>Wrapping Up</h2><p>Thank you for reading this week's Weekly Tech Tidbits. Here's a quick recap:</p><ul><li><p><strong>Master Your Learning with <a href="https://roadmap.sh">roadmap.sh</a></strong>: Simplify your learning journey with visual roadmaps for various development topics.</p></li><li><p>Kotlin Gems: <strong><a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/scan.html">The Scan Function</a></strong>: Utilize the scan function for tracking the progression of computations and gaining intermediate results.</p></li><li><p><strong><a href="https://googlecloudplatform.github.io/region-picker/">Google Cloud Region Picker</a></strong>: Select the most suitable region for your cloud services based on proximity, cost, and availability.</p></li></ul><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/kotlins-scan-function-fantastic-learning/comments"><span>Leave a comment</span></a></p><p></p><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Deploy your Own Image to CloudRun - CloudRun 101 - Part 2]]></title><description><![CDATA[&#128640; Deploying Your Docker Image to Cloud Run with a Private Artifact Registry: A Step-by-Step Guide]]></description><link>https://verbosemode.dev/p/deploy-your-own-image-to-cloudrun</link><guid isPermaLink="false">https://verbosemode.dev/p/deploy-your-own-image-to-cloudrun</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Fri, 28 Jun 2024 10:29:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hah1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hah1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hah1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!hah1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!hah1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!hah1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hah1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:429530,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&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_!hah1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!hah1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!hah1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!hah1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8db8d2-e6a8-4557-ad29-c50dd3fb0d62_1792x1024.webp 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">Drawn by DALL-E.</figcaption></figure></div><p>In the <a href="https://verbosemode.dev/p/getting-started-with-cloudrun-and">last post of this series</a>, we set up our first CloudRun service with a simple "Hello, World." Now, we're ready to take the next step.</p><p><strong>In this post, you'll learn how to set up a private artifact registry and use it to deploy your own Docker image to CloudRun. &#128640;</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2><strong>Prerequisites</strong></h2><p>I assume you followed the previous post or have equivalent knowledge. If you're unsure, you can always go back and review or get the previous code from <a href="https://github.com/ablx/cloudrun_terraform_getting_started/tree/main">GitHub</a>.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;7678a642-a577-4652-a5fe-189c14c7a9f0&quot;,&quot;caption&quot;:&quot;CloudRun has become my go-to solution for deploying applications in the cloud due to its simplicity and scalability. It's an ideal choice for various use cases. In this upcoming blog post series, I'll guide you on how to get started with CloudRun effectively. We'll begin with the quintessential \&quot;Hello, World,\&quot; using Terraf&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Getting Started with CloudRun and Terraform - CloudRun 101&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-06-10T11:14:56.264Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/getting-started-with-cloudrun-and&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145408879,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>You must have a Google Cloud account and project, as well as gcloud and Terraform installed and running. We&#8217;ll also add Docker to the mix this time. Chances are, you already have it installed, but if not, you can find instructions on<a href="https://docs.docker.com/engine/install/"> Docker's website</a>.</p><p>To check if Docker is set up correctly, run the following command in your terminal:</p><pre><code>docker run hello-world</code></pre><p>You should see something like this:</p><pre><code>Hello from Docker!
This message shows that your installation appears to be working correctly.</code></pre><p>Great, now let's dive into today's task: getting your own Docker &#128051; image up to CloudRun! </p><div><hr></div><h2>Artifact Registry</h2><p>The <a href="https://cloud.google.com/artifact-registry/docs/overview">Artifact Registry</a> is Google&#8217;s product for storing artifacts, including (but not limited to) Docker containers within your project. While you don&#8217;t have to use it to deploy your images to CloudRun&#8212;DockerHub works just fine&#8212;I find it convenient to keep everything in one place.</p><p>Like CloudRun, Artifact Registry includes a <a href="https://cloud.google.com/artifact-registry/pricing">free tier</a>, allowing you to store up to 500 megabytes for free. If you exceed that, you&#8217;ll be charged $0.10 per gigabyte per month. Additionally, data transfers crossing regions incur charges, so we'll set up our registry in the same location as our CloudRun service to avoid extra costs. However, even if you do incur charges, the prices are very reasonable. &#128176;</p><p></p><p>To get started, we must first <strong>activate the Artifact Registry API</strong>. Open <code>apis.tf</code> and add the following:</p><pre><code>resource "google_project_service" "artifact_registry_api" {
  project            = local.project_id
  service            = "artifactregistry.googleapis.com"
  disable_on_destroy = false
}</code></pre><p>This will enable the Artifact Registry API for your project.</p><p>Next, create a new file called <code>artifactregistry.tf</code> and enter the following:</p><pre><code>resource "google_artifact_registry_repository" "artifact_registry" {
  location      = local.region
  repository_id = "docker-repository"
  description   = "Docker Repository for CloudRun"
  format        = "DOCKER"

  cleanup_policies {
    id     = "delete"
    action = "DELETE"
    condition {
      older_than   = "3600s"
    }
  }
}</code></pre><p>Here, <code>local.region</code> refers to the region we set up in <code>constants.tf</code> in the <a href="https://verbosemode.dev/p/getting-started-with-cloudrun-and">last post</a>. This is also used in the CloudRun configuration. Since we're just experimenting, I've added a cleanup policy that removes each image after one hour to ensure we don't incur any unwanted costs.</p><p>That&#8217;s all for now. Run <code>terraform apply</code> to set up the artifact registry. In the output, you should see something like this:</p><pre><code>...
  # google_artifact_registry_repository.artifact_registry will be created
  + resource "google_artifact_registry_repository" "artifact_registry" {
...
      + description      = "Docker Repository for CloudRun"
...
      + format           = "DOCKER"
...
      + location         = &lt;your location&gt;
      + mode             = "STANDARD_REPOSITORY"
...
      + project          = &lt;your project&gt;
      + repository_id    = "docker-repository"
...

      + cleanup_policies {
          + action = "DELETE"
          + id     = "delete"

          + condition {
              + older_than            = "3600s"
              + package_name_prefixes = []
              + tag_prefixes          = []
              + tag_state             = "ANY"
              + version_name_prefixes = []
                # (1 unchanged attribute hidden)
            }
        }
    }</code></pre><p>Before we can publish to the artifact registry, we must authorize access. This can be easily done via:</p><pre><code>gcloud auth configure-docker  &lt;your location&gt;-docker.pkg.dev</code></pre><p>Let's go ahead and publish a Docker image. &#128051;</p><div><hr></div><h2>Docker Image</h2><p>Now we are ready to push a Docker image to our registry. If you don't have one on hand, you can use the small Flask application I wrote for this purpose. It has a GET and a POST endpoint, which we can use to verify that everything is working correctly.</p><p>Get the <a href="https://github.com/ablx/cloudrun_terraform_getting_started/blob/main/02_deploy_own_images_via_artifactregistry/app/app.py">Python code</a> and <a href="https://github.com/ablx/cloudrun_terraform_getting_started/blob/main/02_deploy_own_images_via_artifactregistry/app/Dockerfile">Dockerfile</a> from <a href="https://github.com/ablx/cloudrun_terraform_getting_started/tree/main/02_deploy_own_images_via_artifactregistry">GitHub</a>. Then navigate to the directory where you downloaded the files and build the Docker image with the following command:</p><pre><code>docker build &lt;path to the files&gt; -t cloudrun101</code></pre><p>Next, we need to add a tag containing the location of the registry and the project ID:</p><pre><code>docker tag cloudrun101 &lt;your region from constants.tf&gt;-docker.pkg.dev/&lt;your project id&gt;/docker-repository/cloudrun101:latest</code></pre><p>Finally, we can push the image:</p><pre><code>docker push &lt;your region from constants.tf&gt;-docker.pkg.dev/&lt;your project id&gt;/docker-repository/cloudrun101</code></pre><p>If everything succeeded, you can check the registry in the web interface and see something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ejI9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ejI9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 424w, https://substackcdn.com/image/fetch/$s_!ejI9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 848w, https://substackcdn.com/image/fetch/$s_!ejI9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 1272w, https://substackcdn.com/image/fetch/$s_!ejI9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ejI9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png" width="608" height="306" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:306,&quot;width&quot;:608,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21248,&quot;alt&quot;:&quot;Screenshot of the artifact registry with our image.&quot;,&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="Screenshot of the artifact registry with our image." title="Screenshot of the artifact registry with our image." srcset="https://substackcdn.com/image/fetch/$s_!ejI9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 424w, https://substackcdn.com/image/fetch/$s_!ejI9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 848w, https://substackcdn.com/image/fetch/$s_!ejI9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 1272w, https://substackcdn.com/image/fetch/$s_!ejI9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be15880-0aec-4289-91c2-e2fd0d7e09aa_608x306.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now we can use it in our CloudRun service.</p><div><hr></div><h2>Use the Image in CloudRun</h2><p>We only need to change the image name in our <code>cloudrun.tf</code> file:</p><pre><code># Terraform configuration to create a Cloud Run service
resource "google_cloud_run_v2_service" "service" {
....
  template {
    containers {
      image = "${local.region}-docker.pkg.dev/${local.project_id}/docker-repository/cloudrun101:latest"
    }
  }

}</code></pre><p>Run <code>terraform apply</code> to update your CloudRun revision with the new image. Note that I kept the public access as discussed last time for easier testing. Once <code>terraform apply</code> succeeds, you can test if the image works by opening <code>&lt;your-cloudrun-url&gt;/hello</code> in your browser.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WRb6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WRb6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 424w, https://substackcdn.com/image/fetch/$s_!WRb6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 848w, https://substackcdn.com/image/fetch/$s_!WRb6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 1272w, https://substackcdn.com/image/fetch/$s_!WRb6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WRb6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png" width="487" height="125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:125,&quot;width&quot;:487,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7457,&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_!WRb6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 424w, https://substackcdn.com/image/fetch/$s_!WRb6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 848w, https://substackcdn.com/image/fetch/$s_!WRb6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 1272w, https://substackcdn.com/image/fetch/$s_!WRb6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02e5921c-42ba-4ff6-aff5-b6c0c72d34c0_487x125.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This may not be the most useful CloudRun service, but it runs our own image from Artifact Registry! Great! &#127881;</p><div><hr></div><h2>Wrapping Up</h2><p>Congratulations! &#127881; You've set up a private artifact registry and deployed your own Docker image to CloudRun.</p><p>Remember to run <code>terraform destroy</code> to clean up your resources.</p><p>Stay tuned for the next post, where we'll connect Pub/Sub to CloudRun. Thanks for following along, and happy coding! &#128640;</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;23a70ccd-989e-4ac6-9cda-d1dbada2e02e&quot;,&quot;caption&quot;:&quot;CloudRun has become my go-to solution for deploying applications in the cloud due to its simplicity and scalability. It's an ideal choice for various use cases. In this upcoming blog post series, I'll guide you on how to get started with CloudRun effectively. We'll begin with the quintessential \&quot;Hello, World,\&quot; using Terraf&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Getting Started with CloudRun and Terraform - CloudRun 101&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:184622759,&quot;name&quot;:&quot;Mirco&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-06-10T11:14:56.264Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/getting-started-with-cloudrun-and&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145408879,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The Future of Kotlin and Hidden Gems - Weekly Tech Tidbits #4 - Kotlin Special]]></title><description><![CDATA[Discover the Latest in Kotlin: Hidden Gems, IntelliJ Innovations, and Future Directions &#128640;&#128302;]]></description><link>https://verbosemode.dev/p/the-future-of-kotlin-and-hidden-gems</link><guid isPermaLink="false">https://verbosemode.dev/p/the-future-of-kotlin-and-hidden-gems</guid><pubDate>Wed, 26 Jun 2024 10:43:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/tAGJ5zJXJ7w" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi &#128075;, it's great to have you here for this <strong>Kotlin special edition</strong> of Weekly Tech Tidbits. In today's post, we'll cover three intriguing topics:</p><ol><li><p><strong>IntelliJ IDEA's New K2 Mode</strong> &#128187;</p></li><li><p><strong>Hidden Kotlin Gems: The Windowed Function</strong> &#128142;</p></li><li><p><strong>Future Directions for Kotlin: What's Next?</strong> &#128302;</p></li></ol><p><em>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! </em>&#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share verbosemode&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share verbosemode</span></a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;9ccd4a56-38db-4356-84af-e16fb52ea830&quot;,&quot;caption&quot;:&quot;Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics: Efficient Communication with the Minto Pyramid &#128208; Key Takeaways from Kat Gaines' Talk on Incident Communication &#127908; Insights on&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Minto Pyramid, Talk Recommendation and Slow Productivity - Weekly Tech Tidbits #3&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-19T05:01:05.704Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-3-slow-productivity&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145408024,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h2>IntelliJ ID<strong>EA's New K2 Mode</strong> &#128187;</h2><p><a href="https://blog.jetbrains.com/idea/2024/03/k2-kotlin-mode-alpha-in-intellij-idea/">IntelliJ IDEA 2024.1</a> has introduced an optional K2 mode, utilizing the new <strong><a href="https://blog.jetbrains.com/kotlin/2023/02/k2-kotlin-2-0/">K2 compiler</a> for enhanced Kotlin support.</strong> This mode promises:</p><ul><li><p>Compatibility with future Kotlin features </p></li><li><p>Improved code analysis stability </p></li><li><p>Better IDE performance &#128640;</p></li></ul><p>However, as an <strong>Alpha</strong> release, it has <strong>notable limitations,</strong> including:</p><ul><li><p>Lack of Methods and Calls Hierarchy &#128683;</p></li><li><p>No support for Android projects </p></li><li><p>No code analysis in .gradle.kts files </p></li></ul><p>Despite its current limitations, K2 mode offers an exciting glimpse into the future of Kotlin development. IntelliJ IDEA is clearly making strides towards a more efficient and robust development environment.</p><p>While I wouldn't use it daily just yet, I'm eager to see how it evolves.</p><div><hr></div><h2>Kotlin Gems: The Windowed Function &#128142;</h2><p>The <code>windowed</code><a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/windowed.html"> function</a> in Kotlin is a hidden gem for processing consecutive elements in overlapping segments, or "windows." This function is perfect for tasks like calculating moving averages, smoothing data, or analyzing trends by creating sublists of a specified size, sliding over the original list with a specified step.</p><p>Using <code>windowed</code>, you gain a more granular view of your data &#128202;, detecting patterns and anomalies that an overall average might miss. Take a look at this example:</p><pre><code>fun main() {
    val responseTime = listOf(72, 75, 78, 80, 77)
    val windows = responseTime.windowed(size = 3, step = 1)
    val trends = windows.map { window -&gt; window.average() &gt; 75 }
}</code></pre><p>This code creates windows of 3 consecutive measurements, sliding one step at a time. The <code>windowed</code> function produces the following windows:</p><pre><code>Windows: [[72, 75, 78], [75, 78, 80], [78, 80, 77]]</code></pre><p>And checks if the average response time in each window exceeds 75, resulting in:</p><pre><code>Trends: [false, true, true]</code></pre><p>This approach is more helpful than averaging the entire list because it detects periods of higher response times that might be missed when looking at the overall average &#128200;.</p><p>For example, in the list of response times<code>[72, 75, 78, 80, 77]</code>, the overall average is 76.4. However, this average hides the fact that there are consecutive higher response times (78, 80, 77). By looking at smaller windows of 3 elements each, you can identify these spikes and trends that an overall average would overlook.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div><hr></div><h2>Future Directions for Kotlin: What's Next? &#128302;</h2><p>I highly recommend watching Michail Zare&#269;enskij's talk on "<strong><a href="https://www.youtube.com/watch?v=tAGJ5zJXJ7w">Kotlin Language Features in 2.0 and Beyond.</a></strong>" Kotlin 2.0 introduces several cool features that enhance the language's expressiveness and developer productivity. </p><div id="youtube2-tAGJ5zJXJ7w" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;tAGJ5zJXJ7w&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/tAGJ5zJXJ7w?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Looking ahead, Kotlin plans to introduce even more powerful features, making it a language of choice for many developers.</p><div><hr></div><p></p><h2>Wrapping Up</h2><p>Thank you for reading this week's Weekly Tech Tidbits. Here's a quick recap:</p><ol><li><p><strong>IntelliJ IDEA's New K2 Mode</strong>: Promising but currently limited.</p></li><li><p><strong>Hidden Kotlin Gems</strong>: The windowed function offers powerful data analysis capabilities.</p></li><li><p><strong>Future Directions for Kotlin</strong>: Exciting features on the horizon to enhance language expressiveness and productivity.</p></li></ol><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/the-future-of-kotlin-and-hidden-gems/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/the-future-of-kotlin-and-hidden-gems/comments"><span>Leave a comment</span></a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3172afe4-f43a-4536-98a8-1ef682c7eb1c&quot;,&quot;caption&quot;:&quot;Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics: the concept of Disagree and Commit &#128483;&#65039;&#9989; how to keep your code tidy &#129532; Typed Error Handling in Kotlin &#9888;&#65039;&#127909; If you missed the previous issue, find it&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Weekly Tech Tidbits #2: Disagree and Commit, Spotless, and Error Handling in Kotlin.&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-12T05:00:09.771Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/youtube/w_728,c_limit/T04ynq2IVFs&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-2&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145249252,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Minto Pyramid, Talk Recommendation and Slow Productivity - Weekly Tech Tidbits #3]]></title><description><![CDATA[Master Clear Communication, Incident Management Tips, and Cal Newport's Slow Productivity Principles in One Read!]]></description><link>https://verbosemode.dev/p/weekly-tech-tidbits-3-slow-productivity</link><guid isPermaLink="false">https://verbosemode.dev/p/weekly-tech-tidbits-3-slow-productivity</guid><pubDate>Wed, 19 Jun 2024 05:01:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QxkM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Hi, it's <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Mirco&quot;,&quot;id&quot;:184622759,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;uuid&quot;:&quot;fa205345-141b-490d-a947-c57b11c651b0&quot;}" data-component-name="MentionToDOM"></span>! &#128075; Welcome to this week's edition of <strong>Weekly Tech Tidbits</strong>. In today's post, we will cover three interesting topics:</em></p><ul><li><p>Efficient Communication with the <strong>Minto Pyramid</strong> &#128208;</p></li><li><p>Key Takeaways from Kat Gaines' <strong>Talk on Incident Communication</strong> &#127908;</p></li><li><p>Insights on <strong>Slow Productivity</strong> from Cal Newport's New Book &#128012;&#128213;</p></li></ul><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;69e89439-bfce-4b98-a041-eb29586b120a&quot;,&quot;caption&quot;:&quot;Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics: the concept of Disagree and Commit &#128483;&#65039;&#9989; how to keep your code tidy &#129532; Typed Error Handling in Kotlin &#9888;&#65039;&#127909; If you missed the previous issue, find it&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Weekly Tech Tidbits #2: Disagree and Commit, Spotless, and Error Handling in Kotlin.&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-12T05:00:09.771Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/youtube/w_728,c_limit/T04ynq2IVFs&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-2&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145249252,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><em>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! </em>&#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share verbosemode&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share verbosemode</span></a></p><div><hr></div><p></p><h2><strong>Efficient Communication with the Minto Pyramid</strong></h2><p>The <strong><a href="https://www.goodreads.com/book/show/33206.The_Minto_Pyramid_Principle">Minto Pyramid</a></strong> is an effective framework for structuring written communication, particularly useful in incident communication.</p><p>The structure is fairly easy:</p><ul><li><p><strong>Main Point (WHAT)</strong>: State the incident and its immediate impact in 1-2 sentences.</p></li><li><p><strong>Key Information (WHY | HOW)</strong>: Provide details such as the cause of the incident or steps being taken to resolve it.</p></li><li><p><strong>(Optional) Additional Details</strong>: Include further information that might interest specific stakeholders, like technical logs or timelines.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QxkM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QxkM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 424w, https://substackcdn.com/image/fetch/$s_!QxkM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 848w, https://substackcdn.com/image/fetch/$s_!QxkM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 1272w, https://substackcdn.com/image/fetch/$s_!QxkM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QxkM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png" width="512" height="279.56485355648533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:522,&quot;width&quot;:956,&quot;resizeWidth&quot;:512,&quot;bytes&quot;:61376,&quot;alt&quot;:&quot;Minto Pyramid, basically showing the three points above.&quot;,&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="Minto Pyramid, basically showing the three points above." title="Minto Pyramid, basically showing the three points above." srcset="https://substackcdn.com/image/fetch/$s_!QxkM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 424w, https://substackcdn.com/image/fetch/$s_!QxkM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 848w, https://substackcdn.com/image/fetch/$s_!QxkM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 1272w, https://substackcdn.com/image/fetch/$s_!QxkM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee6344e-7bd9-48f0-8c75-8f7c8478d31d_956x522.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here is an example incident communication using this principle:</p><blockquote><p><strong>Service X has been unavailable since June 12, 2024, affecting approximately 15% of our users.</strong></p><p><strong>Incident Overview</strong></p><ol><li><p><strong>Cause</strong>: Our investigation indicates that the outage is likely due to a load balancer failure.</p></li><li><p><strong>Actions Taken</strong>: A technical team is currently working to resolve the issue.</p></li><li><p><strong>Estimated Resolution Time</strong>: We expect the service to be restored within the next 2 hours.</p></li></ol><p><strong>Additional Details</strong></p><ul><li><p>Several restarts and configuration checks have already been performed to isolate the issue.</p></li></ul></blockquote><p>By using the Minto Pyramid, you can ensure your incident communications are clear, concise, and effective, providing essential information promptly and accurately.</p><div><hr></div><p></p><h2><strong>Key Takeaways from Kat Gaines' Talk on Incident Communication &#127908;</strong></h2><p>My example above may not be very useful for end customers. I am biased toward incident communication like this since I work on internal software that is not directly customer-facing, unlike my company's website. However, everyone also has internal customers, and most likely not all of them are techies.</p><p>This requires another level of incident communication. Kat Gaines from PagerDuty recently gave a short talk on this topic.</p><div id="youtube2-pgmNa9rS-n0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;pgmNa9rS-n0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/pgmNa9rS-n0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p><strong>Here are the key takeaways:</strong></p><ol><li><p><strong>Involve customer-facing teams as soon as possible</strong>: They know your customers and how to communicate with them (around <a href="https://youtu.be/pgmNa9rS-n0?si=KTxMhq04Ou_Yv9Uo&amp;t=190">minute three</a>)</p></li><li><p><strong>Have pre-defined templates that are easy to fill out</strong>: This will reduce the stress during an incident while keeping stakeholders and customers informed (around <a href="https://youtu.be/pgmNa9rS-n0?si=KIoA51IyKMji14pe">minute fifteen</a>)</p></li><li><p><strong>Give frequent and meaningful updates</strong>: Keep notification fatigue in mind(Around <a href="https://youtu.be/pgmNa9rS-n0?si=4EQFsPCJ1-lf16Cz&amp;t=1147">minute nineteen</a>)</p></li></ol><p>Kat's talk is only 25 minutes long, so it can fit into your lunch break. Alternatively, you can use the timestamps provided above to get the main gist.</p><div><hr></div><p></p><h2><strong>Slow Productivity  &#128012;&#128213;</strong></h2><p>I am an avid reader, and since 2021, also a listener of Cal Newport's ideas. I can warmly recommend everyone to read his famous <a href="https://calnewport.com/writing/">book</a> &#8220;Deep Work&#8221; and listen to his <a href="https://calnewport.com/podcasts/">podcast</a>.</p><p>A couple of months ago, he published his new book called &#8220;<strong>Slow Productivity</strong>&#8221;. Main topic of the book is that the definition of productivity in the knowledge sector is broken. He refers to this as &#8220;pseudo productivity&#8221;. Since there is no good way to measure productivity (as opposed to a factory worker who can be measured by produced &#8220;units&#8221; per hour), many knowledge workers use visible business as a proxy for productivity, e.g. by joining a lot of meetings and there like.</p><p>Cal wants to coin an alternative approach which he calls &#8220;Slow Productivity&#8221; as another way to see productivity in knowledge work. Slow Productivity is based on the three principles</p><ol><li><p><strong>Do Fewer Things</strong>: Focus on fewer tasks to achieve more meaningful accomplishments.</p></li><li><p><strong>Work at a Natural Pace</strong>: Avoid the constant rush and instead find a sustainable rhythm.</p></li><li><p><strong>Obsess Over Quality</strong>: Prioritize high-quality work over high-quantity outputs.</p></li></ol><p>While I think the overall content of the book is just fine, I was a little bit disappointed. The book is full of anecdotes which act as anecdotal evidence for the principles, but they are far too long and frequent. On could easily reduce the page count of the book by 25% without loosing any of its meaning. Also, many of the ideas feel like a rehash of content Cal Newport already produced.</p><p>So if you are familiar with Cal Newports ideas, I&#8217;d suggest to read the <a href="https://www.blinkist.com/en/books/slow-productivity-en">Blink</a> or another summary first.</p><div><hr></div><p></p><h2>Wrapping Up</h2><p>Thank you for reading this week's Weekly Tech Tidbits. Here's a quick recap:</p><ul><li><p><strong>Efficient Communication with the Minto Pyramid</strong>: Ensure clear and concise incident communications.</p></li><li><p><strong>Kat Gaines' Talk on Incident Communication</strong>: Involve customer-facing teams, use templates, and provide meaningful updates.</p></li><li><p><strong>Slow Productivity from Cal Newport</strong>: Focus on fewer tasks, work at a natural pace, and prioritize quality.</p></li></ul><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-3-slow-productivity/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/weekly-tech-tidbits-3-slow-productivity/comments"><span>Leave a comment</span></a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3172afe4-f43a-4536-98a8-1ef682c7eb1c&quot;,&quot;caption&quot;:&quot;Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics: the concept of Disagree and Commit &#128483;&#65039;&#9989; how to keep your code tidy &#129532; Typed Error Handling in Kotlin &#9888;&#65039;&#127909; If you missed the previous issue, find it&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Weekly Tech Tidbits #2: Disagree and Commit, Spotless, and Error Handling in Kotlin.&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-12T05:00:09.771Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/youtube/w_728,c_limit/T04ynq2IVFs&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-2&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145249252,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Weekly Tech Tidbits #2: Disagree and Commit, Spotless, and Error Handling in Kotlin.]]></title><description><![CDATA[Disagree and Commit, Keep your Code Tidy and improve your error handling!]]></description><link>https://verbosemode.dev/p/weekly-tech-tidbits-2</link><guid isPermaLink="false">https://verbosemode.dev/p/weekly-tech-tidbits-2</guid><pubDate>Wed, 12 Jun 2024 05:00:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/T04ynq2IVFs" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Hi, it's <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Mirco&quot;,&quot;id&quot;:184622759,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;uuid&quot;:&quot;fa205345-141b-490d-a947-c57b11c651b0&quot;}" data-component-name="MentionToDOM"></span>! &#128075; Welcome to this week's edition of <strong>Weekly Tech Tidbits</strong>. In today's post, we will cover three interesting topics:</em></p><ul><li><p><em>the concept of Disagree and Commit </em>&#128483;&#65039;&#9989;</p></li><li><p><em>how to keep your code tidy </em>&#129532;</p></li><li><p><em>Typed Error Handling in Kotlin </em>&#9888;&#65039;&#127909;</p></li></ul><p><em>If you missed the previous issue, find it <a href="https://verbosemode.dev/p/weekly-tech-tidbits-1?r=31x3tz&amp;utm_campaign=post&amp;utm_medium=web">here</a>.</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;25af9572-ab96-457b-a6e1-20b30f17ae9a&quot;,&quot;caption&quot;:&quot;Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics: Compound interest of mentoring &#128161; How to save time during git rebase &#9201;&#65039; How to choose your tools &#129690; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this &#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Weekly Tech Tidbits #1&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-05T05:01:28.500Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-1&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145156261,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><em>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! &#128226;</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share verbosemode&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share verbosemode</span></a></p><div><hr></div><p></p><h2><strong>Disagree and Commit &#128483;&#65039;&#9989;</strong></h2><p>In any collaborative environment, disagreements are inevitable. However, the principle of "<a href="https://en.wikipedia.org/wiki/Disagree_and_commit">disagree and commit</a>" provides a powerful attitude for maintaining momentum and unity.</p><p>The idea is simple: after thoroughly considering all viewpoints, a decision is made. Even if you initially disagreed with the chosen direction, <strong>once the decision is finalized, you fully commit to its implementation</strong>. You leave all your doubts behind and accept that your suggestion was not accepted.</p><p>However, this only works effectively if all opinions on the issue are heard and taken seriously prior to making the decision; otherwise, it can lead to entrenched conflicts, negative sentiments, and hidden rivalries.</p><p>It's important to work on yourself to adopt this attitude, cultivating humility and avoiding stubbornness to ensure the process is genuine and effective.</p><p>Several companies live by this principle, including <a href="https://handbook.gitlab.com/handbook/values/#transparency-competency">GitLab</a>, <a href="https://jobs.netflix.com/culture?lang=English">Netflix</a>, and most prominently <a href="https://eu.usatoday.com/story/tech/news/2017/04/13/jeff-bezos-amazon-annual-shareholder-letter-day-1/100418722/">Amazon</a>. Even if your company isn't as big as Amazon<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, adopting this mindset can still drive significant improvements in team collaboration.</p><p></p><div><hr></div><h2><strong>Keep your Code Tidy with Spotless &#129532;</strong></h2><p>Maintaining a <strong>consistent code style</strong> is essential for noise-free merges and readable code, yet synchronizing these styles across a team can be a hassle. The key is to <strong>automate this process,</strong> allowing developers to focus on coding and not on manual formatting.</p><p><a href="https://github.com/diffplug/spotless">Spotless</a> addresses this need by enabling you to write code without worrying about style inconsistencies until it&#8217;s time to merge. Spotless can be easily integrated to your build system as plenty plugins exist.</p><p><strong>Here's how it works:</strong></p><ol><li><p>Define which formatters and linters you want to use (e.g. <a href="https://github.com/pinterest/ktlint">ktlint</a> and <a href="https://github.com/saveourtool/diktat">diktat</a> for Kotlin). This is only done once in your build system, so it is the same for everyone.</p></li><li><p>Write your code without focusing on style.</p></li><li><p>Before opening a pull request, run <code>spotless apply</code> to ensure your code adheres to the predefined style guidelines.</p></li><li><p>Finally, run the <code>spotless check</code> before merging to maintain consistency on the main branch.</p></li></ol><p>This approach is challenging to implement 1:1 in a trunk-based development style, but you can use pre-commit hooks to automatically run Spotless before each commit, ensuring consistency throughout the development process.</p><p>By integrating spotless into your workflow, you ensure that your team&#8217;s code remains clean and consistent, enhancing both code quality and team efficiency.</p><div><hr></div><p></p><h2><strong>Typed Error Handling in Kotlin &#127919;&#127909;</strong></h2><p><strong><a href="https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/">Typed error handling</a></strong><a href="https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/"> </a>is an alternative to the traditional <code>try-catch</code> method, offering a more structured way to manage errors in your code. This approach uses types to <strong>explicitly represent possible errors</strong>, enhancing code readability and maintainability by ensuring that all potential failures are clearly defined within the type system.</p><p>Kotlin is well-suited for typed error handling due to its type system and functional programming capabilities. Here is a short example of typed error handling:</p><pre><code>// try-catch
fun parseNumber(str: String): Int {
    return try {
        str.toInt()
    } catch (e: NumberFormatException) {
        -1 // or some error handling logic
    }
}

// typed error handling
sealed class ParseError {
    object NotANumber : ParseError()
}

fun parseNumberTyped(str: String): Either&lt;ParseError, Int&gt; {
    return str.toIntOrNull()?.right() ?: ParseError.NotANumber.left()
}</code></pre><p>For a practical and in-depth look at functional error handling in Kotlin, I highly recommend the video "<strong>Functional Error Handling &#8211; A Practical Approach</strong>" by Bas de Groot.</p><div id="youtube2-T04ynq2IVFs" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;T04ynq2IVFs&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/T04ynq2IVFs?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>This talk provides a short and useful way to understand typed errors, addressing the problems they solve, how to implement them, and leveraging the <a href="https://arrow-kt.io/">Arrow</a> library.</p><div><hr></div><h2>Wrapping Up</h2><p>Thank you for reading this week's insights. To summarize, adopting 'disagree and commit' can enhance team unity, using Spotless ensures clean code, and leveraging typed error handling in Kotlin can make your code more reliable.</p><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-2/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/weekly-tech-tidbits-2/comments"><span>Leave a comment</span></a></p><p></p><p><strong>Stay tuned for next week's post!</strong></p><p></p><div><hr></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;0aa529d5-0f95-47ef-b576-ac3686779416&quot;,&quot;caption&quot;:&quot;Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics: Compound interest of mentoring &#128161; How to save time during git rebase &#9201;&#65039; How to choose your tools &#129690; Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this &#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Weekly Tech Tidbits #1&quot;,&quot;publishedBylines&quot;:[],&quot;post_date&quot;:&quot;2024-06-05T05:01:28.500Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-1&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:145156261,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;verbosemode&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a032e9-78c2-4163-8baa-f0e0149e0986_1024x1024.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>However if your company IS indeed Amazon, let me know in the comments ;-)</p></div></div>]]></content:encoded></item><item><title><![CDATA[Getting Started with CloudRun and Terraform - CloudRun 101]]></title><description><![CDATA[Master CloudRun Deployment: A Step-by-Step Guide with Terraform.]]></description><link>https://verbosemode.dev/p/getting-started-with-cloudrun-and</link><guid isPermaLink="false">https://verbosemode.dev/p/getting-started-with-cloudrun-and</guid><dc:creator><![CDATA[Mirco]]></dc:creator><pubDate>Mon, 10 Jun 2024 11:14:56 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="6016" height="4016" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4016,&quot;width&quot;:6016,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;blue clouds under white sky&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&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="blue clouds under white sky" title="blue clouds under white sky" srcset="https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1517483000871-1dbf64a6e1c6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw4fHxjbG91ZCUyMGNvbXB1dGluZ3xlbnwwfHx8fDE3MTgwMTMzMjZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 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">Photo by <a href="true">CHUTTERSNAP</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>CloudRun has become my go-to solution for deploying applications in the cloud due to its simplicity and scalability. It's an ideal choice for various use cases.</p><p>In this upcoming blog post series, I'll guide you on how to get started with CloudRun effectively. We'll begin with the quintessential "Hello, World," using Terraform to manage the infrastructure. You can get the complete code on <strong><a href="https://github.com/ablx/cloudrun_terraform_getting_started/tree/main/01_cloudrun_and_terraform">GitHub</a></strong>.</p><p>But first, let's take a look at the basics of CloudRun and understand why it's such a powerful tool.</p><div><hr></div><p></p><h2>What is CloudRun? &#9729;&#65039;&#127939;&#8205;&#9794;&#65039;</h2><p><a href="https://cloud.google.com/run?hl=de">CloudRun</a> is a fully managed serverless platform on the Google Cloud Platform (GCP). It allows you to deploy containerized applications written in any programming language or framework. The platform <strong>automatically scales</strong> to handle incoming requests based on demand, making it suitable for a wide range of applications, from small-scale projects to large enterprise applications. CloudRun follows a <strong>pay-as-you-go pricing model</strong>, making it cost-effective.</p><p>You can deploy any <strong>Docker container</strong> to CloudRun. The platform operates on a <strong>request-based model</strong>, meaning it starts your container when an <strong>HTTP request</strong> comes in and processes it. If there are no incoming requests, CloudRun scales down to zero, resulting in <strong>zero costs</strong> for you.</p><p>While there are ways to keep containers alive without requests, the primary model of CloudRun is request-based. It is not designed for long-running operations, especially background processes. For such needs, Google Cloud offers another service called <a href="https://cloud.google.com/run/docs/create-jobs">CloudRun Jobs</a>, which is specifically tailored for long-running processes.</p><div><hr></div><p></p><h2>Setting Up the Environment</h2><p>Setting up the environment for deploying applications on Google Cloud Platform (GCP) involves a few key components: a <a href="https://cloud.google.com/?hl=en">GCP account</a>, the <strong>gcloud command-line tool</strong>, and <strong>Terraform</strong> for infrastructure provisioning. I assume that you already have a <strong>GCP account</strong> and a <strong><a href="https://console.cloud.google.com/projectcreate?">Google Cloud Project</a></strong>. I also take basic command line skills for granted.</p><p>We need to install two essential command line tools:</p><ul><li><p><strong>gcloud</strong> is the primary command-line interface for interacting with GCP resources. Install gcloud by following the instructions provided in the <a href="https://cloud.google.com/sdk/docs/install">GCP documentation</a>.</p></li><li><p><strong>Terraform</strong> is an infrastructure as code tool that allows you to define and provision cloud infrastructure using a declarative configuration language. You can download and install Terraform from the official <a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli">Terraform website</a>. I recommend using a version manager like <strong><a href="https://github.com/tfutils/tfenv">tfenv</a></strong> to install Terraform.</p></li></ul><p>Now we are ready to go furthe!</p><div><hr></div><p></p><h2>A Quick Terraform Primer &#127959;&#65039;</h2><p>Terraform is a tool to manage <strong>infrastructure as code</strong>. Instead of manually clicking through a web interface to set up resources, Terraform utilizes <strong>HCL</strong> (HashiCorp Configuration Language), a YAML-like language, to describe what resources you need. HCL is a <strong>declarative language</strong> (like SQL): instead of describing how to set up your infrastructure, you write what you expect as the end result. So you define <strong>how</strong> your CloudRun service should look, and Terraform determines <strong>what</strong> to do and in what order.</p><p>For this, Terraform needs to keep a <strong>state</strong>. This is a plain text file where Terraform saves which resources it has created and details about them. Since Terraform relies on this state, it is important to <strong>never change resources created by Terraform without using Terraform</strong>.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> Although you could manually change resources and get away with it, it would confuse Terraform and cause issues later. Only do this if you are sure about the changes. Additionally, <strong>never cancel a Terraform operation</strong>, as it may result in a corrupted state. If you make a mistake, let Terraform complete the operation, correct the mistake, and then run Terraform again.</p><p>To interact with Terraform, it is sufficient to know these commands:</p><ul><li><p><code>terraform init</code>: Initializes Terraform (similar to <code>git init</code>). Must be done only once.</p></li><li><p><code>terraform plan</code>: Shows what Terraform will do without actually performing any actions (dry run).</p></li><li><p><code>terraform apply</code>: Creates the resources.</p></li><li><p><code>terraform destroy</code>: Destroys <strong>all</strong> resources saved in the state.</p></li></ul><p>Since this is not primarily a Terraform tutorial, I aim to balance best practices with simplicity. Check the section at the bottom for a discussion on what could be improved in a real-world scenario.</p><p>There are many <a href="https://developer.hashicorp.com/terraform/tutorials/gcp-get-started">great resources to learn Terraform,</a> but this overview is sufficient for now.</p><p>Lastly, we must <strong>enable Terraform to create GCP resources on our behalf</strong>. Run the following command to create a credentials file for Terraform. It will prompt you to open a browser and log in with the account you want to use:</p><pre><code><code>gcloud auth application-default login</code></code></pre><p>Now can create our CloudRun service.</p><div><hr></div><p></p><h2>Hello, CloudRun!</h2><p>Now that we have the necessary tools installed and initialized, we can move on to the exciting part&#8212;setting up and deploying our CloudRun service. In the following sections, we'll configure Terraform to create and manage our CloudRun infrastructure.</p><p></p><h3>Initialize Terraform</h3><p>Go to the folder where you want to store the Terraform configuration files and create a file called <strong>constants.tf</strong> to hold your project settings:</p><pre><code># constants.tf
locals {
  # The project ID where the Cloud Run service will be created
  project_id = "..."
}
</code></pre><p>Next, we must tell Terraform to load the Google Cloud provider so it can communicate with GCP. Create a new file called <strong>provider.tf</strong>:</p><pre><code># provider.tf
terraform {
  required_providers {
    google = {
      version = "~&gt; 5.32.0"
    }
  }
}

provider "google" {
  project = local.project_id
}

</code></pre><p>Now, use <code>terraform init</code> to load the provider and create your workspace.</p><pre><code>&gt; terraform init                                                                                                                                                 

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/google from the dependency lock file
- Using previously-installed hashicorp/google v5.32.0

Terraform has been successfully initialized!</code></pre><p>Since we have all the tools ready, we can start setting up the CloudRun.</p><p></p><h3>Adding CloudRun</h3><p>Before you can use any service on GCP, you first must activate its API. Create a new file called <strong>apis.tf</strong>:</p><pre><code># apis.tf
resource "google_project_service" "run_api" {
  # references the value in constants.tf
  project            = local.project_id
  service            = "run.googleapis.com"
  disable_on_destroy = false
}
</code></pre><p><code>disable_on_destroy</code> tells Terraform to keep the API activated even if you call <code>terraform destroy</code>.</p><p>Now create <strong>cloudrun.tf</strong> to add the actual service:</p><pre><code># cloudrun.tf
resource "google_cloud_run_v2_service" "service" {
  name     = "hello-cloudrun"
  location = "europe-west1"
  ingress  = "INGRESS_TRAFFIC_ALL"

  template {
    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello"
    }
  }

}</code></pre><p>The <strong>location</strong> specifies where your service should be hosted. Choose a region that is close to your users. You can use this<a href="https://googlecloudplatform.github.io/region-picker/"> handy tool to select the region which suits you the most.</a> <strong>Ingress</strong> describes how your service can be accessed. We choose to accept all traffic. You could also allow only load balancer traffic or only traffic from your internal GCP network, which we will explore in another post.</p><p>The <strong>template</strong> section describes how your service should look. Here, we only specify the Docker image and leave the rest with the defaults.</p><p>Next, create a file called <strong>outputs.tf</strong> to print the URL of the CloudRun service to the terminal after it is created:</p><pre><code># outputs.tf
output "cloudrun_url" {
  value       = google_cloud_run_v2_service.service.uri
  description = "The URL of the Cloud Run service"
}
 </code></pre><p>We are all set now. Run <code>terraform plan</code> to see what will happen:</p><pre><code>&gt; terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # google_cloud_run_v2_service.service will be created
  + resource "google_cloud_run_v2_service" "service" {
...
      + ingress                 = "INGRESS_TRAFFIC_ALL"
...
      + location                = "europe-west1"
      + name                    = "hello-cloudrun"
...
      + project                 = "premium-oven-425714-n3"
...
      + uri                     = (known after apply)

      + template {
...

          + containers {
              + image = "us-docker.pkg.dev/cloudrun/container/hello"
            }
        }
    }

  # google_project_service.run_api will be created
  + resource "google_project_service" "run_api" {
      + disable_on_destroy = false
      + id                 = (known after apply)
      + project            = "your_project_id"
      + service            = "run.googleapis.com"
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + cloudrun_url = (known after apply)</code></pre><p>Looks good. Terraform will enable the API, create a CloudRun service, and then print its URL. Now, run <code>terraform apply</code> to create the resources:</p><p></p><pre><code>&gt; terraform apply


Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:
...

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + cloudrun_url = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

google_project_service.run_api: Creating...
google_cloud_run_v2_service.service: Creating...
google_project_service.run_api: Creation complete after 4s [id=.../run.googleapis.com]
google_cloud_run_v2_service.service: Still creating... [10s elapsed]
google_cloud_run_v2_service.service: Creation complete after 10s [id=projects/.../locations/europe-west1/services/hello-cloudrun]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

cloudrun_url = "https://hello-cloudrun-...a-ew.a.run.app"</code></pre><p>It is possible that you run into an error:</p><blockquote><p>Error: Error creating Service: googleapi: Error 403: Cloud Run Admin API has not been used in project &#8230; before or it is disabled.</p></blockquote><p>It may some take some time to really enable the API. If this is the case, just wait a couple of minutes &#9749; and run <code>terraform apply</code> again.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p>Great! If you now open the URL in the browser, you&#8217;ll see the following:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u9Ei!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u9Ei!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 424w, https://substackcdn.com/image/fetch/$s_!u9Ei!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 848w, https://substackcdn.com/image/fetch/$s_!u9Ei!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 1272w, https://substackcdn.com/image/fetch/$s_!u9Ei!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u9Ei!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png" width="770" height="163" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:163,&quot;width&quot;:770,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16730,&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_!u9Ei!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 424w, https://substackcdn.com/image/fetch/$s_!u9Ei!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 848w, https://substackcdn.com/image/fetch/$s_!u9Ei!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 1272w, https://substackcdn.com/image/fetch/$s_!u9Ei!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c8408e4-941d-41c8-9b81-03b8969fda73_770x163.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Bummer. Didn&#8217;t we allow all traffic via <code>INGRESS_TRAFFIC_ALL</code>? True, but here comes another handy feature of Cloud Run: <strong>secure by default</strong>. It allows traffic from the internet, but only authenticated traffic.</p><p>If you want to access your service in the browser, you can do two things. First is to provide a correct <strong>Authentication header</strong> in your request. To do this, you first must install a browser extension that allows you to set request headers. There are plenty to choose from depending on your browser.</p><p>To get a valid token, run <code>gcloud auth print-identity-token</code> in your terminal. This will print a valid OAuth token. Now, use your extension to add the <strong>Authorization header</strong>, and set it to the value <code>Bearer &lt;token from above&gt;</code>. If you now open the URL again with the header activated, you&#8217;ll see this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L3pF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L3pF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 424w, https://substackcdn.com/image/fetch/$s_!L3pF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 848w, https://substackcdn.com/image/fetch/$s_!L3pF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 1272w, https://substackcdn.com/image/fetch/$s_!L3pF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L3pF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png" width="855" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c280456-6765-4a45-9e24-92e9887e5542_855x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:855,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:114344,&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_!L3pF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 424w, https://substackcdn.com/image/fetch/$s_!L3pF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 848w, https://substackcdn.com/image/fetch/$s_!L3pF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 1272w, https://substackcdn.com/image/fetch/$s_!L3pF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c280456-6765-4a45-9e24-92e9887e5542_855x768.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>So you did it! There&#8217;s your up-and-running CloudRun service! &#129395;&#127870;</strong></p><p></p><p>As mentioned above, there is a way to access the service without authorization. To do this, you must assign the role <code>run.invoker</code> to everyone. <strong>All users</strong> with this role may call your Cloud Run services. To do this, add the following to your <strong>cloudrun.tf</strong> and run <code>terraform apply</code> again:</p><pre><code># cloudrun.tf
...

resource "google_cloud_run_v2_service_iam_member" "public_access" {
  project  = google_cloud_run_v2_service.service.project
  location = google_cloud_run_v2_service.service.location
  name     = google_cloud_run_v2_service.service.name
  role     = "roles/run.invoker"
  member   = "allUsers"
}</code></pre><p>Now, you (<strong>and everyone else on the internet &#129489;&#8205;&#128187;</strong>!) can just open the provided URL. <strong>Obviously, you should use this with care.</strong></p><p>We are done for now. &#127881; Call <code>terraform destroy &#128163;</code> to delete the resources created. Next time, we will see how to deploy our own Docker images to CloudRun, using our own registry!</p><div><hr></div><p></p><h2>Wrapping Up</h2><p><strong>Congratulations on deploying your first CloudRun service!</strong> &#127881; You&#8217;ve taken a big step in leveraging the power of serverless infrastructure. <strong><a href="https://github.com/ablx/cloudrun_terraform_getting_started/tree/main/01_cloudrun_and_terraform">Head over to GitHub to get the complete code</a></strong>!</p><p>As mentioned above, this is not a comprehensive Terraform tutorial. In the real world, you would do some things differently.</p><p>We saved the Terraform state in a local file. The state contains all information about what Terraform created in the cloud. In a real-world scenario, you would likely save the state in the cloud itself, ensuring that the latest version is accessible to every team member. Terraform self-manages a lock on the state, preventing concurrent modifications.</p><p><strong>Thank you for reading!</strong> In the next article of this series, we will explore how to <strong>deploy our own Docker images to CloudRun using our own registry &#128230;</strong>. Stay tuned for more insights and tips. &#128640;</p><p></p><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/getting-started-with-cloudrun-and?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thank you for reading verbosemode. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/getting-started-with-cloudrun-and?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/getting-started-with-cloudrun-and?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>First rule of the Terraform Club.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Weekly Tech Tidbits #1]]></title><description><![CDATA[Hi, it's Mirco! &#128075; Welcome to this week's edition of Weekly Tech Tidbits. In today's post, we will cover three interesting topics:]]></description><link>https://verbosemode.dev/p/weekly-tech-tidbits-1</link><guid isPermaLink="false">https://verbosemode.dev/p/weekly-tech-tidbits-1</guid><pubDate>Wed, 05 Jun 2024 05:01:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IKuH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Hi, it's <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Mirco&quot;,&quot;id&quot;:184622759,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e97b0dc1-14e0-4adb-88aa-c2106a9652da_6000x4000.jpeg&quot;,&quot;uuid&quot;:&quot;fa205345-141b-490d-a947-c57b11c651b0&quot;}" data-component-name="MentionToDOM"></span>! </em>&#128075; <em>Welcome to this week's edition of <strong>Weekly Tech Tidbits</strong>. In today's post, we will cover three interesting topics:</em></p><ul><li><p><em>Compound interest of mentoring </em>&#128161;</p></li><li><p><em>How to save time during git rebase </em>&#9201;&#65039;</p></li><li><p><em>How to choose your tools &#129690;</em></p></li></ul><p><em>Enjoy reading and feel free to share your thoughts in the comments below. Don't forget to subscribe for more insights and share this post with your network! </em>&#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share verbosemode&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share verbosemode</span></a></p><div><hr></div><p></p><h2><strong>Compound interest of mentoring &#128161;</strong></h2><p>The more experienced you become, the more you see that <strong>knowledge compounds</strong>. Learning your first programming language is hard, but the second one is easier since you already understand loops, classes, and variables. After working with one cloud provider, switching to another is simpler because the underlying challenges, like role management, are similar.</p><p>However, <strong>your time is limited</strong>. As a senior developer, you may be faster than less experienced colleagues, but you also attend more meetings, leaving less time for actual implementation.</p><p>You can optimize your day by minimizing non-coding activities to boost your output, especially when deadlines are near. <strong>But a smarter approach is to enable others to increase their output.</strong> If you can help two people improve, you invest a small portion of your time to gain double the value for the team. If those people mentor others, the benefits multiply exponentially.</p><p>The math may be off, but the essence is clear: <strong>the more you help others improve, the more your team benefits.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IKuH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IKuH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 424w, https://substackcdn.com/image/fetch/$s_!IKuH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 848w, https://substackcdn.com/image/fetch/$s_!IKuH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 1272w, https://substackcdn.com/image/fetch/$s_!IKuH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IKuH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png" width="433" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e97c678-0430-4649-9298-629c07480541_433x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:433,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3677,&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_!IKuH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 424w, https://substackcdn.com/image/fetch/$s_!IKuH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 848w, https://substackcdn.com/image/fetch/$s_!IKuH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.png 1272w, https://substackcdn.com/image/fetch/$s_!IKuH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e97c678-0430-4649-9298-629c07480541_433x302.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">Value added over time by alone vs. sharing knowledge.</figcaption></figure></div><p>If you lack time for intensive mentoring, consider these strategies:</p><ul><li><p><strong>Write and Update Documentation:</strong> Help others solve problems independently with clear documentation.</p></li><li><p><strong>Write Detailed Comments in Code Reviews:</strong> Provide useful feedback and links to relevant documentation or articles.</p></li><li><p><strong>Host Regular Knowledge Sharing Sessions:</strong> Set up weekly or bi-weekly sessions where team members can share their expertise on different topics.</p></li></ul><p>Investing time in mentoring boosts both individual and team productivity, creating a more efficient and skilled team over time.</p><p>If you want to read more on mentoring, I recommend <a href="https://read.highgrowthengineer.com/p/how-to-be-the-mentor-you-wish-you#%C2%A7build-a-career-growth-plan">this article</a> by <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Jordan Cutler&quot;,&quot;id&quot;:58854493,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fe86d99-af64-4285-b982-9466a4c58d63_1311x1312.jpeg&quot;,&quot;uuid&quot;:&quot;c06ad478-491c-4f4f-9b3e-cb0543538533&quot;}" data-component-name="MentionToDOM"></span>.</p><p></p><h2><strong>Save rebase time with fixup and autosquash &#9201;&#65039;</strong></h2><p>There is a common pattern when you work with feature branches and pull requests. After receiving comments on your pull request, you add changes to the branch, leading to new commits. However, not each commit must be preserved and merged to the main branch. Especially smaller commits, like fixing a typo, are of no value. So what you typically do is:</p><ol><li><p><strong>Fix the typo in the commit.</strong></p></li><li><p><strong>Run </strong><code>git rebase -i &lt;SHA&gt;</code>.</p></li><li><p><strong>Manually reorder your commit.</strong></p></li><li><p><strong>Change the action to fixup.</strong></p></li><li><p><strong>Execute.</strong></p></li></ol><p>This process is a bit tedious, especially if you have to do it often. Another way is to use <code>git commit --fixup</code>.</p><p>Imagine this initial git history:</p><pre><code>* 316e87f (HEAD -&gt; master) add bar
* 226733c first commit  &lt;-- commit with typo
* a9c145c initial</code></pre><p>You want to add a commit between <code>226733c</code> and <code>316e87f</code> to fix it up later. You can add the commit using <code>git commit --fixup 226733c</code>, which leads to this history:</p><pre><code>* 4da3895 (HEAD -&gt; master) fixup! first commit &lt;-- fixup commit
* 316e87f add bar
* 226733c first commit  &lt;-- commit with typo
* a9c145c initial</code></pre><p>It's important to note that the whole commit message was added by git itself. You can now call <code>git rebase -i --autosquash a9c145c</code>, which has already 1) moved your commit to the correct position and 2) changed the action from <strong>p</strong>ick to <strong>f</strong>ixup:</p><pre><code>git rebase -i --autosquash a9c145c
p 226733c first commit &lt;-- commit with typo
f 4da3895 fixup! first commit &lt;-- reordered commit
p 316e87f add bar</code></pre><p>This handy trick might only save you one or two minutes, but <strong>free time compounds as well</strong>. &#128521;</p><p></p><h2><strong>The Craftsman Approach to Tool Selection &#129690;</strong></h2><p>Earlier this year, I re-read Cal Newport&#8217;s <em>Deep Work</em>. The book is full of useful ideas, but one I frequently overlooked is the craftsman approach to tool selection:</p><blockquote><p>[&#8230;]<strong> </strong>Identify core factors that determine success and happiness  [&#8230;]. Adopt a tool only if its positive impacts on these factors <strong>substantially outweigh its negative impacts</strong>. <em>(Deep Work by Cal Newport, page 181ff.)</em></p></blockquote><p>Cal mentions this in the context of leaving (or reducing) social media, but in my mind, this approach can be applied to all areas of life. For instance, do you need a full-fledged solution for executing HTTP requests occasionally, or isn&#8217;t curl just enough?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!K7KR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!K7KR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 424w, https://substackcdn.com/image/fetch/$s_!K7KR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 848w, https://substackcdn.com/image/fetch/$s_!K7KR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 1272w, https://substackcdn.com/image/fetch/$s_!K7KR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!K7KR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png" width="300" height="460.45816733067727" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1541,&quot;width&quot;:1004,&quot;resizeWidth&quot;:300,&quot;bytes&quot;:2508777,&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_!K7KR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 424w, https://substackcdn.com/image/fetch/$s_!K7KR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 848w, https://substackcdn.com/image/fetch/$s_!K7KR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.png 1272w, https://substackcdn.com/image/fetch/$s_!K7KR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5923e9c2-6adc-4a51-8bbd-7402eba4c65b_1004x1541.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">Physical books &gt; digital books. &#10084;&#65039;</figcaption></figure></div><p>The key here is that the positive impacts must &#8220;substantially outweigh&#8221; the negative ones. Consider factors like bloated UIs, new dependencies in your project, maintenance burdens, and so on.</p><p>By carefully selecting the right tools, you can streamline your workflow and focus on what truly matters.</p><p></p><div><hr></div><h2>Wrapping Up</h2><p>Thank you for reading this week's <strong>Weekly Tech Tidbits</strong>. I covered the importance of mentoring and how it compounds knowledge within a team, a practical tip to save time during git rebasing with fixup and autosquash, and the craftsman approach to tool selection.</p><p>I'd love to hear your thoughts, questions, and feedback in the comments below. &#128172; Don't forget to subscribe for more insights &#128276; and share this post with your network! &#128226;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/p/weekly-tech-tidbits-1/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://verbosemode.dev/p/weekly-tech-tidbits-1/comments"><span>Leave a comment</span></a></p><p></p><p><strong>Stay tuned for next week's post.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://verbosemode.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading verbosemode! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item></channel></rss>